提取图片的边缘信息是底层数字图像处理的基本任务之一。边缘信息对进一步提取高层语义信息有很大的影响。大部分边缘检测算法都是上个世纪的了,OpenCV 的使用的算法是 Canny 边缘检测算法,大概是在 1986 年由 John F. Canny 提出了,似乎说明边缘检测算法的研究已经到达了瓶颈期。跟人眼系统相比,边缘检测算法仍然逊色不少。
Canny 边缘检测算法是比较出色的算法,也是一种多步算法,可用于检测任何输入图像的边缘。利用它检测图像边缘时主要有以下步骤:
Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:
为了满足这些要求 Canny 使用了变分法(calculus of variations),这是一种寻找优化特定功能的函数的方法。最优检测使用四个指数函数项表示,它可以由高斯函数的一阶导数来近似。
cv2.Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None): # 用自定义梯度 cv2.Canny(dx, dy, threshold1, threshold2[, edges[, L2gradient]]) -> edges
def opencv_canny(image): # 高斯模糊 降低噪声 blurred = cv.GaussianBlur(image, (5, 5), 0) # 转为灰度图像 gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY) # 计算x y 方向梯度 grad_x = cv.Sobel(gray, cv.CV_16SC1, 1, 0) grad_y = cv.Sobel(gray, cv.CV_16SC1, 0, 1) edge_output = cv.Canny(grad_x, grad_y, 60, 120) # 英文字体 Times New Roman plt.rcParams['font.sans-serif'] = ['Times New Roman'] # 可视化结果 plt.figure(figsize=(8, 4), dpi=500) plt.subplot(121) plt.imshow(gray, cmap='gray') plt.title('Original Image', fontsize=18) plt.xticks([]), plt.yticks([]) plt.subplot(122) plt.imshow(edge_output, cmap='gray') plt.title('Edge Image', fontsize=18) plt.xticks([]), plt.yticks([]) plt.savefig("002.png", dpi=500) plt.show() if __name__ == "__main__": # 读取图像 传入 src = cv.imread("Lenna.png") opencv_canny(src)
结果如下:
import numpy as np from skimage.io import imread from skimage.feature import canny import matplotlib.pyplot as plt # 读取图像 img = imread("Lenna.png", as_gray=True) # 高斯模糊 降低噪声 img = cv.GaussianBlur(img, (5, 5), 0) # Canny边缘检测 edges = canny(img, sigma=1.6) # 可视化结果 plt.rcParams['font.sans-serif'] = ['Times New Roman'] plt.figure(figsize=(8, 4), dpi=500) plt.subplot(121) plt.imshow(img, cmap='gray') plt.title('Original Image', fontsize=18) plt.xticks([]), plt.yticks([]) plt.subplot(122) plt.imshow(edges, cmap='gray') plt.title('Edge Image', fontsize=18) plt.xticks([]), plt.yticks([]) plt.show()
结果如下:
import numpy as np import matplotlib.pyplot as plt from scipy import ndimage as ndi from skimage import feature # 产生带有噪声的举行图案 im = np.zeros((128, 128)) im[32:-32, 32:-32] = 1 im = ndi.rotate(im, 15, mode='constant') # 旋转一定角度 im = ndi.gaussian_filter(im, 4) im += 0.2 * np.random.random(im.shape) # Compute the Canny filter for two values of sigma edges1 = feature.canny(im, sigma=1) edges2 = feature.canny(im, sigma=3) # display results fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=3, figsize=(8, 4), sharex=True, sharey=True, dpi=500) ax1.imshow(im, cmap=plt.cm.gray) ax1.axis('off') ax1.set_title('Noisy image', fontsize=20) ax2.imshow(edges1, cmap=plt.cm.gray) ax2.axis('off') ax2.set_title(r'Canny filter, $\sigma=1$', fontsize=20) ax3.imshow(edges2, cmap=plt.cm.gray) ax3.axis('off') ax3.set_title(r'Canny filter, $\sigma=3$', fontsize=20) fig.tight_layout() plt.show()
结果如下:
skimage 库中函数
skimage.feature.canny(image, sigma=1.0, low_threshold=None, high_threshold=None, mask=None, use_quantiles=False)