计算机视觉之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为转换类型:

  1. 对于BGR—>Gray:cv2.COLOR_BGR2GRAY
  2. 对于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()实现这个功能。不同的插值方法:

  1. 缩放时推荐使用cv2.INTER_AREA
  2. 扩展时推荐使用cv2.INTER_CUBIC和cv2.INTER_LINEAR。
  3. 默认情况下所有改变图像大小的操作都使用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)

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值