文章目录
- 前言
- 一、边界填充
- 二、图像融合
- 三、图像阈值
- 四、图像平滑
- 1、均值滤波
- 2、方框滤波
- 3、高斯滤波
- 4、中值滤波
- 五、形态学
- 1、腐蚀
- 2、膨胀
- 3、开运算 & 闭运算
- 4、梯度运算
- 5、礼帽 & 黑帽
- 六、图像梯度
- 1、Sobel算子
- 2、Scharr 算子 & Lablacian 算子
- 七、Canny 边缘检测
前言
本文为11月3日 OpenCV 实战基础学习笔记——图像基本处理,分为七个章节:
- 边界填充;
- 图像融合;
- 图像阈值;
- 图像平滑;
- 形态学;
- 图像梯度;
- Canny 边缘检测。
一、边界填充
- BORDER_REPLICATE:复制法:复制最边缘像素;
- BORDER_REFLECT:反射法,使像素在两边进行复制;
- BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称;
- BORDER_WRAP:外包装法;
- BORDER_CONSTANT:常量法,常数值填充。
top_size, bottom_size, left_size, right_size = (50, 50, 50, 50)
replicate = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv.BORDER_WRAP)
constant = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv.BORDER_CONSTANT, value=0)
plt.subplot(231), plt.imshow(img, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
plt.show()
二、图像融合
cat.shape
>>> (414, 500, 3)
dog.shape
>>> (429, 499, 3)
dog = cv.resize(dog, (500, 414))
dog.shape
>>> (414, 500, 3)
res = cv.addWeighted(cat, 0.4, dog, 0.6, 0) # \alpha=0.4, \beta=0.6
plt.imshow(res)
三、图像阈值
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的反转。
ret, thresh1 = cv.threshold(img_gray, 127, 255, cv.THRESH_BINARY)
ret, thresh2 = cv.threshold(img_gray, 127, 255, cv.THRESH_BINARY_INV)
ret, thresh3 = cv.threshold(img_gray, 127, 255, cv.THRESH_TRUNC)
ret, thresh4 = cv.threshold(img_gray, 127, 255, cv.THRESH_TOZERO)
ret, thresh5 = cv.threshold(img_gray, 127, 255, cv.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2, 3, i+1)
plt.imshow(images[i], cmap='gray')
plt.title(titles[i])
plt.xticks([])
plt.yticks([])
plt.show()
四、图像平滑
img = cv.imread('lenaNoise.png')
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img)
1、均值滤波
平均卷积操作。
# 均值滤波:平均卷积操作
blur = cv.blur(img, (3, 3))
cv_show('blur', blur)
2、方框滤波
基本和均值一样,可以选择归一化,容易越界。
box = cv.boxFilter(img, -1, (3, 3), normalize=True)
cv_show('box', box)
3、高斯滤波
卷积核中的数值满足高斯分布,相当于更重视中间的。
gaussian = cv.GaussianBlur(img, (5, 5), 1)
cv_show('gaussian', gaussian)
4、中值滤波
相当于用中值代替。
medium = cv.medianBlur(img, 5)
cv_show('medium', medium)
五、形态学
img = cv.imread('dige.png')
cv_show('img', img)
1、腐蚀
kernel = np.ones((5, 5), np.uint8)
erosion = cv.erode(img, kernel, iterations=1)
cv_show('erosion', erosion)
2、膨胀
kernel = np.ones((3, 3), np.uint8)
dige_dilate = cv.dilate(erosion, kernel, iterations=1)
cv_show('dilate', dige_dilate)
3、开运算 & 闭运算
- 开运算:先腐蚀,再膨胀;
kernel = np.ones((5, 5), np.uint8)
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
cv_show("opening", opening)
- 闭运算:先膨胀,再腐蚀。
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
cv_show("closing", closing)
4、梯度运算
梯度 = 膨胀 - 腐蚀。
pie = cv.imread('pie.png')
kernel = np.ones((7, 7), np.uint8)
dilate = cv.dilate(pie, kernel, iterations=5)
erosion = cv.erode(pie, kernel, iterations=5)
res = np.hstack((dilate, erosion))
cv_show('res', res)
gradient = cv.morphologyEx(pie, cv.MORPH_GRADIENT, kernel)
cv_show('gradient', gradient)
5、礼帽 & 黑帽
- 礼帽:原始输入 - 开运算结果;
img = cv.imread('dige.png')
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
cv_show('tophat', tophat)
- 黑帽:闭运算 - 原始输入。
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
cv_show('blackhat', blackhat)
六、图像梯度
1、Sobel算子
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
- ddepth:图像的深度;
- dx和dy分别表示水平和竖直方向;
- ksize是Sobel算子的大小.
pie_sobel_x = cv.Sobel(pie, cv.CV_64F, 1, 0, ksize=3) # 1, 0: 只算水平方向
cv_show('pie_sobel_x', pie_sobel_x)
# 白到黑是正数,黑到白是负数,所有的负数会被截断成 0,所以要取绝对值
pie_sobel_x = cv.convertScaleAbs(pie_sobel_x)
cv_show('pie_sobel_x', pie_sobel_x)
# 分别计算 G_x 和 G_y,再求和
pie_sobel_y = cv.Sobel(pie, cv.CV_64F, 0, 1, ksize=3) # 0, 1: 只算竖直方向
pie_sobel_y = cv.convertScaleAbs(pie_sobel_y)
cv_show('pie_sobel_y', pie_sobel_y)
pie_sobel_xy = cv.addWeighted(pie_sobel_x, 0.5, pie_sobel_y, 0.5, 0)
cv_show('pie_sobel_xy', pie_sobel_xy)
# 不建议直接计算,会有重影
pie_sobel_xy_2 = cv.Sobel(pie, cv.CV_64F, 1, 1, ksize=3)
pie_sobel_xy_2 = cv.convertScaleAbs(pie_sobel_xy_2)
cv_show('pie_sobel_xy_2', pie_sobel_xy_2)
lena = cv.imread('lena.jpg', cv.IMREAD_GRAYSCALE)
cv_show('lena', lena)
lena_sobel_x = cv.Sobel(lena, cv.CV_64F, 1, 0, ksize=3)
lena_sobel_x = cv.convertScaleAbs(lena_sobel_x)
lena_sobel_y = cv.Sobel(lena, cv.CV_64F, 0, 1, ksize=3)
lena_sobel_y = cv.convertScaleAbs(lena_sobel_y)
lena_sobel_xy = cv.addWeighted(lena_sobel_x, 0.5, lena_sobel_y, 0.5, 0)
cv_show('lena_sobel_xy', lena_sobel_xy)
2、Scharr 算子 & Lablacian 算子
# 不同算子的差异
lena_scharr_x = cv.Scharr(lena, cv.CV_64F, 1, 0)
lena_scharr_x = cv.convertScaleAbs(lena_scharr_x)
lena_scharr_y = cv.Scharr(lena, cv.CV_64F, 0, 1)
lena_scharr_y = cv.convertScaleAbs(lena_scharr_y)
lena_scharr_xy = cv.addWeighted(lena_scharr_x, 0.5, lena_scharr_y, 0.5, 0)
lena_lap = cv.Laplacian(lena, cv.CV_64F)
lena_lap = cv.convertScaleAbs(lena_lap)
res = np.hstack((lena_scharr_xy, lena_lap))
cv_show('res', res)
七、Canny 边缘检测
步骤:
- 高斯滤波,平滑图像;
- 计算每个像素点的梯度强度和方向;
- 非极大值抑制,消除边缘检测带来的杂散响应;
- 双阈值检测,确定真实和潜在的边缘;
- 抑制孤立的弱边缘完成最终检测。
v1 = cv.Canny(lena, 80, 150) # min value 和 max value
v2 = cv.Canny(lena, 50, 100)
res = np.hstack((v1, v2))
cv_show('res', res)
car = cv.imread('car.png', cv.IMREAD_GRAYSCALE)
v1 = cv.Canny(car, 120, 250) # min value 和 max value
v2 = cv.Canny(car, 50, 100)
res = np.hstack((v1, v2))
cv_show('res', res)