图像阈值

图像的每一个像素点的 RGB 值都是 0~255 之间的一个数字,我们可以设定一个阈值,当RGB 值大于(小于)这个数就分别进行相应的处理。

ret, dst = cv2.threshold(src, thresh, maxval, type)
  • src:输入图,通常来说为单通道的灰度图
  • dst:输出图
  • thresh:阈值
  • maxval:当像素值超过了阈值(或者小于阈值,根据 type 来决定),所赋予的值
  • type:二值化操作的类型,包含以下5种类型:
    • cv2.THRESH_BINARY:超过阈值部分取maxval(最大值),否则取 0
    • cv2.THRESH_BINARY_INV:THRESH_BINARY 的反转
    • cv2.THRESH_TRUNC:大于阈值部分设为阈值,否则不变
    • cv2.THRESH_TOZERO:大于阈值部分不改变,否则取 0
    • cv2.THRESH_TOZERO_INV:THRESH_TOZERO的反转

例:

sky = cv2.imread('media/sky.jpg', cv2.IMREAD_GRAYSCALE)

ret, thresh1 = cv2.threshold(sky, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(sky, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(sky, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(sky, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(sky, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [sky, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

图像平滑

也称滤波。
如图,这张图片上有很多噪音点,图像平滑的目标就是消除这些噪音点。

均值滤波

也称模糊,就是简单的平均卷积操作。

关于 卷积 可以参阅 理解图像卷积操作的意义_zxucver_CSDN

blur = cv2.blur(img, (3, 3))

(3, 3) 是规定的 卷积核 大小。

  • 橙色区域就是卷积核。

方框滤波

基本和均值滤波相同,可以选择是否归一化。

box = cv2.boxFilter(img, -1, (3, 3), normalize=False)

如果不归一化,RGB 值很容易越界,就会取 255,图片就会很白。

高斯滤波

离卷积核中心最近,权值越大。比如:

gaussian = cv2.GaussianBlur(img, (5, 5), 1)  

中值滤波

用卷积核的中值代替。

median = cv2.medianBlur(img, 5)

对比展示

import numpy as np
res = np.hstack((blur, gaussian, median))
cv_show('blur, gaussian, median', res)

可以看到中值滤波是效果最好的。


形态学运算

从上到下分别是:

  1. 腐蚀
  2. 膨胀
  3. 开运算
  4. 闭运算
  5. 梯度运算
  6. 礼帽(顶帽)
  7. 黑帽
  8. 击中击不中

腐蚀

正如 “腐蚀” 的含义,图像腐蚀就是把图像(通常是二值图像)中的一部分黑色或白色区域缩减细化。

img = cv2.imread('media/dige.png')
kernel = np.ones((3, 3), np.uint8)

erosion_1 = cv2.erode(img, kernel, iterations=1)
erosion_2 = cv2.erode(img, kernel, iterations=2)
res = np.hstack((img, erosion_1, erosion_2))
cv_show('img, erosion_1, erosion_2', res)
pie = cv2.imread('media/pie.png')

kernel = np.ones((30, 30), np.uint8)

erosion_1 = cv2.erode(pie, kernel, iterations=1)
erosion_2 = cv2.erode(pie, kernel, iterations=2)
res = np.hstack((pie, erosion_1, erosion_2))
cv_show('pie, erosion_1, erosion_2', res)

膨胀

膨胀就是和腐蚀相反。

img = cv2.imread('media/dige.png')
kernel = np.ones((3, 3), np.uint8)

dige_erosion = cv2.erode(img, kernel, iterations=1)
dige_dilate_1 = cv2.dilate(dige_erosion, kernel, iterations=1)
dige_dilate_2 = cv2.dilate(dige_erosion, kernel, iterations=2)

res = np.hstack((dige_erosion, dige_dilate_1, dige_dilate_2))
cv_show('dige_erosion, dige_dilate_1, dige_dilate_2', res)
pie = cv2.imread('media/pie.png')
kernel = np.ones((30, 30), np.uint8)

dilate_1 = cv2.dilate(pie, kernel, iterations=1)
dilate_2 = cv2.dilate(pie, kernel, iterations=2)

res = np.hstack((pie, dilate_1, dilate_2))
cv_show('pie, dilate_1, dilate_2', res)

开运算与闭运算

开运算:先腐蚀再膨胀。

img = cv2.imread('media/dige.png')
kernel = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv_show('opening', opening)

闭运算:先膨胀再腐蚀。

img = cv2.imread('media/dige.png')
kernel = np.ones((5, 5), np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv_show('opening', closing)

梯度运算

梯度运算 = 膨胀 - 腐蚀

pie = cv2.imread('media/pie.png')
kernel = np.ones((7, 7), np.uint8)
dilate = cv2.dilate(pie, kernel, iterations=2)
erosion = cv2.erode(pie, kernel, iterations=2)

res = np.hstack((dilate, erosion))
cv_show('res', res)
pie = cv2.imread('media/pie.png')
kernel = np.ones((5, 5), np.uint8)
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
cv_show('gradient', gradient)

礼帽与黑帽

礼帽 = 原始 - 开运算

img = cv2.imread('media/dige.png')
kernel = np.ones((3, 3), np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv_show('tophat', tophat)

黑帽 = 闭运算 - 原始

img = cv2.imread('media/dige.png')
kernel = np.ones((7, 7), np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv_show('tophat', tophat)