概述
课程一览:
目录
1.opencv中的绘图函数
1.1 线段绘制
1.2 矩形绘制
1.3 圆、椭圆绘制
1.4 多边形绘制
1.5 添加文字
2.图像的几何变换
2.1 图像平移
2.2 图像缩放
2.3 图像旋转
2.4 图像镜像
2.5 仿射变换
2.6 透视变换
3.图像滤波与增强
3.1线性滤波
3.2 非线性滤波
3.3 图像锐化
3.4 直方图均衡化
3.5 Gamma变化
4.图像形态学操作
4.1 图像腐蚀
4.2 图像膨胀
4.3 开运算
4.4 闭运算
4.5 形态学梯度
4.6 顶帽和黑帽
1.opencv中的绘图函数
1.1 线段绘制
函数:cv2.line(img,pts,color,thickness,linetype)
参数说明:
- img:待绘制的图像
- color:形状的颜色,元组如(255,0,0)
- pts:起点和终点
- thickness:线条的粗细。-1位填充,默认值是1。
- linetype:线条的类型,8型或cv2.LINE_AA,默认值为8型。(AA比8型更快,8型比AA型更好看)
#=============================绘制线段============================#
# flag = 0
flag = 1
if flag == 1:
# 创建一张黑色的背景图
img=np.zeros((512,512,3), np.uint8)
cv2.imshow("black", img)
cv2.waitKey(0)
cv2.destroyWindow("black")
# 绘制一条线宽为5的线段
cv2.line(img,(0,0),(200,500),(0,0,255),5)
#定义一个变量
winname = 'example'
#将这个名字作为窗口名
cv2.namedWindow(winname)
cv2.imshow(winname, img)
cv2.waitKey(0)
cv2.destroyWindow(winname)
输出结果:
1.2 矩形绘制
函数:cv2.rectangle(img,prets,color,thickness,linetype)
参数说明:
- img:待绘制图像
- pts:左上角和右下角坐标点
- color:形状的颜色,元组如(255,0,0)
- thickness:线条的粗细。-1位填充,默认值是1。
- linetype:线条的类型,使用默认值即可
#=============================矩形线段============================#
# flag = 0
flag = 1
if flag == 1:
img = np.zeros((512,512,3),np.uint8)
#绘制矩形
#新图像可以单独命名,也可以直接原位操作
img_2 = cv2.rectangle(img,(23,23),(234,134),(19,0,240),-1)
# cv2.rectangle(img, (23, 23), (234, 134), (19, 0, 240), -1)
cv2.imshow("rectangle",img_2)
cv2.waitKey(0)
cv2.destroyWindow()
1.3 圆、椭圆绘制
绘制圆
函数:cv2.circle(img,pts,radius,color,thickness,linetype)
参数说明:
- img:待绘制图像
- pts:左圆心
- radius:半径
- color:形状的颜色
- thickness:线条的粗细。-1位填充,默认值是1。
- linetype:线条的类型,使用默认值即可
#=============================圆绘制============================#
# flag = 0
flag = 1
if flag == 1:
img = np.zeros((512,512,3),np.uint8)
#绘制圆形
#新图像可以单独命名,也可以直接原位操作
#最后一个参数为1则表示不填充
img_2 = cv2.circle(img,(100,100),78,(19,0,240),-1)
# cv2.rectangle(img, (23, 23), (234, 134), (19, 0, 240), -1)
cv2.imshow("rectangle",img_2)
cv2.waitKey(0)
cv2.destroyWindow()
绘制椭圆
函数:cv2.ellipse()
画椭圆需要的参数比较多,请对照后面的代码理解这几个参数。
参数说明:
- 参数1:图像
- 参数2:椭圆中心(x,y)
- 参数3:x/y轴的长度
- 参数4:angle——椭圆的旋转角度
- 参数5:startAngle——椭圆的起始角度
- 参数6:endAngle——椭圆的结束角度
#=============================椭圆绘制============================#
# flag = 0
flag = 1
if flag == 1:
img = np.zeros((512,512,3),np.uint8)
#绘制椭圆
#新图像可以单独命名,也可以直接原位操作
#最后一个参数为1则表示不填充
cv2.ellipse(img,(200,100),(78,45),0,30,270,(19,0,240),-1)
cv2.ellipse(img, (200, 250), (78, 45), 0, 0, 360, (19, 0, 240), -1)
cv2.ellipse(img, (200, 400), (78, 45), 30, 180, 360, (19, 0, 240), -1)
# cv2.rectangle(img, (23, 23), (234, 134), (19, 0, 240), -1)
cv2.imshow("picture",img)
cv2.waitKey(0)
cv2.destroyWindow()
1.4 多边形绘制
函数:cv2.polylines(img,pts,isClosed,color,thickness,lineType)
参数说明:
- 参数1:img图像
- 参数2:pts,表示多个坐标点
- 参数3:isClosed,布尔型,True表示的是线段闭合,False表示的是仅保留线段
- 参数4:color,线段颜色,格式是(R,G,B)
- 参数5:thickness,数值型,线宽度,默认值为1,-1则会填充整个图形
- 参数6:lineType,线型
#=============================多边形绘制============================#
# flag = 0
flag = 1
if flag == 1:
img = np.zeros((512, 512, 3), np.uint8)
# 定义四个顶点坐标
pts = np.array([[200, 200], [250, 210], [100, 280], [230, 100]])
print(pts)
# 顶点个数:4,矩阵变成4*1*2维
pts = pts.reshape((-1, 1, 2))
print(pts)
#绘制多边形
cv2.polylines(img, [pts], False, (19, 0, 240))
cv2.polylines(img, [pts], True, (19, 0, 240))
cv2.imshow("picture", img)
cv2.waitKey(0)
cv2.destroyWindow()
1.5 添加文字
函数:cv2.putText()
参数说明:
- 参数1:img,图像--画板
- 参数2:要添加的文字
- 参数3:文字的起始坐标(左下角为起点)
- 参数4:字体
- 参数5:文字大小(缩放比例)
- 参数6:颜色
- 参数7:线条宽度
- 参数8:线条形状
#=============================添加文字============================#
# flag = 0
flag = 1
if flag == 1:
img = np.zeros((512, 512, 3), np.uint8)
#添加文字
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(50,200), font, 3,(0,255,255),5)
cv2.imshow("picture", img)
cv2.waitKey(0)
cv2.destroyWindow()
2.图像的几何变换
2.1 图像平移
图像平移:
将图像中所有的点按照指定的平移量水平或垂直移动。
变换公式:
设(x0,y0)为原图像上的一点,图像水平平移量为Tx,垂直平移量为Ty,则平移后的点坐标(x1,y1)变为:
x1 = x0 + Tx; y1 = y0 + Ty
用仿射变换来封装函数
仿射变换函数:cv2.warpAffine(src,M,dsize,flags,borderMode,borderValue)
参数说明:
- src:输入图像
- M:变换矩阵
- M作为仿射变换矩阵,一般反映平移或旋转的关系,为InputArray类型的2×3的变换矩阵
- dsize:输出图像的大小
- flags:插值方法的组合(int类型!)
- 默认为flag = cv2.INTER_LINEAR,表示线性插值
- cv2.INTER_NEAREST(最近邻插值)
- cv2.INTER_AREA(区域插值)
- cv2.INTER_CUBIC(三次样条插值)
- cv2.INTER_LANCZOS4(Lanczos插值)
- borderMode:边界像素模式(int类型!)
- borderValue:(重点!)边界填充值;默认情况下为0。
#=============================图像平移============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('img2.png')
# 构造移动矩阵H
# 在x轴方向移动多少距离,在y轴方向移动多少距离
#[1,0,50]表示在x轴上移动50单位;[0,1,25]表示在y轴上平移25单位
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()
2.2 图像缩放
下采样:缩小图像称为下采样或降采样
上采样:方法图像称为上采样,主要目的是得到更高的分辨率
图像缩放:图像缩放是指图像大小按照指定比例进行方法或缩小
函数:cv2.resize(src,dsize=None,fx,fy,interpolation)
参数说明:
- src:原图
- dsize:输出图像尺寸,与比例因子二选一
- fx:沿水平轴的比例因子
- fy:沿垂直轴的比例因子
- interpolation:插值方法
- 默认为flag = cv2.INTER_NEAREST(最近邻插值)
- cv2.INTER_LINEAR,表示线性插值
- cv2.INTER_AREA(区域插值)
- cv2.INTER_CUBIC(三次样条插值)
- cv2.INTER_LANCZOS4(Lanczos插值)
(1)最近邻插值:最简单的一种插值方法,不需要计算,在待求像素的四邻像素中,将距离待求像素最近的邻像素灰度赋给待求像素。(缺点:输出的图像会有锯齿状)
设i+u,j+v(i,j为正整数,u,v为大于零小于1的小数,下同)为待求像素坐标,则待求像素灰度的值f(i+u,j+v)
公式如下:src为原来的坐标,dst为待求的坐标
如图:图像由原来的3×3变为4×4大小的图像
srcWidth为3;dstWidth为4
以待求图的第一个点(0,0)为例:
srcX = (0*(3/4),0*(3/4))=(0,0)= 234
得出的(0,0)就为原图坐标,则待求点的值就用求出的相对应原图位置的值来代替
以待求图的(3,0)点为例:
srcX = ((3*(3/4),(0*(3/4))=(3*0.75,0)=(2.25)=(2,0)=89
采用四舍五入的方法求最近坐标
(2)线性插值:
单线性插值:
双线性插值:
双线性插值又叫一阶插值法,它要经过三次插值才能获得最终结果,是对最近邻插值法的一种改进,先对两水平方向进行一阶线性插值,然后再在垂直方向进行一阶线性插值。
#=============================图像缩放============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('img2.png')
# 方法一:通过设置缩放比例,来对图像进行放大或缩小
#缩放因子设置为2,放大两倍
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)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.3 图像旋转
图像旋转:以图像的中心为原点,旋转一定的角度,也就是将图像上的所有像素都旋转一个相同的角度。旋转都图像的大小一般会改变,即可以把转出显示区域的图像裁取,或扩大图像范围来显示所有的图像。图像的旋转变换也可以用矩阵变换来表示。
设点逆时针旋转角后的对应点为
那么,旋转后点的坐标是:
利用上述方法进行图像旋转是需要注意以下两点:
(1)图像旋转之前,为了避免信息的丢失,一定要有坐标平移。
(2)图像旋转之后,会出现许多空洞点。对这些空洞点必须进行填充处理,否则画面效果不好,一般也称这种操作为插值处理。
图像的旋转使用仿射变换函数封装:
变换矩阵函数:cv2.getRotationMatrix2D(center,angle,scale)
参数说明:
- center:图片的旋转中心
- angle:旋转角度
- scale:缩放比例,0.5表示缩小一半
- scale的正负表示旋转方向:正为逆时针,负为顺时针。
#=============================图像旋转============================#
# flag = 0
flag = 1
if flag == 1:
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))
#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()
2.4 图像镜像
2.5 仿射变换
仿射变换的作用:通过仿射变换对图片进行旋转、平移、缩放等操作以达到数据增强的效果。
线性变换从几何直观上来看有两个要点:变换之前是直线、变换之后依然是直线;直线的比例保持不变。
以下变换分别为:平移、旋转、同比例缩放、不同比例缩放、镜像、剪切
仿射变换:平移、旋转、缩放、剪切、反射
函数:
仿射变换的函数原型如下:
M = cv2.getAffineTransform(pos1,pos2)
pos1表示变换前的位置,三个点
pos2表示变换后的位置,三个点
#=============================仿射变换============================#
# flag = 0
flag = 1
if flag == 1:
src = cv2.imread('bird.png')
# 获取图像大小
rows, cols = src.shape[:2]
# 设置图像仿射变换矩阵
pos1 = np.float32([[50, 50], [200, 50], [50, 200]])
pos2 = np.float32([[10, 100], [200, 50], [100, 250]])
M = cv2.getAffineTransform(pos1, pos2)
print(M)
# 图像仿射变换
result = cv2.warpAffine(src, M, (2 * cols, 2 * rows))
# 显示图像
cv2.imshow("original", src)
cv2.imshow("result", result)
# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
2.6 透视变换
透视变换:本质是将图像投影到一个新的视屏面
函数:
M = cv2.getPerspectiveTransform(pos1,pos2)
参数说明:
- pos1表示透视变换前的四个点对应位置
- pos2表示透视变换后的四个点对应位置
cv2.warpPerspective(src,M,(cols,rows))
参数说明:
- src表示原始图像
- M表示透视变换矩阵
- (rows,cols)表示变换后的图像大小,rows表示行数,cols表示列数
# =============================透视变换============================#
# flag = 0
flag = 1
if flag == 1:
#读取图片
src = cv2.imread('bird.png')
#获取图像大小
rows, cols = src.shape[:2]
#设置图像透视变换矩阵
pos1 = np.float32([[114, 82], [287, 156],
[8, 100], [143, 177]])
pos2 = np.float32([[0, 0], [188, 0],
[0, 262], [188, 262]])
M = cv2.getPerspectiveTransform(pos1, pos2)
#图像透视变换
result = cv2.warpPerspective(src, M, (2*cols,2*rows))
#显示图像
cv2.imshow("original", src)
cv2.imshow("result", result)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
2.7 小结
例1:利用图像的变换对文档进行矫正
# =============================图像矫正============================#
# flag = 0
flag = 1
if flag == 1:
#读取图片
src = cv2.imread('paper.png')
#获取图像大小
rows, cols = src.shape[:2]
#将源图像高斯模糊,去除噪声
img = cv2.GaussianBlur(src, (3,3), 0)
#进行灰度化处理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#边缘检测(检测出图像的边缘信息)
edges = cv2.Canny(gray,50,250,apertureSize = 3)
cv2.imwrite("canny.jpg", edges)
cv2.imshow("canny", edges)
#通过霍夫变换得到A4纸边缘,这是可以在二值图像中检测直线的方法
lines = cv2.HoughLinesP(edges,1,np.pi/180,50,minLineLength=90,maxLineGap=10)
print(lines)
#下面输出的四个点分别为四个顶点
for x1,y1,x2,y2 in lines[0]:
print(x1,y1)
print(x2,y2)
for x3,y3,x4,y4 in lines[1]:
print(x3,y3)
print(x4,y4)
#绘制边缘
for x1,y1,x2,y2 in lines[0]:
cv2.line(gray, (x1,y1), (x2,y2), (0,0,255), 1)
#根据四个顶点设置图像透视变换矩阵
pos1 = np.float32([[114, 82], [287, 156], [8, 322], [216, 333]])
pos2 = np.float32([[0, 0], [188, 0], [0, 262], [188, 262]])
M = cv2.getPerspectiveTransform(pos1, pos2)
# pos1 = np.float32([[114, 82], [287, 156], [8, 322]])
# pos2 = np.float32([[0, 0], [188, 0], [0, 262]])
# M = cv2.getAffineTransform(pos1,pos2)
print(M)
#图像仿射变换
#result = cv2.warpAffine(src, M, (2*cols, 2*rows))
#图像透视变换
result = cv2.warpPerspective(src, M, (190, 272))
#显示图像
cv2.imshow("original", src)
cv2.imshow("result", result)
cv2.imshow("gray", gray)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
例2:利用几何变换,对图像进行扩增
# =============================图数扩增============================#
# flag = 0
flag = 1
if flag == 1:
# 读取图片
img = cv2.imread('test2.png')
image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 图像平移矩阵
M = np.float32([[1, 0, 80], [0, 1, 30]])
rows, cols = image.shape[:2]
img1 = cv2.warpAffine(image, M, (cols, rows))
# 图像缩小
img2 = cv2.resize(image, (200, 100))
# 图像放大
img3 = cv2.resize(image, None, fx=1.1, fy=1.1)
# 绕图像的中心旋转
# 源图像的高、宽 以及通道数
rows, cols, channel = image.shape
# 函数参数:旋转中心 旋转度数 scale
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 30, 1)
# 函数参数:原始图像 旋转参数 元素图像宽高
img4 = cv2.warpAffine(image, M, (cols, rows))
# 图像翻转
img5 = cv2.flip(image, 0) # 参数=0以X轴为对称轴翻转
img6 = cv2.flip(image, 1) # 参数>0以Y轴为对称轴翻转
# 图像的仿射
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[10, 100], [200, 50], [100, 250]])
M = cv2.getAffineTransform(pts1, pts2)
img7 = cv2.warpAffine(image, M, (rows, cols))
# 图像的透射
pts1 = np.float32([[56, 65], [238, 52], [28, 237], [239, 240]])
pts2 = np.float32([[0, 0], [200, 0], [0, 200], [200, 200]])
M = cv2.getPerspectiveTransform(pts1, pts2)
img8 = cv2.warpPerspective(image, M, (200, 200))
# 循环显示图形
titles = ['source', 'shift', 'reduction', 'enlarge', 'rotation', 'flipX', 'flipY', 'affine', 'transmission']
images = [image, img1, img2, img3, img4, img5, img6, img7, img8]
for i in range(9):
plt.subplot(3, 3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
3.图像滤波与增强
- 滤波实际上是信号处理的一个概念,图像可以看成一个二维信号,其中像素点的灰度值代表信号的强弱。
- 高频:图像上变化剧烈的部分
- 低频:图像灰度值变化缓慢,平坦的地方
- 根据图像高低频,设置高通和低通滤波器。高通滤波器可以检测变化尖锐,明显的地方,低通可以让图像变得平滑,消除噪声
- 滤波作用:高通滤波用于边缘检测,低通滤波用于图像平滑去噪
- 线性滤波:方框滤波/均值滤波/高斯滤波
- 非线性滤波:中值滤波/双边滤波
3.1线性滤波
邻域算子:利用给定像素周围的像素值决定此像素的最终输出值得一种算子。
线性滤波:一种常用的邻域算子,像素输出取决于输入像素的加权和。(卷积操作)
(1)方框滤波
方框滤波被封装在一个名为boxFilter的函数中,即boxFilter函数的作用是使用方框滤波器来模糊一张图片,从src输入,从dst输出。
方框滤波核:
normalize = True 与均值滤波相同,归一化
normalize = False 很容易发生溢出
函数:cv2.boxFilter(src,depth,ksize,normalize)
参数说明:
- 参数1:输入图像
- 参数2:目标图像深度,一般采用默认值
- 参数3:核大小,默认是3×3
- 参数4:normalize属性,1或 0
# =============================方框滤波============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('girl2.png',cv2.IMREAD_UNCHANGED)
r = cv2.boxFilter(img, -1 , (7,7) , normalize = 1)
d = cv2.boxFilter(img, -1 , (3,3) , normalize = 0)
cv2.namedWindow('img',cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('r',cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('d',cv2.WINDOW_AUTOSIZE)
cv2.imshow('img',img)
cv2.imshow('r',r)
cv2.imshow('d',d)
cv2.waitKey(0)
cv2.destroyAllWindows()
(2)均值滤波
均值滤波是一种最简单的滤波处理,它取的是卷积核区域内元素的均值,用cv2.blur()实现,如3×3的卷积核:
函数:cv2.blur(src,ksize)
参数说明:
- 参数1:输入原图
- 参数2:kernel的大小,一般为奇数
# =============================均值滤波============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('image/opencv.png')
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
blur = cv2.blur(img,(7,7 ))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
#不显示坐标
plt.xticks([]), plt.yticks([])
plt.show()
(3)高斯滤波
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛用于图像处理的减噪过程。高斯滤波的卷积核权重并不相同,中间像素点权重最高,越远离中心的像素权重越小。(其原理是一个二维高斯函数)
高斯滤波相比均值滤波效率要慢,但可以有效消除高斯噪声,能保留更多的图像细节,所以经常被称为最有用的滤波器。
函数:cv2.Guassianblur(src,ksize,std) ,表示进行高斯滤波
参数说明:
- 参数1:输入原图
- 参数2:高斯核大小
- 参数3:标准差σ,平滑时,调整σ实际是在调整周围像素对当前像素的影响程度,调大σ即提高了远处像素对中心像素的影响程度,滤波结果也就越平滑。
# =============================高斯滤波============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('image/median.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
blur = cv2.GaussianBlur(img, (7, 7), 7)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()
可以看到噪声消除了一些
3.2 非线性滤波
(1)中值滤波
中值滤波是一种非线性滤波,是用像素点邻域灰度值的中值代替该点的灰度值,中值滤波可以去除椒盐噪声和斑点噪声。
函数:cv2.medianBlur(img,ksize)
参数说明:
- 参数1:输入图像
- 参数2:核大小
# =============================中值滤波============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('image/median.png')
median = cv2.medianBlur(img, 3)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(median), plt.title('median')
plt.xticks([]), plt.yticks([])
plt.show()
(2)双边滤波
双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。
函数:cv2.bilateralFilter(src = image,d,sigmaColor,sigmaSpace)
参数说明:
- 参数1:输入原图
- 参数2:像素的邻域直径
- 参数3:灰度值相似性高斯函数标准差
- 参数4:空间高斯函数标准差
# =============================双边滤波============================#
# flag = 0
flag = 1
if flag == 1:
'''
关于2个sigma参数:
简单起见,可以令2个sigma的值相等;
如果他们很小(小于10),那么滤波器几乎没有什么效果;
如果他们很大(大于150),那么滤波器的效果会很强,使图像显得非常卡通化;
关于参数d:
过大的滤波器(d>5)执行效率低。 对于实时应用,建议取d=5;
对于需要过滤严重噪声的离线应用,可取d=9;
d>0时,由d指定邻域直径;
d<=0时,d会自动由sigmaSpace的值确定,且d与sigmaSpace成正比;
'''
img = cv2.imread('image/bilateral.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
blur = cv2.bilateralFilter(img, -1, 15, 10)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()
加大参数3和参数4的值可以更好的去除噪声
3.3 图像锐化
# =============================图像锐化============================#
# flag = 0
flag = 1
if flag == 1:
def custom_blur_demo(image):
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) #锐化
dst = cv2.filter2D(image, -1, kernel=kernel)
cv2.imshow("custom_blur_demo", dst)
src = cv2.imread("./image/sharpen.png")
cv2.namedWindow("input image", cv2.WINDOW_AUTOSIZE)
cv2.imshow("input image", src)
custom_blur_demo(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.4 直方图均衡化
(1)灰度图直方图均衡化
目的:直方图均衡化是将原图通过某种变换,得到一幅灰度直方图为均匀分布的新图像的方法
直方图均衡化方法的基本思想是对在图像中像素个数多的灰度级进行展宽,而对像素个数少的灰度级进行缩减。从而达到清晰图像的目的。
函数:cv2.equalizeHist(img)
参数说明:
- 参数1:待均衡化图像
步骤:
- 统计直方图中每个灰度级出现的次数
- 计算累计归一化直方图
- 重新计算像素点的像素值。
# =============================直方图均衡化============================#
# flag = 0
flag = 1
if flag == 1:
#直接读为灰度图像
img = cv2.imread('./image/dark.png',0)
cv2.imshow("dark",img)
cv2.waitKey(0)
#调用cv2.equalizeHist函数进行直方图均衡化
img_equal = cv2.equalizeHist(img)
cv2.imshow("img_equal",img_equal)
cv2.waitKey(0)
cv2.destroyAllWindows()
(2)局部直方图均衡化
# flag = 0
flag = 1
if flag == 1:
#局部直方图均衡化
#直接读为灰度图像
img = cv2.imread('./image/dark.png',0)
cv2.imshow("dark",img)
cv2.waitKey(0)
#调用cv2.createCLAHE函数进行局部直方图均衡化
clahe = cv2.createCLAHE(clipLimit=2,tileGridSize=(30,30))
cl1 = clahe.apply(img)
cv2.imshow("img_equal",cl1)
cv2.waitKey(0)
cv2.destroyAllWindows()
(3)彩色图直方图均衡化
# flag = 0
flag = 1
if flag == 1:
#彩图直方图均衡化
img = cv2.imread("./image/dark1.jpg")
cv2.imshow("src", img)
# 彩色图像均衡化,需要分解通道 对每一个通道均衡化
(b, g, r) = cv2.split(img)
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
# 合并每一个通道
result = cv2.merge((bH, gH, rH))
cv2.imshow("dst", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
亮度提升,但提升效果夸张
3.5 Gamma变化
Gamma变换是对输入图像灰度值进行的非线性操作,使输出图像灰度值与输入图像灰度值呈指数关系。
目的:Gamma变换就是用来图像增强,其提升了暗部细节,通过非线性变换,让图像从曝光强度的线性响应变得更接近人眼感受的响应,即将漂白(相机曝光)或过暗(曝光不足)的图片,进行矫正。
Gamma > 1,图像变亮
Gamma < 1,图形变暗
# =============================Gamma变换============================#
# flag = 0
flag = 1
if flag == 1:
img=cv2.imread('./image/dark1.jpg')
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)
#print(img_gamma)
cv2.imshow("img",img)
cv2.imshow("img_gamma",img_gamma)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.图像形态学操作
形态学是图像处理中应用最为广泛的技术之一,主要用于从图像中提取对表达和描绘区域形状有意义的图像分量,使后续的识别工作能够抓住目标对象最为本质的形状特征,如边界和连通区域等。
结构元素:
设有两幅图像B,X。
若X是被处理的对象,而B是用来处理X的,则称B为结构元素,又被形象的称作刷子。
结构原色通常都是一些比较小的图像。
腐蚀和膨胀
图像的膨胀(Dilation)和腐蚀(Erosion)是两种基本的形态学运算,其中膨胀类似于“领域扩张”,将图像中的白色部分(领域)进行扩张,其运行结果图比原图的白色区域更大;腐蚀类似于“领域被蚕食”,将图像中白色部分进行缩减细化,其运行结果图比原图的白色区域更小。
4.1 图像腐蚀
(1)灰度图像的腐蚀操作
腐蚀运算符“—”,其定义如下:
该公式表示图像A用卷积模板B来进行腐蚀处理,通过模板B与图像A进行卷积计算,得出B覆盖区域的像素点最小值,并用这个最小值来代替参考点的像素值。
(2)二值图像的腐蚀操作
把结构元素B平移a后得到Ba,若Ba包含于X,我们记下这个a点,所有满足上述条件的a点组成的集合称作X被B腐蚀的结果。如图所示。
其中X是被处理的对象,B是结构元素。对于任意一个在阴影部分的点a,Ba包含于X,所以X被B腐蚀的结果就是那个阴影部分。阴影部分在X的范围之内,且比X小,就像X被剥掉一层似的。
函数:cv2.erode(src,element,anchor,iterations)
参数说明:
- 参数1:src,原图像
- 参数2:element,腐蚀操作的内核,默认为一个简单的3×3矩阵
- 参数3:anchor,默认为point(-1,1),内核中心点
- 参数4:iterations,腐蚀次数,默认值为1
# =============================图像腐蚀============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('./image/morphology.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(erosion),plt.title('erosion')
plt.xticks([]), plt.yticks([])
plt.show()
4.2 图像膨胀
膨胀(dilation)可以看做是腐蚀的对偶运算。
其定义是:把结构元素B平移a后得到Ba,若Ba击中(即B的任何一个点碰到X)X,我们记下这个a点。所有满足上述条件的a点组成的集合称作X被B膨胀的结果。如图所示。
其中X是被处理的对象,B是结构元素,对于任意一个在阴影部分的点a,Ba击中X,所以X被B膨胀的结果就是那个阴影部分。阴影部分包括X的所有范围,就像X膨胀了一圈似的。
# =============================图像膨胀============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('./image/morphology.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#kernel = np.ones((3,),np.uint8)
# kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
# kernel = np.ones((5,5),np.uint8)
# kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (7,7))
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
dilation = cv2.dilate(img,kernel,iterations = 1)
plt.subplot(121),plt.imshow(img),plt.title('opening')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dilation),plt.title('dilation')
plt.xticks([]), plt.yticks([])
plt.show()
4.3 开运算
开运算 = 先腐蚀运算,再膨胀运算(看上去把细微连在一起的两块目标分开了),开运算的效果图如下所示:
开运算总结:
- 开运算能够去除孤立的小点,毛刺和小桥,而总的位置和形状不变。
- 开运算是一个基于几何运算的滤波器。
- 结构元素大小的不同将导致滤波效果的不同。
- 不同的结构元素的选择导致了不同的分割,即提取出不同的特征。
# =============================开运算(去除噪音)============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('./image/open.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#kernel = np.ones((5,5),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
opening = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(opening),plt.title('opening')
plt.xticks([]), plt.yticks([])
plt.show()
可以看到,噪声被去掉了
4.4 闭运算
闭运算 = 先膨胀运算,再腐蚀运算(看上去将两个细微连接的图块封闭在一起),闭运算的效果图如图所示:
# =============================开运算(去除噪音)============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('./image/close.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#kernel = np.ones((5,5),np.uint8)
kernel = np.ones((7,7),np.uint8)
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(closing),plt.title('closing')
plt.xticks([]), plt.yticks([])
plt.show()
闭运算总结:
- 闭运算能够填平小孔,弥合小裂缝,而总的位置和形状不变。
- 闭运算是通过填充图像的凹角来滤波图像的。
- 结构元素大小的不同将导致滤波效果的不同。
- 不同结构元素的选择导致了不同的分割。
4.5 形态学梯度
形态学梯度:
- 基础梯度:基础梯度时用膨胀后的图像减去腐蚀后的图像得到差值图像,也是opencv中支持的计算形态学梯度的方法,而此方法得到梯度有称为基本梯度。
- 内部梯度:是用原图像减去腐蚀后的图像得到差值图像,称为图像的内部梯度。
- 外部梯度:图像膨胀后再减去原来的图像得到的差值图像,称为图像的外部梯度。
# =============================形态学梯度============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('./image/morphology.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
kernel = np.ones((3,3),np.uint8)
gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(gradient),plt.title('gradient')
plt.xticks([]), plt.yticks([])
plt.show()
4.6 顶帽和黑帽
顶帽(Top Hat):原图像与开运算图的差值,突出原图像中比周围亮的区域。
黑帽(Black Hat):闭操作图像与原图像的差值,突出原图像比周围暗的区域。
顶帽代码:
# =============================顶帽============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('./image/morphology.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
kernel = np.ones((9, 9), np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(tophat), plt.title('tophat')
plt.xticks([]), plt.yticks([])
plt.show()
黑帽代码:
# =============================黑帽============================#
# flag = 0
flag = 1
if flag == 1:
img = cv2.imread('./image/morphology.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
kernel = np.ones((9,9),np.uint8)
tophat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(tophat),plt.title('tophat')
plt.xticks([]), plt.yticks([])
plt.show()
open CV 代码数据集
点击卡片关注公众号【学姐带你玩AI】
回复 “open CV”领取
最后
以上就是寂寞吐司为你收集整理的OpenCV(二)——图像基本处理1.opencv中的绘图函数2.图像的几何变换3.图像滤波与增强4.图像形态学操作的全部内容,希望文章能够帮你解决OpenCV(二)——图像基本处理1.opencv中的绘图函数2.图像的几何变换3.图像滤波与增强4.图像形态学操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复