目录
1. 介绍
因为,一阶导数通常会产生粗边缘。二阶导数对精细细节(细线、孤立点、噪声)有更强的响应。
所以,检测孤立点应该以二阶导数为基础,而二阶导数的差分计算为:
这个差分计算可以通过一个 系数和为零 的kernel去完成
于是,如果滤波器的响应超过一个规定的阈值,那我们就认为在kernel的中心找到了一个点。将找到的点记作1,其他的点看作0,于是就得到了一副二值图像
直观上看,这个概念是孤立点的灰度完全不同于其周围像素的灰度
孤立点是那些灰度差超过某个阈值T,被认为是孤立点的像素点
为了更好的探测8邻域的灰度差值,将滤波器的权重换成下面类型的:
1 | 1 | 1 |
1 | -8 | 1 |
1 | 1 | 1 |
2. 代码实现
代码为:
-
import numpy
as np
-
import cv2
-
-
-
def
point_detect(
img):
-
-
canvas = np.zeros(img.shape, dtype=np.uint8)
# 拷贝图像
-
kernel = np.array([[
1,
1,
1], [
1, -
8,
1], [
1,
1,
1]])
# 定义卷积核
-
laplacian = cv2.filter2D(img, cv2.CV_16S, kernel)
# 拉普拉斯变换
-
-
img_lap = cv2.convertScaleAbs(laplacian)
# 拉普拉斯图像
-
cv2.imshow(
'laplacian',img_lap)
-
-
T =
0.9 * np.
abs(laplacian).
max()
# 阈值 T
-
-
for i
in
range(img.shape[
0]):
# 遍历图像,寻找孤立点
-
for j
in
range(img.shape[
1]):
-
if (laplacian[i, j] > T)
or (laplacian[i, j] < -T):
# 绝对值大于阈值的点
-
canvas[i, j] =
255
# 二值处理
-
cv2.circle(canvas, (j, i),
10,
255)
# 绘制圆
-
-
return canvas
-
-
-
img = cv2.imread(
'img.tif',
0)
-
ret = point_detect(img)
-
cv2.imshow(
'img',np.hstack((img,ret)))
-
cv2.waitKey()
-
cv2.destroyAllWindows()
处理的结果为:
原图、检测孤立点的二值图像
原图的拉普拉斯图像为:
这里对孤立点检测函数的代码做简单讲解:
1. 首先,建立一个全零的图片canvas,后面将检测的孤立点改为255,这样canvas就是二值图像了
2. filter2D 里面的ddepth 是CV_16S ,因为做差会出现负数,不能采用无符号的形式
3. 如果为了打印拉普拉斯图像,需要将图像转换成uint8,并且灰度值在0-255之间。这里用的是convertScaleAbs函数,就是取绝对值,然后超过255的都取255。
如果采用norm的形式是这个样子的,代码为:
img_norm = cv2.normalize(laplacian,None,0,255,norm_type=cv2.NORM_MINMAX,dtype=cv2.CV_8U)
4. 这里不管用convert还是norm的形式都要取对应的阈值T,最后就是遍历图像,将大于T的找出来,赋值为255就行了。为了方便观察,以孤立点绘制出一个圆弧,注:圆心的坐标是反过来的
转载:https://blog.csdn.net/qq_44886601/article/details/127699635
查看评论