计算机视觉之OpenCV中的图像处理1(13章-17章)
导入所需的库
import cv2
import numpy as np
import matplotlib.pyplot as plt
for i in [cv2, np]:
print(i.__name__,": ",i.__version__,sep="")
输出:
cv2.cv2: 4.2.0
numpy: 1.17.4
# 定义图像显示函数
def showImages(original, processed):
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.imshow(original)
plt.axis("off")
plt.title("Original"+": "+str(original.shape))
plt.subplot(1,2,2)
plt.imshow(processed)
plt.axis("off")
plt.axis("off")
plt.title("Processed"+": "+str(processed.shape))
plt.tight_layout()
plt.show()
13. 颜色空间转换
学习函数:cv2.cvtColor(), cv2.inRange()
13.1 转换颜色空间
OpenCV中超过有150种颜色空间转换的方法,但常用也就两种:BGR—>Gray和BGR—>HSV。常用函数就是cv2.cvtColor(input_image, flag),其中flag为转换类型:
- 对于BGR—>Gray:cv2.COLOR_BGR2GRAY
- 对于BGR—>HSV:cv2.COLOR_BGR2HSV
flags = [i for i in dir(cv2) if i.startswith("COLOR_")]
print(len(flags))
print(flags)
输出:
274
['COLOR_BAYER_BG2BGR', 'COLOR_BAYER_BG2BGRA', 'COLOR_BAYER_BG2BGR_EA', 'COLOR_BAYER_BG2BGR_VNG', 'COLOR_BAYER_BG2GRAY', 'COLOR_BAYER_BG2RGB', 'COLOR_BAYER_BG2RGBA', 'COLOR_BAYER_BG2RGB_EA', 'COLOR_BAYER_BG2RGB_VNG', 'COLOR_BAYER_GB2BGR', 'COLOR_BAYER_GB2BGRA', 'COLOR_BAYER_GB2BGR_EA', 'COLOR_BAYER_GB2BGR_VNG', 'COLOR_BAYER_GB2GRAY', 'COLOR_BAYER_GB2RGB', 'COLOR_BAYER_GB2RGBA', 'COLOR_BAYER_GB2RGB_EA', 'COLOR_BAYER_GB2RGB_VNG', 'COLOR_BAYER_GR2BGR', 'COLOR_BAYER_GR2BGRA', 'COLOR_BAYER_GR2BGR_EA', 'COLOR_BAYER_GR2BGR_VNG', 'COLOR_BAYER_GR2GRAY', 'COLOR_BAYER_GR2RGB', 'COLOR_BAYER_GR2RGBA', 'COLOR_BAYER_GR2RGB_EA', 'COLOR_BAYER_GR2RGB_VNG', 'COLOR_BAYER_RG2BGR', 'COLOR_BAYER_RG2BGRA', 'COLOR_BAYER_RG2BGR_EA', 'COLOR_BAYER_RG2BGR_VNG', 'COLOR_BAYER_RG2GRAY', 'COLOR_BAYER_RG2RGB', 'COLOR_BAYER_RG2RGBA', 'COLOR_BAYER_RG2RGB_EA', 'COLOR_BAYER_RG2RGB_VNG', 'COLOR_BGR2BGR555', 'COLOR_BGR2BGR565', 'COLOR_BGR2BGRA', 'COLOR_BGR2GRAY', 'COLOR_BGR2HLS', 'COLOR_BGR2HLS_FULL', 'COLOR_BGR2HSV', 'COLOR_BGR2HSV_FULL', 'COLOR_BGR2LAB', 'COLOR_BGR2LUV', 'COLOR_BGR2Lab', 'COLOR_BGR2Luv', 'COLOR_BGR2RGB', 'COLOR_BGR2RGBA', 'COLOR_BGR2XYZ', 'COLOR_BGR2YCR_CB', 'COLOR_BGR2YCrCb', 'COLOR_BGR2YUV', 'COLOR_BGR2YUV_I420', 'COLOR_BGR2YUV_IYUV', 'COLOR_BGR2YUV_YV12', 'COLOR_BGR5552BGR', 'COLOR_BGR5552BGRA', 'COLOR_BGR5552GRAY', 'COLOR_BGR5552RGB', 'COLOR_BGR5552RGBA', 'COLOR_BGR5652BGR', 'COLOR_BGR5652BGRA', 'COLOR_BGR5652GRAY', 'COLOR_BGR5652RGB', 'COLOR_BGR5652RGBA', 'COLOR_BGRA2BGR', 'COLOR_BGRA2BGR555', 'COLOR_BGRA2BGR565', 'COLOR_BGRA2GRAY', 'COLOR_BGRA2RGB', 'COLOR_BGRA2RGBA', 'COLOR_BGRA2YUV_I420', 'COLOR_BGRA2YUV_IYUV', 'COLOR_BGRA2YUV_YV12', 'COLOR_BayerBG2BGR', 'COLOR_BayerBG2BGRA', 'COLOR_BayerBG2BGR_EA', 'COLOR_BayerBG2BGR_VNG', 'COLOR_BayerBG2GRAY', 'COLOR_BayerBG2RGB', 'COLOR_BayerBG2RGBA', 'COLOR_BayerBG2RGB_EA', 'COLOR_BayerBG2RGB_VNG', 'COLOR_BayerGB2BGR', 'COLOR_BayerGB2BGRA', 'COLOR_BayerGB2BGR_EA', 'COLOR_BayerGB2BGR_VNG', 'COLOR_BayerGB2GRAY', 'COLOR_BayerGB2RGB', 'COLOR_BayerGB2RGBA', 'COLOR_BayerGB2RGB_EA', 'COLOR_BayerGB2RGB_VNG', 'COLOR_BayerGR2BGR', 'COLOR_BayerGR2BGRA', 'COLOR_BayerGR2BGR_EA', 'COLOR_BayerGR2BGR_VNG', 'COLOR_BayerGR2GRAY', 'COLOR_BayerGR2RGB', 'COLOR_BayerGR2RGBA', 'COLOR_BayerGR2RGB_EA', 'COLOR_BayerGR2RGB_VNG', 'COLOR_BayerRG2BGR', 'COLOR_BayerRG2BGRA', 'COLOR_BayerRG2BGR_EA', 'COLOR_BayerRG2BGR_VNG', 'COLOR_BayerRG2GRAY', 'COLOR_BayerRG2RGB', 'COLOR_BayerRG2RGBA', 'COLOR_BayerRG2RGB_EA', 'COLOR_BayerRG2RGB_VNG', 'COLOR_COLORCVT_MAX', 'COLOR_GRAY2BGR', 'COLOR_GRAY2BGR555', 'COLOR_GRAY2BGR565', 'COLOR_GRAY2BGRA', 'COLOR_GRAY2RGB', 'COLOR_GRAY2RGBA', 'COLOR_HLS2BGR', 'COLOR_HLS2BGR_FULL', 'COLOR_HLS2RGB', 'COLOR_HLS2RGB_FULL', 'COLOR_HSV2BGR', 'COLOR_HSV2BGR_FULL', 'COLOR_HSV2RGB', 'COLOR_HSV2RGB_FULL', 'COLOR_LAB2BGR', 'COLOR_LAB2LBGR', 'COLOR_LAB2LRGB', 'COLOR_LAB2RGB', 'COLOR_LBGR2LAB', 'COLOR_LBGR2LUV', 'COLOR_LBGR2Lab', 'COLOR_LBGR2Luv', 'COLOR_LRGB2LAB', 'COLOR_LRGB2LUV', 'COLOR_LRGB2Lab', 'COLOR_LRGB2Luv', 'COLOR_LUV2BGR', 'COLOR_LUV2LBGR', 'COLOR_LUV2LRGB', 'COLOR_LUV2RGB', 'COLOR_Lab2BGR', 'COLOR_Lab2LBGR', 'COLOR_Lab2LRGB', 'COLOR_Lab2RGB', 'COLOR_Luv2BGR', 'COLOR_Luv2LBGR', 'COLOR_Luv2LRGB', 'COLOR_Luv2RGB', 'COLOR_M_RGBA2RGBA', 'COLOR_RGB2BGR', 'COLOR_RGB2BGR555', 'COLOR_RGB2BGR565', 'COLOR_RGB2BGRA', 'COLOR_RGB2GRAY', 'COLOR_RGB2HLS', 'COLOR_RGB2HLS_FULL', 'COLOR_RGB2HSV', 'COLOR_RGB2HSV_FULL', 'COLOR_RGB2LAB', 'COLOR_RGB2LUV', 'COLOR_RGB2Lab', 'COLOR_RGB2Luv', 'COLOR_RGB2RGBA', 'COLOR_RGB2XYZ', 'COLOR_RGB2YCR_CB', 'COLOR_RGB2YCrCb', 'COLOR_RGB2YUV', 'COLOR_RGB2YUV_I420', 'COLOR_RGB2YUV_IYUV', 'COLOR_RGB2YUV_YV12', 'COLOR_RGBA2BGR', 'COLOR_RGBA2BGR555', 'COLOR_RGBA2BGR565', 'COLOR_RGBA2BGRA', 'COLOR_RGBA2GRAY', 'COLOR_RGBA2M_RGBA', 'COLOR_RGBA2RGB', 'COLOR_RGBA2YUV_I420', 'COLOR_RGBA2YUV_IYUV', 'COLOR_RGBA2YUV_YV12', 'COLOR_RGBA2mRGBA', 'COLOR_XYZ2BGR', 'COLOR_XYZ2RGB', 'COLOR_YCR_CB2BGR', 'COLOR_YCR_CB2RGB', 'COLOR_YCrCb2BGR', 'COLOR_YCrCb2RGB', 'COLOR_YUV2BGR', 'COLOR_YUV2BGRA_I420', 'COLOR_YUV2BGRA_IYUV', 'COLOR_YUV2BGRA_NV12', 'COLOR_YUV2BGRA_NV21', 'COLOR_YUV2BGRA_UYNV', 'COLOR_YUV2BGRA_UYVY', 'COLOR_YUV2BGRA_Y422', 'COLOR_YUV2BGRA_YUNV', 'COLOR_YUV2BGRA_YUY2', 'COLOR_YUV2BGRA_YUYV', 'COLOR_YUV2BGRA_YV12', 'COLOR_YUV2BGRA_YVYU', 'COLOR_YUV2BGR_I420', 'COLOR_YUV2BGR_IYUV', 'COLOR_YUV2BGR_NV12', 'COLOR_YUV2BGR_NV21', 'COLOR_YUV2BGR_UYNV', 'COLOR_YUV2BGR_UYVY', 'COLOR_YUV2BGR_Y422', 'COLOR_YUV2BGR_YUNV', 'COLOR_YUV2BGR_YUY2', 'COLOR_YUV2BGR_YUYV', 'COLOR_YUV2BGR_YV12', 'COLOR_YUV2BGR_YVYU', 'COLOR_YUV2GRAY_420', 'COLOR_YUV2GRAY_I420', 'COLOR_YUV2GRAY_IYUV', 'COLOR_YUV2GRAY_NV12', 'COLOR_YUV2GRAY_NV21', 'COLOR_YUV2GRAY_UYNV', 'COLOR_YUV2GRAY_UYVY', 'COLOR_YUV2GRAY_Y422', 'COLOR_YUV2GRAY_YUNV', 'COLOR_YUV2GRAY_YUY2', 'COLOR_YUV2GRAY_YUYV', 'COLOR_YUV2GRAY_YV12', 'COLOR_YUV2GRAY_YVYU', 'COLOR_YUV2RGB', 'COLOR_YUV2RGBA_I420', 'COLOR_YUV2RGBA_IYUV', 'COLOR_YUV2RGBA_NV12', 'COLOR_YUV2RGBA_NV21', 'COLOR_YUV2RGBA_UYNV', 'COLOR_YUV2RGBA_UYVY', 'COLOR_YUV2RGBA_Y422', 'COLOR_YUV2RGBA_YUNV', 'COLOR_YUV2RGBA_YUY2', 'COLOR_YUV2RGBA_YUYV', 'COLOR_YUV2RGBA_YV12', 'COLOR_YUV2RGBA_YVYU', 'COLOR_YUV2RGB_I420', 'COLOR_YUV2RGB_IYUV', 'COLOR_YUV2RGB_NV12', 'COLOR_YUV2RGB_NV21', 'COLOR_YUV2RGB_UYNV', 'COLOR_YUV2RGB_UYVY', 'COLOR_YUV2RGB_Y422', 'COLOR_YUV2RGB_YUNV', 'COLOR_YUV2RGB_YUY2', 'COLOR_YUV2RGB_YUYV', 'COLOR_YUV2RGB_YV12', 'COLOR_YUV2RGB_YVYU', 'COLOR_YUV420P2BGR', 'COLOR_YUV420P2BGRA', 'COLOR_YUV420P2GRAY', 'COLOR_YUV420P2RGB', 'COLOR_YUV420P2RGBA', 'COLOR_YUV420SP2BGR', 'COLOR_YUV420SP2BGRA', 'COLOR_YUV420SP2GRAY', 'COLOR_YUV420SP2RGB', 'COLOR_YUV420SP2RGBA', 'COLOR_YUV420p2BGR', 'COLOR_YUV420p2BGRA', 'COLOR_YUV420p2GRAY', 'COLOR_YUV420p2RGB', 'COLOR_YUV420p2RGBA', 'COLOR_YUV420sp2BGR', 'COLOR_YUV420sp2BGRA', 'COLOR_YUV420sp2GRAY', 'COLOR_YUV420sp2RGB', 'COLOR_YUV420sp2RGBA', 'COLOR_mRGBA2RGBA']
13.2 物体跟踪
在HSV颜色空间中要比在BGR空间中更容易表示一个特定颜色。
cap = cv2.VideoCapture(0)
while(True):
ret, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
mask = cv2.inRange(hsv, lower_blue, upper_blue)
res = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow(frame)
cv2.imshow(mask)
cv2.imshow(res)
k = cv2.waitKey(5)
if k == 27:
break
cv2.destroyAllWindows()
输出:
13.3 如何找到跟踪对象的HSV值?
green = np.uint8([[[0,255,0]]])
hsv_green = cv2.cvtColor(green, cv2.COLOR_BGR2HSV)
print(hsv_green)
输出:
[[[ 60 255 255]]]
14. 几何变换
学习函数cv2.getPerspectiveTransform。
OpenCV提供了两个变换函数:cv2.warpAffine和cv2.warpPerspective,前者接收23的变换矩阵,后者接收33的变换矩阵。
14.1 扩展缩放
扩展缩放就是改变图像的尺寸大小,OpenCV中用cv2.resize()实现这个功能。不同的插值方法:
- 缩放时推荐使用cv2.INTER_AREA
- 扩展时推荐使用cv2.INTER_CUBIC和cv2.INTER_LINEAR。
- 默认情况下所有改变图像大小的操作都使用cv2.INTER_LINEAR
img = cv2.imread("messi5.jpg")
res = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC) # 使用缩放因子
height, width = img.shape[:2]
res2 = cv2.resize(img,(2*width,2*height), interpolation=cv2.INTER_CUBIC)# 直接给出尺寸
showImages(img, res)
showImages(img, res2)
输出:
14.2 平移
如果将图像沿(x,y)方向移动(tx,ty),则可按下式构建移动矩阵:
rows, cols, ch = img.shape
M = np.float32([[1,0,100],[0,1,50]]) # 创建M矩阵,向X方向移动100,Y方向移动50
dst = cv2.warpAffine(img, M, (cols, rows)) # 第三参数代表输出图像的尺寸
showImages(img, dst)
输出:
14.3 旋转
OpenCV允许你在任意地方进行旋转,旋转矩阵为:
# 参数1:旋转中心,参数2:旋转角度,参数3:旋转后缩放因子
M1 = cv2.getRotationMatrix2D(((cols-1)/2.0, (rows-1)/2.0),90,1)
M2 = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1)
dst1 = cv2.warpAffine(img, M1, (cols, rows))
dst2 = cv2.warpAffine(img, M2, (cols, rows))
showImages(img, dst1)
showImages(img, dst2)
输出:
14.4 仿射变换
仿射变换中原图中平行的线结果中同样平行。cv2.getAffineTransform会创建一个2*3的变换矩阵,需要传入:原图中三个点位置、以及这三个点在结果图像中的位置。
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1, pts2)
dst = cv2.warpAffine(img, M, (cols, rows))
showImages(img, dst)
输出:
14.5 透视变换
cv2.getPerspectiveTransform()构建变换矩阵,需要传入原图中4个点的位置以及这4个点在输出图像对应的位置。
pts_ori = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts_des = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv2.getPerspectiveTransform(pts_ori, pts_des)
dst = cv2.warpPerspective(img, M, (cols,rows))
showImages(img, dst)
输出:
15. 图像阈值
学习函数:cv2.threshold, cv2.adaptiveThreshold
15.1 简单阈值
当像素高于阈值时,赋予像素一个新值,否则赋予另外一个值。OpenCV中cv2.threshold()完成这个功能,参数1原图像,参数2阈值,参数3新值,参数4不同的阈值方法,包括:
- cv2.THRESH_BINARY
- cv2.THRESH_BINARY_INV
- cv2.THRESH_TRUNC
- cv2.THRESH_TOZERO
- cv2.THRESH_TOZERO_INV
img = cv2.imread("messi5.jpg",0)
ret1, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret2, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret3, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret4, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret5, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
ret6, thresh6 = cv2.threshold(img, 127, 255, cv2.THRESH_TRIANGLE)
showImages(img, thresh1)
showImages(img, thresh2)
showImages(img, thresh3)
showImages(img, thresh4)
showImages(img, thresh5)
showImages(img, thresh6)
输出:
15.2 自适应阈值
上面使用的是全局阈值,整幅图像采用同一个数作为阈值。但大部分情况下,图像不同部分可能具有不同的亮度,这种情况下自适应阈值就显得非常有用。自适应具体做法是根据图像上的每一个小区域计算与其对应的阈值,因此同一图像不同区域采用的是不同的阈值。
OpenCV中cv2.adaptiveThreshold()函数提供自适应计算,参数:
-
Adaptive Method:指定计算机阈值的方法:
- cv2.ADAPTIVE_THRESH_MEAN_C:相邻区域内平均值减去常数C
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C:相邻值的高斯加权和减去常数C
- Block Size:邻域大小
img = cv2.medianBlur(img, 5) # 中值滤波
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 11, 2) # 11为block size,2为常数C
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2) # 11为block size,2为常数C
for th in [th1,th2,th3]:
showImages(img, th)
输出:
15.3 Otsu's二值化
对于双峰图,单纯给定一个数值做阈值进行二值化处理是不科学的。Otsu's二值化就是针对双峰图自动计算出一个阈值。cv2.threshold()函数进行Otu's二值化需要多传入一个参数,即cv2.THRESH_OTSU,阈值设为0,返回值为找到的最优阈值。(注意:如果不使用Otsu二值化,返回的retVal就是设定的阈值。)
ret1, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
blur = cv2.GaussianBlur(img,(5,5),0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
for th in [th1, th2, th3]:
showImages(img, th)
输出:
16. 图像平滑
OpenCV提供函数cv2.filter2D()可以对图像进行卷积操作。
16.1 2D卷积
img = cv2.imread("3.jpg")
kernel = np.ones((5,5),np.float32)/25
dst = cv2.filter2D(img, -1, kernel)
showImages(img, dst)
输出:
很明显,经过上述2D卷积处理过后图像变得模糊。
图像模糊(图像平滑):使用低通滤波器可以达到图像模糊的目的。其实就是去除图像中的高频成分,所以边界也变得有些模糊。OpenCV中提供了四种模糊技术:平均模糊、高斯模糊、中值模糊、双边滤波。
16.2 平均模糊
使用cv2.blur()和cv2.boxFilter()来完成平均模糊。cv2.blur()需传入归一化的卷积框参数,cv2.boxFilter()需传入normalize=False参数
blur = cv2.blur(img,(5,5))
boxFilter = cv2.boxFilter(img, -1, (5,5), normalize=False)
showImages(img, blur)
showImages(img, boxFilter)
输出:
16.3 高斯模糊
高斯核:方框大小不变,里面的值符合高斯分布,中心值最大,边缘值越小,最终求加权平均。
OpenCV中提供cv2.GaussianBlur()函数完成高斯模糊,需要指定高斯核的宽和高(要求都为奇数)、沿X和Y方向的标准差。如果只指定一个数,则X和Y取相同的标准差,如果为0,则函数自动计算标准差。
也可使用cv2.getGaussianKernel()构建一个高斯核。
Gaussian_blur= cv2.GaussianBlur(img, (5,5), 0)
showImages(img, Gaussian_blur)
输出:
16.4 中值模糊
用卷积核中像素值的中值来替代中心像素的值,经常用于去除椒盐噪声。
OpenCV中提供cv2.medianBlur()完成中值模糊。
median_blur = cv2.medianBlur(img, 5)
img_saltNoise = img.
showImages(img, median_blur)
输出:
16.5 双边滤波
双边滤波能在保持边界清晰的情况下有效去除噪音。双边滤波同时考虑空间高斯权重和灰度值相似性高斯权重。
OpenCV提供cv2.bilateralFilter()实现双边滤波。
bilater_blur = cv2.bilateralFilter(img, 9, 75, 75)
showImages(img, bilater_blur)
输出:
17. 形态学转换
形态学操作:腐蚀、膨胀、开运算、闭运算。形态学操作是根据图像形状进行的简单操作。
学习函数:cv2.erode(), cv2.dilate(), cv2.morphologyEx()
17.1 腐蚀
img = cv2.imread("4.jpg")
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
showImages(img, erosion)
输出:
17.2 膨胀
dilation = cv2.dilate(img, kernel, iterations=1)
showImages(img, dilation)
输出:
17.3 开运算
先进行腐蚀再进行膨胀叫做开运算。
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
showImages(img, opening)
输出:
17.4 闭运算
先膨胀再腐蚀叫做闭运算。经常用于填充前景物体中的小洞,或是前景物体上的小黑点。
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
showImages(img, closing)
输出:
17.5 形态学梯度
就是图像膨胀与腐蚀的差别,结果像是前景物体的轮廓。
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
showImages(img, gradient)
输出:
17.6 礼帽
就是原始图像与开运算图像的差。
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
showImages(img ,tophat)
输出:
17.7 黑帽
就是闭运算后和图像与原图的差。
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
showImages(img, blackhat)
输出:
17.8 结构化元素
上述例子中使用了NumPy构建核,都是方形的。OpenCV提供cv2.getStructuringElement()函数,可以完成圆形等核的构建。
方形核:
cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
输出:
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]], dtype=uint8)
椭圆形核:
cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
输出:
array([[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0]], dtype=uint8)
十字形核:
cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
输出:
array([[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]], dtype=uint8)