原图
- Sobel算子
Sobel算子是一种离散型的差分算子,用来计算图像灰度函数的梯度的近似值,是基于一阶导数的边缘检测算子。原理主要是算子包含两组3×3的矩阵,分别为横向以及纵向模板,将之与图像进行平面卷积,最终分别得出横向及纵向的灰度差分近似值,再进行加权操作得出完整边缘信息。实现及效果如下:
img_x = cv2.Sobel(img, cv2.CV_64F, 1, 0)
img_x = cv2.convertScaleAbs(img_x)
img_y = cv2.Sobel(img, cv2.CV_64F, 0, 1)
img_y = cv2.convertScaleAbs(img_y)
final = cv2.addWeighted(img_x, 0.5, img_y, 0.5, 0)
Sobel
2.Scharr算子
Scharr算子与Sobel算子类似,也是由两个核卷积组成 ,但这两个卷积核都不可分离,图像与水平方向上的卷积结果反映的是垂直方向上的边缘强度,图像与垂直方向上的卷积结果反映的是水平方向上的边缘强度。与Sobel相比,计算速度相同,但是精确度更高,实现以及效果如下:
img_x = cv2.Scharr(img, cv2.CV_64F, 1, 0)
img_x = cv2.convertScaleAbs(img_x)
img_y = cv2.Scharr(img, cv2.CV_64F, 0, 1)
img_y = cv2.convertScaleAbs(img_y)
final = cv2.addWeighted(img_x, 0.5, img_y, 0.5, 0)
Scharr
3.Canny边缘检测
Canny是综合了多种边缘检测的算法,其步骤如下:
①采用高斯滤波去除图像的噪声,提早边缘检测的准确性。
②采用Sobel算子计算图像边缘的幅度,然后将得到的横向和纵向卷积得到的进行平方和的开方来计算边缘强度以及梯度方向。
③对每一个位置进行极大值抑制处理,细化边缘信息,具体操作为:遍历图像像素点,判断当前像素点是否是周围像素点中具有相同梯度方向上的最大值,如果该点为极大值,则保留该点,否则将其归零。
④双阈值的滞后阈值处理,常用的处理方法是全局阈值分割和局部自适应阈值分割。
其效果如下:
img= cv2.Canny(img, 100, 200)
Canny
4.Laplacian算子
Laplacian算子是一种二阶导数算子,具有旋转不变性。图像矩阵与拉普拉斯核的卷积本质上是计算任意位置的值与其在水平方向和垂直方向上四个相邻点平均值之间的差值。拉普拉斯核内所有制的和必须等于0,这样就使得在恒等灰度值区域不会产生错误的边缘,其效果如下:
img = cv2.Laplacian(img, cv2.CV_64F)
final = cv2.convertScaleAbs(img)
Laplacian
题外话:
因为看着太黑了,就拿去直方均衡化了一波,结果意外的效果不错
均衡化后图片
def cal_hist(image):
rows, cols = image.shape
grayHist = np.zeros([256], np.uint32)
for r in range(rows):
for c in range(cols):
grayHist[image[r][c]] += 1
return grayHist
def equal_hist(image):
rows, cols = image.shape
grayHist = cal_hist(image)
zeroCumuMoment = np.zeros([256], np.uint32)
for p in range(256):
if p == 0:
zeroCumuMoment[p] = grayHist[0]
else:
zeroCumuMoment[p] = zeroCumuMoment[p - 1] + grayHist[p]
output_q = np.zeros([256], np.uint8)
cofficient = 256.0 / (rows * cols)
for p in range(256):
q = cofficient * float(zeroCumuMoment[p]) - 1
if q >= 0:
output_q[p] = math.floor(q)
else:
output_q[p] = 0
equal_image = np.zeros(image.shape, np.uint8)
for r in range(rows):
for c in range(cols):
equal_image[r][c] = output_q[image[r][c]]
return equal_image
5.高拉普拉斯(改良版)
相对于Laplacian算子相比,这里是首先对图像进行高斯平滑处理,然后再与拉普拉斯核进行卷积运算,代码和效果如下:
def create_kernel(sigma, kSize):
h, w = kSize
log_kernel = np.zeros(kSize, np.float32)
sigma_square = pow(sigma, 2.0)
center_h = (h - 1) / 2
center_w = (w - 1) / 2
for r in range(h):
for c in range(w):
norm = pow(r - center_h, 2.0) + pow(c - center_w, 2.0)
log_kernel[r][c] = 1.0 / sigma_square * (norm / sigma_square - 2) * math.exp(-norm / (2 * sigma_square))
return log_kernel
def deal_log(image, sigma, kSize, _boundary='symm', _fillValue=0):
log_kernel = create_kernel(sigma, kSize)
img_conv_log = signal.convolve2d(image, log_kernel, 'same', boundary=_boundary)
return img_conv_log
def edge_binary(image):
edge = np.copy(image)
edge[edge >= 0] = 0
edge[edge < 0] = 255
edge = edge.astype(np.uint8)
return edge
img = cv2.imread('./line.jpg', 0)
img = cv2.resize(img, (1080, 720))
image1 = deal_log(img, 2, (11, 11), 'symm')
#image1 = deal_log(img, 2, (11, 11), 'fill')
final = edge_binary(image1)
高拉普拉斯后二值化
其中卷积核越大,边缘信息也会越多,随之,噪声也会越多,以下是13×13的效果:
卷积核增大