目录
图像的读取和显示
#cv.imread(filename[,flags]) -> retval函数读取图像
#filename表示文件路径,[]内的参数表示可选,flag指定了读取图像的方式,也可以不填,flag指定了读取图像的方式
#cv.IMREAD_COLOR:加载彩色图像,任何图像的透明度都会被忽略,它是默认标志
#cv.IMREAD_GRAYSCALE:以灰度模式加载图像
#cv.IMREAD_UNCHANGED:加载图像,包括 alpha 通道
#可以简单地分别传递整数 1、0 或-1,而不是这三个 flag
#cv.imshow(winname, mat) -> None函数在窗口中显示图像,窗口自动适应图像的大小
#winname表示窗口标题,mat 表示图像对象
#cv.waitKey(0) 表示一直等待,直到任意一个键盘操作
#cv.waitKey(1000) #表示等待1000毫秒即1秒
def show_img():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.imshow("japanese",image)
cv.waitKey(0)
cv.destroyAllWindows() #回收资源
图像色彩空间转换
注意:彩色图像 OpenCV 用的 BGR 模式,但是 Matplotlib 显示用的 RGB 模式。因此如果图像用 OpenCV 加载,则 Matplotlib 中彩色图像将无法正常显示。
- RGB色彩空间,设备独立,RGB是计算机显示器的标准支持色彩系统
- HSV色彩空间,对计算机友好,区分各种色彩
- YCrCb, Y分量表示信息,CrCb可以被压缩
- RGB的取值范围0~255
- HSV取值范围:
H:0~180(OpenCV中)
SV:0~255
从一个色彩空间转换到另外一个色彩空间会造成信息传递与损失
#cv.cvtColor(src, code[,dst[,dstCn]])->dst
#src表示输入图像,类型有CV_8U和CV_32F
#code表示:COLOR_BGR2RGB=4,COLOR_BGR2GRAY=6,COLOR_GRAY2BGR=8,COLOR_BGR2HSV=40
def color_space_demo():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.imshow("wicher", image)
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
cv.imshow("hsv", hsv)
cv.imshow("ycrcb", ycrcb)
cv.waitKey(0)
cv.destroyAllWindows()
图像对象的创建与赋值
- 图像宽高 image.shape
- 图像深度 image
- 图像数据类型 image.dtype
- 图像通道 image.shape
- OpenCV-Python支持的数据类型:
np.uint8
np.float32
np.int32
np.int64
def numpy_demo():
m1 = np.array([[2, 3], [4, 5]], dtype=np.uint8)
print(m1)
m2 = np.ones((4, 4, 3), dtype=np.uint8)
print(m2)
m2[:] = (255, 0, 0)
print(m2)
m3 = np.zeros((4, 4, 3), dtype=np.uint8)
print(m3)
m3[:] = 255
图像像素的读写操作
def visit_pixel_demo():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.imshow("wicher", image)
h, w, c = image.shape
for row in range(h):
for col in range(w):
b, g, r = image[row, col]
image[row, col] = (255-b, 255-g, 255-r)
cv.imshow("visited", image)
cv.waitKey(0)
cv.destroyAllWindows()
图像算术操作
#cv.add(src1, src2[, dst[, mask[, dtype]]])->dst
#cv.subtract(src1,src2[,dst[,mask[,dtype]]])->dst
#cv.multiply(src1,src2[,dst[,scale[,dtype]]])->dst
#cv.divide(src1, src2[, dst[, scale[, dtype]]])->dst
#src1 & src2表示图像
#加法,保证不越界:saturate(src1 + src2)->0~255
def arithmetic_demo():
image1 = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
image2 = np.zeros_like(image1)
image2[:,:] = (110,0,250)
cv.imshow("image1", image1)
cv.imshow("image2", image2)
added = cv.add(image1, image2)
cv.imshow("added", added)
cv.waitKey(0)
cv.destroyAllWindows()
def arithmetic_demo1():
image1 = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
image2 = np.zeros_like(image1)
image2[:,:] = (110,0,250)
cv.imshow("image1", image1)
cv.imshow("image2", image2)
added = cv.add(image1, image2)
cv.imshow("added", added)
cv.waitKey(0)
cv.destroyAllWindows()
- mask参数:
滚动条操作
- Callback基本流程
#cv.namedWindow(winname[,flags])->None
#参数: winname表示窗口标题
#参数flags支持的flag有:
#WINDOW_NORMAL – 可以调整窗口大小
#WINDOW_AUTOSIZE – 根据图像大小自动适应,不可调
#WINDOW_KEEPRATIO – 可以保持比例窗口,调整大小
#调整图像亮度
#RGB值表示亮度,RGB(0,0,0)黑色->RGB(255,255,255)白色
#add函数支持图像+图像与图像+常量方式
#subtract函数支持图像+图像与图像+常量方式
#通过他们可以修改图像的亮度
def trackbar_callback(pos):
print(pos)
def trackbar_demo():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.namedWindow("trackbar_demo", cv.WINDOW_AUTOSIZE)
cv.createTrackbar("Lightness", "trackbar_demo", 0, 200, trackbar_callback)
while True:
pos = cv.getTrackbarPos("Lightness", "trackbar_demo")
image2 = np.zeros_like(image)
image2[:,:] = (np.uint8(pos), np.uint8(pos), np.uint8(pos))
#提升亮度
result = cv.add(image, image2)
#降低亮度
#result = cv.subtract(image, image2)
cv.imshow("trackbar_demo", result)
c = cv.waitKey(1)
if c == 27:
break
cv.waitKey(0)
cv.destroyAllWindows()
键盘响应操作
- cv.waitKey( [, delay] ) -> retval
delay如果没有声明或者delay=0,表示一直阻塞
delay大于0,表示阻塞指定毫秒数
retval返回的对应键盘键值,注意:在不同的操作系统中可能会有差异!典型的retval = 27是ESC按键 - 检查返回键值,根据不同键值完成不同操作,推荐使用if-elif-else, switch-case方式python3.10支持
#按ESC推出,按1显示HSV图像,按2显示YCrCb,按3显示RGB图像,按0恢复原图BGR显示
def keyboard_demo():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.namedWindow("keyboard_demo", cv.WINDOW_AUTOSIZE)
cv.imshow("keyboard_demo", image)
while True:
c = cv.waitKey(10)
if c == 27:
break
elif c == 48:
cv.imshow("keyboard_demo", image)
elif c == 49:
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
cv.imshow("keyboard_demo", hsv)
elif c == 50:
ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
cv.imshow("keyboard_demo", ycrcb)
elif c == 51:
rgb = cv.cvtColor(image, cv.COLOR_BGR2RGB)
cv.imshow("keyboard_demo", rgb)
cv.waitKey(0)
cv.destroyAllWindows()
自带颜色表操作
- 查找表LUT(Look Up Table)
- Gamma校正
- OpenCv中LUT支持(OpenCV提供的colormap)
def lut_demo():
cv.namedWindow("lut-demo", cv.WINDOW_NORMAL)
lut = [[255, 0, 255], [125, 0, 0], [127, 255, 200], [200, 127, 127], [0, 255,255]]
m1 = np.array([[2, 1, 3, 0], [2, 2, 1, 1], [3, 3, 4, 4], [4, 4, 1, 1]])
m2 = np.zeros((4, 4, 3), dtype=np.uint8)
for i in range(4):
for j in range(4):
index = m1[i, j]
m2[i, j] = lut[index]
cv.imshow("lut-demo", m2)
cv.waitKey(0)
cv.destroyAllWindows()
#建立查找表
def lut_demo1():
lut1 = np.zeros((256), dtype=np.uint8)
gamma = 0.7
for i in range(256):
print(i, "--", np.log(i / 255.0 + 1e-5))
lut1[i] = int(np.exp(np.log(i / 255 + 1e-5) * gamma) * 255.0)
print(lut1)
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.imshow("input", image)
cv.namedWindow("lut-demo", cv.WINDOW_AUTOSIZE)
h, w, c = image.shape
for row in range(h):
for col in range(w):
b, g, r = image[row, col]
image[row, col] = (lut1[b], lut1[g], lut1[r])
cv.imshow("lut-demo", image)
cv.waitKey(0)
cv.destroyAllWindows()
#自定义查找表
def lut_demo2():
lut2 = np.zeros((256, 1, 3), dtype=np.uint8)
gamma = 0.7
for i in range(256):
print(i, "--", np.log(i / 255.0 + 1e-5))
c = int(np.exp(np.log(i / 255.0 + 1e-5) * gamma) * 255.0)
lut2[i, 0] = (c, c, c)
print(lut2)
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.imshow("input", image)
cv.namedWindow("lut-demo", cv.WINDOW_AUTOSIZE)
dst = cv.LUT(image, lut2)
cv.imshow("lut-demo", dst)
cv.waitKey(0)
cv.destroyAllWindows()
#系统查找表
def lut_demo3():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
dst = cv.applyColorMap(image, cv.COLORMAP_PINK)
cv.imshow("japanese-pink", dst)
cv.waitKey(0)
cv.destroyAllWindows()
通道分离与合并
- 分离函数
通道分离函数cv.split(m[, mv]) ->mv
m表示输入图像,必须是多通道图像,mv表示输出的 - 合并与混合
cv.merge(mv[, dst])->dst
mv表示各个通道
cv.mixChannels(src, dst, fromTo)->dst
src表示输入多通道图像,fromTo表示通道索引,dst表示返回结果 - 通道阈值
cv.inRange(src, lowerb, upperb[, dst])->dst
其中src是输入图像,Lowerb是低值,Upperb是高值
dst = (lowerb < src < upperb)
def channel_demo():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.namedWindow("channel-demo", cv.WINDOW_AUTOSIZE)
cv.imshow("channel-demo", image)
mv = cv.split(image)
cv.imshow("mv[0]", mv[0 ])
dst = np.zeros_like(image)
#BGR2RGB
cv.mixChannels([image], [dst], fromTo=[0, 2, 1, 1, 2, 0])
cv.imshow("mix-channels", dst)
mask = cv.inRange(image, (43, 46, 100), (128, 200, 200))
cv.imshow("inRange", mask)
cv.waitKey(0)
cv.destroyAllWindows()
图像像素值统计信息
- cv.mean(src[, mask])->retval
- cv.meanStdDev(src[, mean[, stddev[, mask]]]) ->mean, stddev
- cv.minMaxLoc(src[, mask]) ->minVal, maxVal, minLoc, maxLoc
src表示输入图像,mask表示计算区域
mean, stddev, minVal, maxVal分别表示均值,标准方差,最小与最大 - 均值应用:调整对比度
Dst = (Src-mean) * contrast + mean
def stats_demo():
image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
cv.imshow("wicher", image)
bgr_m = cv.mean(image)
sub_m = np.float32(image)[:,:] - (bgr_m[0], bgr_m[1], bgr_m[2])
result = sub_m * 0.5
result = result[:,:] + (bgr_m[0], bgr_m[1], bgr_m[2])
cv.imshow("low-contrast-wicher", cv.convertScaleAbs(result))
result = sub_m * 2.0
result = result[:, :] + (bgr_m[0], bgr_m[1], bgr_m[2])
cv.imshow("high-contrast-wicher", cv.convertScaleAbs(result))
cv.waitKey(0)
cv.destroyAllWindows()
图像几何形状绘制
- 相关函数cv.line()、cv.circle()、cv.rectangle()、cv.ellipse()、cv.putText()
相关参数解释:img表示输入图像,color表示颜色,如(255, 0,0)表示蓝色,thickness表示线宽, 大于0表示绘制,小于0表示填充,lineType表示渲染模式, 默认LINE_8, LINE_AA表示反锯齿
putText 默认只支持英文,org表示文字起始坐标点,fontFace表示字体类型,fontScale表示字体大小 - 计算文本区域大小函数getTextSize (text, fontFace, fontScale, thickness)
text表示文本信息,fontFace表示字体类型,fontScale表示字体大小,thickness表示线宽
返回文本信息区域大小,与字体的基线baseline位置
def draw_demo():
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
cv.rectangle(canvas, (100, 100), (300, 300), (0, 0, 255), 2, 8)
cv.circle(canvas, (250, 250), 50, (255, 0, 0), 4, cv.LINE_8)
cv.line(canvas, (100, 100), (300, 300), (0, 255, 0), 2, 8)
cv.putText(canvas, "OpenCV-Python", (100, 100), cv.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 255), 2)
cv.imshow("canvas", canvas)
cv.waitKey(0)
cv.destroyAllWindows()
def draw_demo():
#动态合理显示文本区域
font_color = (140, 199, 0)
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
cv.rectangle(canvas, (100, 100), (300, 300), font_color, 2, 8)
label_txt = "OpenCV-Python"
font = cv.FONT_HERSHEY_SIMPLEX
font_scale = 0.5
thickness = 1
(fw, uph), dh = cv.getTextSize(label_txt, font, font_scale, thickness)
cv.rectangle(canvas, (100, 100-uph-dh), (100+fw, 100), (255, 255, 255), -1, 8)
cv.putText(canvas, label_txt, (100, 100-dh), font, font_scale, (255, 0, 255), thickness)
cv.imshow("canvas", canvas)
cv.waitKey(0)
cv.destroyAllWindows()
随机数与随机颜色
- Numpy中的随机函数:random.randint(low, high=None, size=None, dtype=int)
Low表低值,high表示高值,size表示维度,dtype表示类型 - 随机噪声图的生成cv.randn(dst, mean, stddev)
生成目标图像dst,噪声均值mean,噪声方差stddev
cv.randn(canvas, (40, 200, 140), (10, 50, 10))
def random_demo():
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
#random draw
while True:
b, g, r = np.random.randint(0, 256, size=3)
x1 = np.random.randint(0, 512)
x2 = np.random.randint(0, 512)
y1 = np.random.randint(0, 512)
y2 = np.random.randint(0, 512)
cv.rectangle(canvas, (x1, y1), (x2, y2), (int(b), int(g), int(r)), -1, 8)
cv.imshow("canvas", canvas)
c = cv.waitKey(50)
if c == 27:
break
cv.rectangle(canvas, (0, 0), (512, 512), (0, 0, 0), -1, 8)
cv.randn(canvas, (120, 100, 140), (30, 50, 20))
cv.imshow("noise image", canvas)
cv.waitKey(0)
cv.destroyAllWindows()
多边形填充与绘制
- cv.fillPoly(img, pts, color[, lineType[, shift[, offset]]]) ->img
填充多边形(可以一次绘制多个) - cv.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]] ) ->img
绘制多边形(可以一次绘制多个)
pts表示一个或者多个点集,color表示颜色,thickness表示线宽,注意:必须大于0,lineType 表示渲染方式 - 点集支持
def poly_demo():
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
pts = []
pts.append((100, 100))
pts.append((200, 50))
pts.append((280, 100))
pts.append((290, 300))
pts.append((50, 300))
pts = np.asarray(pts, dtype=np.int32)
print(pts.shape)
pts2 = []
pts2.append((300, 300))
pts2.append((400, 250))
pts2.append((500, 300))
pts2.append((500, 500))
pts2.append((250, 500))
pts2 = np.asarray(pts2, dtype=np.int32)
print(pts2.shape)
cv.polylines(canvas, [pts, pts2], True, (0, 255, 255), 4, 8)
cv.fillPoly(canvas, [pts, pts2], (255, 0, 0), 8, 0)
cv.imshow("poly-demo", canvas)
cv.waitKey(0)
cv.destroyAllWindows()