Prewitt算子和Sobel算子也是基于一阶导数的算子。
Sobel算子为距离近的元素设计了了更高的权重。
算子 | 卷积核 |
---|---|
Prewitt算子 | [[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]] 和 [[-1, -1, -1], [0, 0, 0], [1, 1, 1]] |
Sobel算子 | [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]] 和 [[-1, -2,-1], [ 0, 0, 0], [ 1, 2, 1]] |
所以Prewitt算子和Sobel算子计算方式相同。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
def convolution(matrix, c_kernel):
# Prewitt算子的卷积核是3*3,所以卷积后少一圈
rows, columns = matrix.shape
# 这里提前补上了
result_matrix = matrix.copy().astype(np.int16)
for i in range(1, rows-1):
for j in range(1, columns-1):
result_matrix[i][j] = (matrix[i-1][j-1]*c_kernel[0][0] +
matrix[i-1][j]*c_kernel[0][1] +
matrix[i-1][j+1]*c_kernel[0][2] +
matrix[i][j-1]*c_kernel[1][0] +
matrix[i][j]*c_kernel[1][1] +
matrix[i][j+1]*c_kernel[1][2] +
matrix[i+1][j-1]*c_kernel[2][0] +
matrix[i+1][j]*c_kernel[2][1] +
matrix[i+1][j+1]*c_kernel[2][2]
)
return result_matrix
def Prewitt_Edge_Detection(source_img):
# 输入灰度图,输出边缘提取后的灰度图
rows, columns = source_img.shape
img = source_img.copy()
# Prewitt算子
Prewitt_1 = np.array([[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]], dtype=int)
Prewitt_2 = np.array([[-1, -1, -1],
[0, 0, 0],
[1, 1, 1]], dtype=int)
'''
# Sobel算子
Sobel_1 = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]], dtype=int)
Sobel_2 = np.array([[-1, -2,-1],
[ 0, 0, 0],
[ 1, 2, 1]], dtype=int)
# 用Sobel时直接更换。
'''
# step2 卷积
x = convolution(img, Prewitt_1)
y = convolution(img, Prewitt_2)
# 也可以调用cv2的filter2D函数。
# x = cv2.filter2D(img, cv2.CV_16S, Prewitt_1)
# y = cv2.filter2D(img, cv2.CV_16S, Prewitt_2)
# # 转换卷积后的图片深度,转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Prewitt_img = np.zeros((rows, columns), dtype=np.uint8)
# 或 Prewitt_img = np.array([[0]*columns]*rows).astype(np.uint8)
for i in range(rows):
for j in range(columns):
Prewitt_img[i][j] = 0.5*absX[i][j] + 0.5*absY[i][j]
# 或 Prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
return Prewitt_img
if __name__ == "__main__":
# 用imread时需要注意图片路径不要包含中文,否则会can't open/read file: check file path/integrity
# cv2.IMREAD_GRAYSCALE 读入灰度图
source_img = cv2.imread('pictures\\source\\1.jpg', cv2.IMREAD_GRAYSCALE)
# 文件中说In the case of color images, the decoded images will have the channels stored in **B G R** order.彩色图读入BGR
result_img = Prewitt_Edge_Detection(source_img)
# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# plt.imshow()里添加参数cmap=“gray”,显示灰度图
plt.subplot(121), plt.imshow(source_img, cmap="gray"), plt.title('source imge'), plt.axis('off') # 坐标轴关闭
plt.subplot(122), plt.imshow(result_img, cmap="gray"), plt.title('Prewitt operator imge'), plt.axis('off')
plt.savefig('pictures\\result\\1_Prewitt operator result.jpg', bbox_inches='tight')
plt.show()
起初,卷积公式按照Roberts算子实现时的用result_matrix矩阵进行卷积,即
result_matrix[i-1][j-1]*c_kernel[0][0] +
result_matrix[i-1][j]*c_kernel[0][1] + (省略)
编译时出错:RuntimeWarning: overflow encountered in long_scalars
起初认为是np.int16表示范围不够大造成溢出,于是简单的将其改为np.int32最后甚至改为np.longlong,但还是溢出。这时应该是程序逻辑出错了,在出错地点及其周围检查后终于发现了问题。
在用Roberts算子进行卷积时,其 本次计算结果不会影响到下一次计算(因为计算结果仅与本身、右像素点、下像素点、右下像素点有关),所以用结果数组进行计算不会出错;而Prewitt算子和Sobel算子的卷积核为3*3,导致计算结果会影响下一次计算,所以最终导致程序可能将多次结果进行累计(互相影响),使得计算结果非常大,最终溢出。改为原始matrix后问题得以解决。