前言:总纲请看《计算机视觉学习路》
概念
- 基于图像形态学进行处理的一些基本方法
- 这些处理方法基本是对二进制图像进行处理
- 卷积核决定着图像处理后的效果
二值化
将图像的每个像素变成两种值,如0,255
分为全局二值化和局部二值化
全局二值化:
threshold(img , thresh , maxVal , type)
img : 图像,最好是灰度图
thresh : 阈值
maxVal : 高于阈值,像素值替换成maxval
type: THRESH_BINARY:低于阈值像素值为0,高于阈值像素值为maxVal
THRESH_BINARY_INV:相反,低于阈值是maxVal,高于阈值是0
THRESH_TOZERO :高于阈值的部分不变,其他地方设为0
THRESH_TOZERO_INV :低于阈值的部分不变,其他地方设为0
THRESH_TRUNC : 高于阈值的部分令其等于阈值,其余不变
注:蓝色的这三个选项不是二值化的内容,用的也不多,了解即可
代码如下:
import cv2
im = cv2.imread('../img/lena.jpg')
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # 转为灰度图
cv2.imshow('im', im)
# 二值化 返回阈值和二值化后的图像
t, im_bin = cv2.threshold(im,
127, 255, # 阈值和最大值 阈值越高白色的部分越少
cv2.THRESH_BINARY) # 二值化选项
cv2.imshow('im_bin', im_bin)
# 反二值化 小于阈值部分设置为255
t, im_bin_inv = cv2.threshold(im,
127, 255, # 阈值和最大值 阈值越高白色的部分越少
cv2.THRESH_BINARY_INV) # 反二值化选项
cv2.imshow('im_bin_inv', im_bin_inv)
cv2.waitKey()
cv2.destroyAllWindows()
自适应阈值
由于光照不均,二值化会出现下面的情况:
所以采用自适应阈值
adaptiveThreshold(img , maxVal , adaptiveMethod, Type , blockSize , C)
dadptiveMethod : 计算阈值的方法,有如下选项:
ADAPTIVE_THRESH_MEAN_C : 计算临近区域的平均值
ADAPTIVE_THRESH_GAUSSIAN_C : 高斯窗口加权平均值,中间权值高,常用
Type : THRESH_BINARY 和 THRESH_BINARY_INV
blockSize : 临近区域的大小
C : 常量,应从计算出的平均值或加权平均值中减去,一般=0
import cv2
im = cv2.imread('../img/自适应.png')
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # 转为灰度图
cv2.imshow('im', im)
# 二值化 返回阈值和二值化后的图像
im_bin = cv2.adaptiveThreshold(im,
255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, # 高斯
cv2.THRESH_BINARY, # type
3,0) # 块大小为3*3 C=0
cv2.imshow('im_bin', im_bin)
im_bin_inv = cv2.adaptiveThreshold(im,
255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, # 高斯
cv2.THRESH_BINARY_INV, # type
3,0) # 块大小为3*3 C=0
cv2.imshow('im_bin_inv', im_bin_inv)
cv2.waitKey()
cv2.destroyAllWindows()
腐蚀
cv2.erode(img, kernel, iterations=1)
kernel:腐蚀核,一般情况下是全1的矩阵
iterations : 迭代次数,值越大,腐蚀的越厉害
import cv2
import numpy as np
img = cv2.imread('../img/5.png')
cv2.imshow('img', img)
# 腐蚀
kernel = np.ones((3, 3), np.uint8) # 腐蚀核
im_erode = cv2.erode(img, kernel, iterations=2) # 迭代次数
cv2.imshow('im_erode', im_erode)
cv2.waitKey()
cv2.destroyAllWindows()
获得卷积核
通常都是全1卷积核,也可以通过API获得其他腐蚀核
getStructuringDlement(type , size)
type:MORPH_RECT : 全1卷积核
MORPH_ELLIPSE : 椭圆形1分布,图片见下方
MORPH_CROSS 十字形1分布
size : (3,3) (5,5)...
import cv2
import numpy as np
img = cv2.imread('../img/5.png')
cv2.imshow('img', img)
# 腐蚀
kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
print(kernel1)
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
print(kernel2)
kernel3 = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
print(kernel3)
im1 = cv2.erode(img, kernel1, iterations=2) # 迭代次数
im2 = cv2.erode(img, kernel2, iterations=2) # 迭代次数
im3 = cv2.erode(img, kernel3, iterations=2) # 迭代次数
cv2.imshow('RECT', im1)
cv2.imshow('ELLIPSE', im2)
cv2.imshow('CROSS', im3)
cv2.waitKey()
cv2.destroyAllWindows()
膨胀
dilate(img , kernel , iterations = 1)
下图是iteration分别为10,20,50的结果
import cv2
import numpy as np
img = cv2.imread('../img/7.png')
cv2.imshow('img', img)
# 腐蚀
kernel = np.ones((3, 3), np.uint8) # 膨胀核
img1 = cv2.dilate(img, kernel, iterations=10) # 迭代次数
img2 = cv2.dilate(img, kernel, iterations=20) # 迭代次数
img3 = cv2.dilate(img, kernel, iterations=50) # 迭代次数
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
cv2.waitKey()
cv2.destroyAllWindows()
获得卷积核
同腐蚀
import cv2
import numpy as np
img = cv2.imread('../img/7.png')
cv2.imshow('img', img)
# 膨胀
kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
kernel3 = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
im1 = cv2.dilate(img, kernel1, iterations=2) # 迭代次数
im2 = cv2.dilate(img, kernel2, iterations=2) # 迭代次数
im3 = cv2.dilate(img, kernel3, iterations=2) # 迭代次数
cv2.imshow('RECT', im1)
cv2.imshow('ELLIPSE', im2)
cv2.imshow('CROSS', im3)
cv2.waitKey()
cv2.destroyAllWindows()
开运算
开运算= 腐蚀+膨胀
morphologyEx(img , MORPH_OPEN , kernel)
# 先腐蚀,后膨胀
import cv2
import numpy as np
# 读取原图
im1 = cv2.imread('../img/7.png')
im2 = cv2.imread('../img/8.png')
# 开运算
k = np.ones((10, 10), np.uint8) # 计算核的类型uint8
# k = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) # 获取卷积核
r1 = cv2.morphologyEx(im1, cv2.MORPH_OPEN, k)
r2 = cv2.morphologyEx(im2, cv2.MORPH_OPEN, k)
cv2.imshow('im1', im1)
cv2.imshow('r1', r1)
cv2.imshow('im2', im2)
cv2.imshow('r2', r2)
cv2.waitKey()
cv2.destroyAllWindows()
获取卷积核同上,这里不再演示
闭运算
闭运算=膨胀+腐蚀
morphologyEx(img , MORPH_CLOSE , kernel)
# 先腐蚀,后膨胀
import cv2
import numpy as np
# 读取原图
im = cv2.imread('../img/9.png')
# 闭运算
k = np.ones((10, 10), np.uint8) # 计算核的类型uint8
# k = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) # 获取卷积核
r1 = cv2.morphologyEx(im, cv2.MORPH_CLOSE, k)
cv2.imshow('im', im)
cv2.imshow('r1', r1)
cv2.waitKey()
cv2.destroyAllWindows()
形态学梯度
梯度= 原图-腐蚀后的图 = 边沿
morphologyEx(img , MORPH_GRADIENT , kernel)
下面是kernel size = 3*3 和 7*7的梯度
可以看出,梯度的大小和卷积核的大小有很大的关系
# 先腐蚀,后膨胀
import cv2
import numpy as np
# 读取原图
im = cv2.imread('../img/2.png')
# 闭运算
# k = np.ones((10, 10), np.uint8) # 计算核的类型uint8
k = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3)) # 获取卷积核
k2 = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7)) # 获取卷积核
r1 = cv2.morphologyEx(im, cv2.MORPH_GRADIENT, k)
r2 = cv2.morphologyEx(im, cv2.MORPH_GRADIENT, k2)
cv2.imshow('im', im)
cv2.imshow('r1', r1)
cv2.imshow('r2', r2)
cv2.waitKey()
cv2.destroyAllWindows()
顶帽运算
顶帽 = 原图 - 开运算
morphologyEx(img , MORPH_TOPHAT , kernel)
去掉大的部分,留下小的部分(外部噪点),下图kernel size分别为 3*3 7*7
kernel size越大,留下的越多
# 先腐蚀,后膨胀
import cv2
import numpy as np
# 读取原图
im = cv2.imread('../img/5.png')
# 闭运算
# k = np.ones((10, 10), np.uint8) # 计算核的类型uint8
k = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3)) # 获取卷积核
k2 = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7)) # 获取卷积核
r1 = cv2.morphologyEx(im, cv2.MORPH_TOPHAT, k)
r2 = cv2.morphologyEx(im, cv2.MORPH_TOPHAT, k2)
cv2.imshow('im', im)
cv2.imshow('r1', r1)
cv2.imshow('r2', r2)
cv2.waitKey()
cv2.destroyAllWindows()
黑帽运算
黑帽 = 原图- 闭运算
morphologyEx(img , MORPH_BLACKHAT , kernel)
取出大块中的小噪点(内部)
# 先腐蚀,后膨胀
import cv2
import numpy as np
# 读取原图
im = cv2.imread('../img/9.png')
# k = np.ones((10, 10), np.uint8) # 计算核的类型uint8
k = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3)) # 获取卷积核
k2 = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7)) # 获取卷积核
r1 = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, k)
r2 = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, k2)
cv2.imshow('im', im)
cv2.imshow('r1', r1)
cv2.imshow('r2', r2)
cv2.waitKey()
cv2.destroyAllWindows()