zl程序教程

您现在的位置是:首页 >  其它

当前栏目

图像分割 - 孤立点的检测

检测 图像 分割
2023-09-11 14:15:38 时间

目录

1. 介绍

2. 代码实现


1. 介绍

因为,一阶导数通常会产生粗边缘。二阶导数对精细细节(细线、孤立点、噪声)有更强的响应。

所以,检测孤立点应该以二阶导数为基础,而二阶导数的差分计算为:

\bigtriangledown ^{2}f(x,y) = f(x+1,y) + f(x-1,y) + f(x,y+1) + f(x,y-1) - 4f(x,y)

这个差分计算可以通过一个 系数和为零 的kernel去完成

于是,如果滤波器的响应超过一个规定的阈值,那我们就认为在kernel的中心找到了一个点。将找到的点记作1,其他的点看作0,于是就得到了一副二值图像

直观上看,这个概念是孤立点的灰度完全不同于其周围像素的灰度

孤立点是那些灰度差超过某个阈值T,被认为是孤立点的像素点

为了更好的探测8邻域的灰度差值,将滤波器的权重换成下面类型的:

111
1-81
111

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就行了。为了方便观察,以孤立点绘制出一个圆弧,注:圆心的坐标是反过来的