目录
2.4 用matplotlib显示图像 plt.imshow()
2.8 数值计算 img1+img2 cv2.add(img1,img2)
2.11 图像阈值 ret, dst = cv2.threshold()
3.1 均值滤波 cv2.blur(img, (3, 3))
3.2 方框滤波 cv2.boxFilter(img,-1,(3,3), normalize=True)
3.3 高斯滤波 cv2.GaussianBlur(img, (5, 5), 1)
3.4 中值滤波 cv2.medianBlur(img, 5)
3.5 双边滤波 cv2.bilateralFilter(img,d,sigmaColor,sigmaSpace)
3.7 直方图均衡化 cv2.equalizeHist(img)
4.3 图像旋转 cv2.getRotationMatrix2D()
4.4 放射变换 cv2.getAffineTransform()
4.5 透视变化 cv2.getPerspectiveTransform() / cv2.warpPerspectiveTransform()
一、图像属性
1.1图像格式
BMP格式:Windows系统下的标准位图格式,未经过压缩,一般图像文件比较大
JPEG格式:应用最广泛的格式之一,它采用一种特殊的有损压缩算法,达到较大的压缩比(可达到2:1甚至40:1)
GIF格式:可以是一张静止的图片,也可以是动画,支持透明背景图像,适用于多种操作系统,“体型”很小。但是其色域不太广,只支持256种颜色。
PNG格式:与JPG格式类似,压缩比高于GIF,支持图像透明,支持Alpha通道调节图像的透明度。
TIFF:特点是图像格式复杂,存储信息多,在Mac中广泛使用,非常有利于原稿的复制。很多地方将TIFF格式用于印刷。
注:JPEG和JPG区别可参考:https://www.zhihu.com/question/20329498。这里可理解为一个东西。
1.2图像尺寸
图像尺寸的长度和宽度以像素为单位。
像素(pixel):像素是数码影像最基本的单位,每个像素就是一个小点,不同颜色的点聚集起来即成为一幅图片。灰度像素点数值范围在0到255之间,0表示黑,255表示白,其他值表示处于黑白之间;彩色图用红、绿、蓝三通道的二维矩阵来表示。每个数值也是在0~255之间,0表示相应的基色,而255则表示相应的基色在该像素中取得最大值。
1.3图像分辨率和通道
分辨率:单位长度中的像素数目。每英寸图像中的像素点数,单位是像素每英寸(PPI)。图像分辨率越高,像素的点密度越高,图像越清晰。
通道数:图像的位深度,是指描述图像中每个pixel数值所占的二进制数。位深度越大则图像能表示的颜色数就越多,色彩越丰富逼真。
- 8位:单通道图像,也就是灰度图,灰度值范围2^8=256
- 24位:三通道3*8=24
- 32位:三通道加透明度Alpha通道
1.4图像直方图
图像直方图(Image Histogram)是用来表示数字图像中亮度分布的直方图,描绘了图像中每个亮度值的像素数。图像直方图中,横坐标左侧为纯黑、较暗的区域,右侧为较亮、纯白的区域。
图像直方图能表现出图像中的像素强度分布情况,它统计了每一个强度值所具有的像素个数。我们常借助图像直方图来实现图像的二值化。
1.5图像颜色空间
概念:一种彩色模型,用途实在某些标准下用通常可接受的方式对彩色加以说明。
常见颜色空间:RGB HSV HSI CMYK
RGB颜色空间:依据人眼识别的颜色创建,图像中每一个像素都有R,G,B三个颜色分量组成,这三个大小均为【0,255】。通常表示某个颜色的时候,写成一个3维向量的形式,如(105,123,135)。
颜色模型:归一化后,原点(0,0,0)对应黑色,距原点最远的顶点对应白色,坐标为(1,1,1);从黑色到白色的灰度值分布在这两个点的连线上,该虚线称为灰度线;立方体的其余各点对应不同的颜色,红绿蓝等等。
HSV颜色空间:根据颜色的直观特性创建的一种颜色空间。这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)。
颜色模型:S通道,色彩/色调,代表颜色;S通道,饱和度,取值范围0%~100%,值越大颜色越饱和;V通道,明暗,数值越高越明亮,0%黑到100%白。
HSV颜色空间常用数值如下:
二、基本操作
2.1 图像读取 cv2.imread()
函数cv2.imread(filename, flags)
参数:
filepath:读入imge的完整路径,可以绝对路径也可以相对路径
flags:标志位,{cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSCALE, cv2.IMREAD_UNCHANGED}
cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道,可用1替代
cv2.IMREAD_GRAYSCALE:读入灰度图片,可用0替代
cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道,可用-1替代
PS:alpha通道,又称A通道,是一个8位的灰度通道,该通道用256级灰度来记录图像中的透明度复信息,定义透明、不透明和半透明区域,其中黑表示全透明,白表示不透明,灰表示半透明
示例:
img = cv2.imread('D:/wzx/tu1.jpg',-1)
2.2 图像的显示 cv2.imshow()
函数:cv2.imshow(winname,img)
参数:
winname:显示图像的窗口的名称,需要引号,例如 ‘img1’
img:所显示的图像
PS:
1.函数 cv2.imshow() 之后要用 waitKey() 函数设定图像窗口的显示时长,否则不会显示图像窗口。
2.图像窗口将在 waitKey() 函数所设定的时长(毫秒)后自动关闭,waitKey(0) 表示窗口显示时长为无限。
3.可以创建多个不同的显示窗口,每个窗口必须命名不同的 winname。
4.可以用 destroyWindow() 函数关闭指定的显示窗口,也可以用 destroyAllWindows() 函数关闭所有的显示窗口。
示例:
img = cv2.imread('D:/wzx/tu1,jpg',-1)
cv2.imshow('img1',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
按照上述方式创建的窗口无法自由变换大小,对于过小或者过大的图片不适合,所以可通过如下放大创建可变换大小窗口。
函数:cv2.namedWindow(winname, type)
参数:winname:显示图像的窗口的名称,需要引号,例如 ‘img1’
type: cv2.WINDOW_NORMAL # 用户可以改变这个窗口大小
cv2.WINDOW_AUTOSIZE # 窗口大小自动适应图片大小,并且不可手动更改。
cv2.WINDOW_FREERATIO # 自适应比例
cv2.WINDOW_KEEPRATIO # 保持比例
cv2.WINDOW_OPENGL # 窗口创建的时候会支持OpenGL
示例:
img = cv2.imread('D:/wzx/tu1.jpg',0)
# 创建一个名为“img1”的可变换窗口
cv2.namedWindow('img1',cv2.WINDOW_NORMAL)
# 将图片img显示在窗口“img1”里面
cv2.imshow('img1', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.3 图像的保存 cv2.imwrite()
函数:cv2.imwrite(filename, img [, paras])
参数:
filename:要保存的文件的路径和名称,包括文件扩展名
img:要保存的 OpenCV 图像,nparray 多维数组
paras:不同编码格式的参数,可选项
cv2.CV_IMWRITE_JPEG_QUALITY:设置 .jpeg/.jpg 格式的图片质量,取值为 0-100(默认值 95),数值越大则图片质量越高;
cv2.CV_IMWRITE_WEBP_QUALITY:设置 .webp 格式的图片质量,取值为 0-100;
cv2.CV_IMWRITE_PNG_COMPRESSION:设置 .png 格式图片的压缩比,取值为 0-9(默认值 3),数值越大则压缩比越大。
retval:返回值,保存成功返回 True,否则返回 False。
示例:
# 引号内可以使用绝对路径换文件夹
cv2.imwrite('tu2.jpg',img)
2.4 用matplotlib显示图像 plt.imshow()
函数:matplotlib.pyplot.imshow(img[, cmap])
参数:
- img:图像数据,nparray 多维数组,对于 openCV(BGR)格式图像要先进行格式转换
- cmap:颜色图谱(colormap),默认为 RGB(A) 颜色空间
- gray:灰度显示
- hsv:hsv 颜色空间
PS:
1.OpenCV 和 matplotlib 中的彩色图像都是 Numpy 多维数组。但 OpenCV 使用 BGR 格式,颜色分量按照 BGR 的次序排列,而 matplotlib 使用 RGB 格式,颜色分量按照红/绿/蓝的次序排序。因此用 plt.imshow() 显示 OpenCV 彩色图像时,先要进行颜色空间转换,将 Numpy 多维数组按照RGB的次序排序。
2.plt.imshow() 可以直接显示 OpenCV 灰度图像,不需要格式转换,但需要使用 cmap=‘gray’ 进行参数设置。例如 plt.imshow(imgGray,'gray')
3.plt.imshow() 可以使用 matplotlib 库中的各种方法绘图,如标题、坐标轴、插值等。
4.图片标题有中文时需要设置字体 fontproperties 参数,如 plt.title('图1',fontproperties="SimHei")
5.subplot 函数可以将多个图片显示在一个窗口下,plt.subplot(121)表示这个窗口有1行2列,该图片位于第1个(图片序列号从左往右,从上往下)
6.PyQt5 也使用 RGB 格式,因此在 PyQt5 中显示 OpenCV 彩色图像时,也要进行颜色空间转换。
示例:
plt.subplot(121),plt.plot(img),plt.title('图1',fontproperties="SimHei")
plt.show()
2.5 视频读取 cv2.VideoCapture()
函数:cv2.VideoCapture()
参数:
0:打开笔记本内置摄像头
filename:打开路径下的视频
函数:ret, frame = vc.read()
参数:
vc.read()按帧读取视频,ret,frame是获cap.read()方法的两个返回值。其中ret是布尔值,如果读取帧是正确的则返回True,如果文件读取到结尾,它的返回值就为False。frame就是每一帧的图像,是个三维矩阵。
函数:vc.release()
参数:释放摄像头
示例:
import cv2
import numpy as np
capture = cv2.VideoCapture(0)
width,height = capture.get(3),capture.get(4)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, width*2)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, height*2)
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
outfile = cv2.VideoWriter('Video7.avi',fourcc,25.,(640,480))
while(capture.isOpened()):
ret,frame = capture.read()
if ret:
outfile.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) == ord('q'):
break
else:
break
2.6 图像截取、颜色通道提取
利用Numpy的切片功能
2.7边界填充 cv.copyMakeBorder()
函数:cv2.copyMakeBorder(img,top, bottom, left, right ,borderType)
参数:
img:需要填充的图像
top:图像上边界需要填充的像素点
bottom:图像下边界需要填充的像素点
left:图像左边界需要填充的像素点
right:图像右边界需要填充的像素点
borderType:图像填充的方法,可用方式如下
BORDER_REPLICATE:复制法,也就是复制最边缘像素
BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制,例如:fedcba|abcdefgh|hgfedcb
BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,例如:gfedcb|abcdefgh|gfedcba
BORDER_WRAP:外包装法,例如:abcdefgh|abcdefgh|abcdefg
BORDER_CONSTANT:常量法,常数值填充,需要在设置一个value值,已显示填充的颜色
代码示例:
#边界填充
top_size,bottom_size,left_size,right_size = (50,50,50,50)
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)
#绘制子图
import matplotlib.pyplot as plt
plt.subplot(231), plt.imshow(img, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
plt.show()
2.8 数值计算 img1+img2 cv2.add(img1,img2)
img1 + img2 :数值相加后%256
cv2.add(img1,img2):数值相加,若超过255则按255写入
2.9 图像融合 cv2.addWeighted()
函数:cv2.addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=None)
参数:
src1, src2:融合相加的两个图像的 shape 需要一致
alpha:src1的权重
beta:src2的权重
gamma:gamma修正系数,不需要修正设置为0
dst:可选参数,输出结果保存的变量,默认值为None,如果为非None,输出图像保存到dst对应实参中,其大小和通道数与输入图像相同,图像的深度(即图像像素的位数)由dtype参数或输入图像确认
dtype:可选参数,输出图像数组的深度,即图像单个像素值的位数(如RGB用三个字节表示,则为24位),选默认值None表示与源图像保持一致。
返回值:融合相加的结果图像
示例:
res = cv2.addWeighted(img_cat, 0.4, img_dog, 0.6, 0)
plt.imshow(res)
2.10 通道转化 cv2.cvtColor()
函数:cv2.cvtColor(input_image, flag)
参数:input_image:需要转换的图片
flag:转换的类型,可选类型部分如下
cv2.COLOR_BGR2GRAY:BGR -> Gray
cv2.COLOR_BGR2RGB:BGR -> RGB
cv2.COLOR_BGR2HSV:BGR -> HSV
Ps:“BGR2GRAY” 中的 “2” 可以巧记为 to
示例:
# 以 BGR 转 GRAY 为例
imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
2.11 图像阈值 ret, dst = cv2.threshold()
函数:ret, dst = cv2.threshold(src, thresh, maxval, type)
参数:
-
src: 输入图,只能输入单通道图像,通常为灰度图,彩色图需要对每个通道逐一使用
-
dst: 输出图
-
thresh: 阈值
-
maxval: 当像素值超过了阈值(或者小于阈值,根据type是否有_INV来判断),所赋予的值
-
type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
-
cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
-
cv2.THRESH_BINARY_INV THRESH_BINARY的反转
-
cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
-
cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
-
cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
-
示例:
img=cv2.imread('cat.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
plt.subplot(131), plt.imshow(img, 'gray'),plt.title('Original Image')
plt.subplot(132), plt.imshow(thresh1, 'gray'),plt.title('BINARY')
plt.subplot(133), plt.imshow(thresh2, 'gray'),plt.title('BINARY_INV')
plt.show()
三、图像滤波与增强
3.1 均值滤波 cv2.blur(img, (3, 3))
线性滤波,简单的平均卷积,卷积核大小(3,3)可以任意选择,下同
示例:
blur = cv2.blur(img, (3, 3))
cv2.imshow('blur', blur)
3.2 方框滤波 cv2.boxFilter(img,-1,(3,3), normalize=True)
线性滤波,基本和均值一样,可以通过 normalize 选择是否归一化
示例:
box = cv2.boxFilter(img,-1,(3,3), normalize=True)
cv2.imshow('box', box)
3.3 高斯滤波 cv2.GaussianBlur(img, (5, 5), 1)
线性滤波,高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
aussian = cv2.GaussianBlur(img, (5, 5), 1)
cv2.imshow('aussian', aussian)
3.4 中值滤波 cv2.medianBlur(img, 5)
非线性滤波,相当于用中值代替
median = cv2.medianBlur(img, 5)
cv2.imshow('median', median)
3.5 双边滤波 cv2.bilateralFilter(img,d,sigmaColor,sigmaSpace)
双边滤波是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空间与信 息和灰度相似性,达到保变去噪的目的,具有简单、非迭代、局部处理的特点。
d:像素的邻域直径
sigmaColor:灰度值相似性高斯函数标准差
sigmaSpace:空间高斯函数标准差
关于参数d:过大的滤波器(d>5)执行效率低。 对于实时应用,建议取d=5; 对于需要过滤严重噪声的离线应用,可取d=9; d>0时,由d指定邻域直径; d<=0时,d会自动由sigmaSpace的值确定,且d与sigmaSpace成正比
关于2个sigma参数:简单起见,可以令2个sigma的值相等; 如果他们很小(小于10),那么滤波器几乎没有什么效果; 如果他们很大(大于150),那么滤波器的效果会很强,使图像显得非常卡通化
3.6 直方图 calcHist()
函数
cv2.calcHist(images,channels,mask,histSize,ranges)
参数:
- images: 原图像图像格式为 uint8 或 float32。当传入函数时应用中括号 [] 括起来,例如[img]
- channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。
- mask: 掩模图像。统整幅图像的直方图就把它为 None。但是如 果你想统图像某一分的直方图的你就制作一个掩模图像并 使用它。
- histSize:BIN 的数目。也应用中括号括来
- ranges: 像素值范围常为 [0~256]
Ps:只有参数 mask 不需要中括号
示例:
hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.hist(img.ravel(),256);
plt.show()
3.7 直方图均衡化 cv2.equalizeHist(img)
统计直方图中每个灰度级出现的次数,计算累计归一化直方图,重新计算像素点的像素值。彩色图像均衡化需要对每个通道单独均衡化。
示例:
import cv2
import numpy as np
import matplotlib.pyplot as plt
pic = cv2.imread('./resource/zftjh.jpg',0)
plt.subplot(221),plt.imshow(pic,'gray'),plt.title('原图',fontproperties="SimHei")
plt.subplot(222),plt.hist(pic.ravel(), 256, [0, 256]),plt.title('原图直方图',fontproperties="SimHei")
a = cv2.equalizeHist(pic)
plt.subplot(223),plt.imshow(a,'gray'),plt.title('原图均衡化',fontproperties="SimHei")
plt.subplot(224),plt.hist(a.ravel(), 256, [0, 256]),plt.title('均衡化直方图',fontproperties="SimHei")
plt.show()
局部直方图均衡化:img1 = cv2.createCLAHE(clipLimit=2,tileGridSize=(30,30))
3.8 Gamma变换
def adjust_gamma(image, gamma=1.0):
invGamma = 1.0/gamma
table = []
for i in range(256):
table.append(((i / 255.0) ** invGamma) * 255)
table = np.array(table).astype("uint8")
print(table)
return cv2.LUT(image, table)
img_gamma = adjust_gamma(img, 0.8)
四、图像的几何变换
4.1 图像平移 cv2.warpAffine()
函数:cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
通过变换矩阵 M 对图像 src 进行仿射变换
参数:
scr:变换操作的输入图像
M:仿射变换矩阵,2行3列
dsize: 输出图像的大小,二元元组 (width, height)
dst:变换操作的输出图像,可选项
flags:插值方法,整型(int),可选项
cv2.INTER_LINEAR:线性插值,默认选项
cv2.INTER_NEAREST:最近邻插值
cv2.INTER_AREA:区域插值
cv2.INTER_CUBIC:三次样条插值
cv2.INTER_LANCZOS4:Lanczos 插值
borderMode:边界像素方法,整型(int),可选项,默认值为 cv2.BORDER_REFLECT
borderValue:边界填充值,可选项,默认值为 0(黑色填充)
示例:
import cv2
import numpy as np
img = cv2.imread('img2.png')
# 构造移动矩阵H
# 在x轴方向移动多少距离,在y轴方向移动多少距离
H = np.float32([[1, 0, 50], [0, 1, 25]])
rows, cols = img.shape[:2]
print(img.shape)
print(rows, cols)
# 注意这里rows和cols需要反置,即先列后行
res = cv2.warpAffine(img, H, (2*cols, 2*rows))
cv2.imshow('origin_picture', img)
cv2.imshow('new_picture', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.2 图像缩放 cv2.resize()
方法一:设置缩放比例,来对图像进行放大或缩小
函数:cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
示例:
res1 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
height, width = img.shape[:2]
方法二:直接设置图像的大小,不需要缩放因子
#cv2.INTER_NEAREST(最近邻插值) cv2.INTER_AREA (区域插值) cv2.INTER_CUBIC(三次样条插值) cv2.INTER_LANCZOS4(Lanczos插值)
res2 = cv2.resize(img, (int(0.8*width), int(0.8*height)),interpolation=cv2.INTER_LANCZOS4)
cv2.imshow('origin_picture', img)
#|cv2.imshow('res1', res1)
cv2.imshow('res2', res2)
4.3 图像旋转 cv2.getRotationMatrix2D()
函数:cv2.getRotationMatrix2D(center, angle, scale)
参数:center:旋转中心
angle:旋转角度,正为逆时针,负为顺时针
scale:缩放因子
示例:
import cv2
import numpy as np
img=cv2.imread('img2.png',1)
rows,cols=img.shape[:2]
#参数1:旋转中心,参数2:旋转角度,参数3:缩放因子
#参数3正为逆时针,负值为正时针
M=cv2.getRotationMatrix2D((cols/2,rows/2),45,1,)
print(M)
#第三个参数是输出图像的尺寸中心
dst=cv2.warpAffine(img,M,(cols,rows))
#borderValue为填充值
#dst=cv2.warpAffine(img,M,(cols,rows),borderValue=(255,255,255))
while(1):
cv2.imshow('img', img)
cv2.imshow('img1',dst)
#0xFF==27 ESC
if cv2.waitKey(1)&0xFF==27:
break
cv2.destroyAllWindows()
4.4 放射变换 cv2.getAffineTransform()
函数:cv2.getAffineTransform(pos1,pos2)
参数:
pos1:变换前的位置
pos2:变换后的位置
4.5 透视变化 cv2.getPerspectiveTransform() / cv2.warpPerspectiveTransform()
函数:cv2.getPerspectiveTransform(pos1, pos2)
参数:
pos1:变换前的4个点对应位置
pos2:变换后的4个点对应位置
函数:cv2.warpPerspectiveTransform(src, M, (cols,rows))
参数:
src:原始图像
M:变换矩阵
(cols.rows):变换后的图像大小,rows表行数,cols表列数
五、形态学
5.1 腐蚀操作 cv2.erode()
函数:cv2.erode(src,element,anchor,iterations)
参数说明:
src:原图像
element:腐蚀操作的内核,默认为(3,3)矩阵,可自定义
anchor:默认为Point(-1,-1),内核中心点
iterations:腐蚀次数,默认为1
作用:腐蚀类似于“领域被蚕食”,将图像中白色部分进行缩减细化,其运行结果图比原图的白色区域更小。
示例:
img = cv2.imread('img1.jpg')
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
5.2 膨胀操作 cv2.dilate()
函数:cv2.dilate(src, element, anchor, iterations)
参数:同腐蚀操作
作用:膨胀类似于“领域扩张”,将图像中的白色部分进行扩张,其运行结果图比原图的白色区域更大。
img = cv2.imread('img1.jpg')
kernel = np.ones((3,3),np.uint8)
dilate = cv2.dilate(img,kernel,iterations = 1)
cv2.imshow('dilate', dilate )
cv2.waitKey(0)
cv2.destroyAllWindows()
5.3 开运算 cv2.morphologyEx()
先腐蚀,后膨胀
函数:cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
5.4 闭运算 cv2.morphologyEx()
先膨胀,后腐蚀
函数:cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
示例:
img = cv2.imread('dige.png')
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) #开运算
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) #闭运算
cv2.imshow('opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
5.5 梯度运算
梯度 = 膨胀 - 腐蚀
函数:cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
示例:
img = cv2.imread('tu1.png')
kernel = np.ones((7,7),np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('gradient', gradient)
5.6 礼帽与黑帽
礼帽 = 原始输入-开运算结果
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
黑帽 = 闭运算-原始输入
blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)
5.7 图像梯度
5.7.1 Sobel 算子
函数:
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
参数:
ddepth:图像的深度
dx和dy:分别表示水平和竖直方向
ksize:Sobel算子的大小,必须为1,3,5,7
白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值
分别计算 x 和 y,再求和,不建议直接计算
示例:
img = cv2.imread('Lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3) # 计算 x 梯度
sobelx = cv2.convertScaleAbs(sobelx) # 取绝对值
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3) # 计算 y 梯度
sobely = cv2.convertScaleAbs(sobely) # 取绝对值
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) # 求和
cv2.imshow('sobelxy',sobelxy )
cv2.waitKey(0)
cv2.destroyAllWindows()
5.7.2 Scharr 算子
示例:
img = cv2.imread('Lena.jpg',cv2.IMREAD_GRAYSCALE)
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
cv2.imshow('scharrxy ',scharrxy )
cv2.waitKey(0)
cv2.destroyAllWindows()
5.7.3 laplacian 算子
示例:
img = cv2.imread('Lena.jpg',cv2.IMREAD_GRAYSCALE)
laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
cv2.imshow('scharrxy ',scharrxy )
cv2.waitKey(0)
cv2.destroyAllWindows()
六、边缘检测、提取
6.1 图像金字塔
高斯金字塔:cv2.pyrUp(img) / cv2.pyrDown(img)
整倍数的放大缩小
拉普拉斯金字塔:先缩小再放大为原图大小
down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
6.2 Canny 边缘检测算法
Canny算子是先平滑后求导数的方法。该算法有较好的错判率,定位性能,且对单一边缘仅有唯一响应。
算法步骤如下:
- 彩色图像转换为灰度图(以灰度图单通道读入);
- 对图像进行高斯模糊(去噪);
- 计算图像梯度,根据梯度计算图像边缘幅值与角度;
- 沿梯度方向进行非极大值抑制(边缘细化);
- 双阈值边缘连接处理;
- 通过抑制孤立的弱边缘最终完成边缘检测,二值化图像输出结果
函数:cv2.Canny(img, th1,th2,size)
参数:
img:原图像
th1:阈值1,较低的
th2:阈值2,较高的
size:可选参数,Sobel 算子的大小
示例:
img=cv2.imread("Lena.jpg",0)
v1=cv2.Canny(img,80,150)
v2=cv2.Canny(img,50,100)
res = np.hstack((v1,v2))
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.3 区域生长算法
区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止。进而实现目标的提取。
区域生长的好坏决定于:初始点的选取,生长条件,终止条件。
算法步骤:
- 对图像顺序扫描,找到第一个还没有归属的像素,设该像素为(x0,y0);
- 以(x0,y0)为中心,考虑其4邻域像素(x,y),若满足生长条件,则将(x,y)与(x0,y0)合并(在同一区域内),同时将(x,y)压入堆栈;
- 从堆栈中取出一个像素,把它当作(x0,y0)返回步骤2;
- 当堆栈为空时,返回步骤1;
- 重复步骤1-4直到图像中的每个点都有归属时,生长结束
6.4 图像轮廓 cv2.findContours()
函数:
cv2.findContours(img,mode,method)
参数:
img:原图
mode:轮廓检索模式
RETR_EXTERNAL :只检索最外面的轮廓;
RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;
method:轮廓逼近方法
CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
示例:
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 旧版CV返回3个值,新版CV只返回2个值(contours 和 hierarchy)
#binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
当轮廓过多,需要通过轮廓的面积、周长、长宽比等选择出符合条件的轮廓时,可以遍历每个轮廓,以求每个方块轮廓的质心为例:
contours, hierarchy = cv2.findContours(dst, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# print(len(contours))
cntc = 0
# 遍历轮廓
for c in contours:
cntc += 1
(x, y, w, h) = cv2.boundingRect(c) # 获取轮廓点位坐标
cenX = int(x + w/2)
cenY = int(y + h/2)
# cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2) # 画出轮廓的矩形框
# rect = cv2.minAreaRect(c)#绘制最小矩形框
# box = cv2.boxPoints(rect) #找矩形的四个顶点
# box = np.int0(box)
# cv2.drawContours(img, [box], 0, (0, 0, 255), 3)
print('第', cntc, '个方块的质心位置为:', cenX, cenY, '面积为:', w*h)
七、傅里叶变换
傅里叶变换的作用:
-
高频:变化剧烈的灰度分量,例如边界
-
低频:变化缓慢的灰度分量,例如一片大海
滤波:
-
低通滤波器:只保留低频,会使得图像模糊
-
高通滤波器:只保留高频,会使得图像细节增强
opencv中主要就是cv2.dft()和cv2.idft(),输入图像需要先转换成np.float32 格式,得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,通过shift变换。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('lena.jpg',0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('lena.jpg',0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2) # 中心位置
# 低通滤波
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show()
img = cv2.imread('lena.jpg',0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2) # 中心位置
# 高通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0
# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show()