孤立点检测
在Python中使用OpenCV进行孤立点(异常点)检测,可以通过应用统计分析或者使用OpenCV的findContours和convexHull函数来识别。以下是一个简单的例子,使用OpenCV的findContours和convexHull来识别并绘制孤立点。
孤立点的检测,是检测嵌在一幅图像的恒定区域或亮度几乎不变的区域里的孤立点。孤立点的检测以二阶导数为基础。
当孤立点在卷积模板的中心时,拉普拉斯滤波器的响应很强烈,而孤立点在非模板中心时,拉普拉斯滤波器响应为零。当滤波器在一个点的响应超过设定阈值 T,则认为在卷积核的中心检测到了孤立点,标记为 1,而其它点都被标记为 0,从而产生一副二值图像。
注意:
-
(1)本节所称的孤立点检测,是绝对意义上的孤立点,即一个孤立的像素。人眼所能感知、识别的孤立点,通常来说其实是一个微小的区域,而不是孤立的一个像素,因此并不能用这种方法检测。
-
(2)使用 Laplace 算子进行图像孤立点检测,推荐使用 scipy.signal 实现卷积运算,不建议使用 cv2.filter2D 实现。后者自动将卷积结果进行归一化处理,不便于通过阈值 T 检测孤立点。
# 11.1 图像孤立点检测 (Laplace 算子)
imgGray = cv2.imread("../images/Fig1004.tif", flags=0)
hImg, wImg = imgGray.shape
# scipy.signal 实现卷积运算 (注意:不能用 cv2.filter2D 处理)
from scipy import signal
kernelLaplace = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]]) # Laplacian kernel
imgLaplace = signal.convolve2d(imgGray, kernelLaplace, boundary='symm', mode='same') # same 卷积
# 在原图上用半径为 5 的圆圈标记角点
T = 0.9 * max(imgLaplace.max(), -imgLaplace.min())
imgPoint = np.zeros((hImg, wImg), np.uint8) # 创建黑色图像
for h in range(hImg):
for w in range(wImg):
if (imgLaplace[h, w] > T) or (imgLaplace[h, w] < -T):
imgPoint[h, w] = 255 # 二值处理
cv2.circle(imgPoint, (w, h), 10, 255)
print(imgLaplace.shape, imgLaplace.max(), imgLaplace.min(), T)
plt.figure(figsize=(9, 6))
plt.subplot(131), plt.axis('off'), plt.title("Original")
plt.imshow(imgGray, cmap='gray', vmin=0, vmax=255)
plt.subplot(132), plt.axis('off'), plt.title("Laplacian K2")
plt.imshow(imgLaplace, cmap='gray', vmin=0, vmax=255)
plt.subplot(133), plt.axis('off'), plt.title("Isolated point")
plt.imshow(imgPoint, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()
import cv2
import numpy as np
# 读取图像
image = cv2.imread('isolated_points.png', 0)
# 二值化图像
_, thresh = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
# 寻找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 遍历轮廓并计算凸包
for contour in contours:
# 计算凸包
hull = cv2.convexHull(contour)
# 如果凸包的点数小于等于3,则可能是孤立点
if len(hull) <= 3:
# 绘制原始轮廓
cv2.drawContours(image, [contour], -1, (0, 255, 0), 2)
# 显示图像
cv2.imshow('Isolated Points', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这个例子中,我们首先读取了一个包含孤立点的图像,然后将其转换为二值图像。接着,我们使用findContours函数找到所有轮廓。对于每个轮廓,我们计算其凸包,并检查凸包的点数。如果点数小于等于3,则可能是孤立点,我们将其用绿色线条绘制在原图上。最后,我们显示处理后的图像
C++
使用拉普拉斯核进行点的检测
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image, image_gray, image_bw, image_bw2;
image = imread("lena孤立点.png"); //读取图像;
if (image.empty())
{
cout << "读取错误" << endl;
return -1;
}
//转换为灰度图像
cvtColor(image, image_gray, COLOR_BGR2GRAY);
cv::imshow("image_gray", image_gray);
//1.构建拉普拉斯孤立点检测卷积核
Mat Laplacian_kernel = (cv::Mat_<float>(3, 3) << 0, 1, 0,
1, -4, 1,
0, 1, 0);
//2.卷积运算
filter2D(image_gray, image_bw, -1, Laplacian_kernel);
cv::imshow("image_bw", image_bw);
//3.阈值处理
threshold(image_bw, image_bw2, 250, 255, 0); //通过0,1调节二值图像背景颜色
cv::imshow("image_bw2", image_bw2);
cv::waitKey(0); //暂停,保持图像显示,等待按键结束
return 0;
}