canny边缘检测
实现代码:
import cv2 import numpy as np img = cv2.imread('./tu2.jpg', 0) print(img.shape) height, width = img.shape # 高斯滤波 fil = np.array([[ 1, 2, 1], [ 2, 4, 2], [ 1, 2, 1]]) fil = fil/16 res = cv2.filter2D(img,-1,fil) # 梯度 dx = np.zeros((height, width)) dy = np.zeros((height, width)) d = np.zeros((height, width)) for i in range(1, height-1): for j in range(1, width-1): dx[i, j] = int(res[i, j+1]) - int(res[i, j]) dy[i, j] = int(res[i+1, j]) - int(res[i, j]) d[i, j] = np.sqrt(dx[i, j]**2 + dy[i, j]**2) cv2.imshow('d', d) # 非极大值抑制 k = d for i in range(1, height-1): for j in range(1, width-1): gradX = dx[i,j] gradY = dy[i,j] gradTemp = d[i,j] if abs(gradY) > abs(gradX): weight = abs(gradX)/abs(gradY) if abs(gradY)!=0 else 1 grad2 = d[i - 1,j] grad4 = d[i + 1,j] if gradX * gradY > 0: grad1 = d[i - 1,j - 1] grad3 = d[i + 1,j + 1] else: grad1 = d[i - 1,j + 1] grad3 = d[i + 1,j - 1] else: weight = abs(gradY) / abs(gradX) if abs(gradY)!=0 else 1 grad2 = d[i,j - 1] grad4 = d[i,j + 1] if gradX * gradY > 0: grad1 = d[i + 1,j + 1] grad3 = d[i - 1,j - 1] else: grad1 = d[i - 1,j + 1] grad3 = d[i + 1,j - 1] # 利用grad1-grad4对梯度进行插值 gradTemp1 = weight * grad1 + (1 - weight) * grad2 gradTemp2 = weight * grad3 + (1 - weight) * grad4 # 当前像素的梯度是局部的最大值,可能是边缘点 if gradTemp >= gradTemp1 and gradTemp >= gradTemp2: k[i,j] = gradTemp else: k[i,j] = 0 cv2.imshow('k', k) # 定义双阈值 EP_MIN = 12 EP_MAX = EP_MIN * 2 EdgeLarge = np.zeros((height, width)) #记录真边缘 EdgeBetween = np.zeros((height, width)) #记录可能的边缘点 for i in range(1, height-1): for j in range(1, width-1): if k[i,j] >= EP_MAX: EdgeLarge[i,j] = k[i,j] elif k[i,j] >= EP_MIN: EdgeBetween[i,j] = k[i,j] cv2.imshow('EdgeLarge', EdgeLarge) cv2.imshow('EdgeBetween', EdgeBetween) # 把EdgeLarge的边缘连成连续的轮廓 edge = np.zeros((height, width)) for i in range(1, height-1): for j in range(1, width-1): if EdgeLarge[i,j] > 0: edge[i,j] = EdgeLarge[i,j] list_position = [[i-1, j-1], [i, j-1], [i+1, j-1], [i+1, j], [i+1, j+1], [i, j+1], [i-1, j+1], [i-1, j]] for lis in list_position: x = lis[0] y = lis[1] if EdgeBetween[x, y] > 0: edge[x, y] = EdgeBetween[x, y] EdgeBetween[x, y] = 0#避免重复计算 cv2.imshow('edge', edge) cv2.waitKey() cv2.destroyAllWindows()
实现结果图片: