赞
踩
首先解释一下第一种分水岭算法:
分水岭算法是一种基于拓扑学的图像分割技术,广泛应用于图像处理和计算机视觉领域。它将图像视为一个拓扑表面,其中亮度值代表高度。算法的目标是通过模拟雨水从山顶流到山谷的过程,将图像分割成若干独立的区域。
距离变换:
寻找局部极大值:
创建标记图:
应用分水岭算法:
生成分割结果:
优点:
缺点:
# 计算每个二值像素到最近零像素的精确欧几里得距离, 然后找到此距离图中的局部峰值
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, footprint=np.ones((3, 3)), min_distance=40, labels=thresh)
# 根据找到的局部峰值创建标记数组, 标记数组的值对应于每个硬币的序号
markers = np.zeros_like(thresh, dtype=np.int32)
markers[tuple(localMax.T)] = np.arange(1, len(localMax) + 1)
# 应用分水岭算法, 将图像分割为不同的区域
labels = watershed(-D, markers, mask=thresh)
ndimage.distance_transform_edt(thresh)
计算每个前景像素到最近背景像素的欧几里得距离,生成距离图 D
。peak_local_max(D, footprint=np.ones((3, 3)), min_distance=40, labels=thresh)
在距离图中寻找局部极大值,这些点将作为初始标记。markers
初始化为全零矩阵,将局部极大值点的位置赋值为不同的标签。labels = watershed(-D, markers, mask=thresh)
使用分水岭算法对距离图的负值进行分割,生成标签图 labels
。通过以上步骤,分水岭算法将输入图像分割成若干独立区域,每个区域代表一个目标物体。
以检测这张图为例子:
读取图像并应用均值漂移滤波:
cv2.imread
读取输入图像。cv2.pyrMeanShiftFiltering
对图像进行均值漂移滤波,平滑图像并减少噪点。转换为灰度图并二值化:
cv2.cvtColor
将平滑后的图像转换为灰度图。cv2.threshold
结合 Otsu 算法进行自动阈值二值化,将图像转换为二值图像。计算欧几里得距离并找到局部峰值:
ndimage.distance_transform_edt
计算每个二值像素到最近零像素的欧几里得距离,生成距离变换图。peak_local_max
找到距离图中的局部峰值,这些峰值将作为分水岭算法的初始标记。创建标记数组并应用分水岭算法:
markers
,将局部峰值的位置赋值为不同的标签。watershed
函数进行分水岭算法,将图像分割成不同区域,每个区域对应一个硬币。遍历分割出的不同区域,绘制轮廓和标签:
cv2.findContours
查找掩码图像中的轮廓,并找到最大的轮廓(即硬币区域)。cv2.minEnclosingCircle
计算最小外接圆的圆心坐标和半径。显示最终结果图像:
cv2.imshow
显示处理后的图像。cv2.waitKey
和 cv2.destroyAllWindows
控制显示窗口。上述流程通过图像平滑、二值化、距离变换、局部峰值检测和分水岭算法,实现了对硬币图像的分割,并在分割后的图像上绘制了硬币的轮廓和编号标签。
完整代码如下:
import numpy as np import cv2 from skimage.feature import peak_local_max from skimage.segmentation import watershed from scipy import ndimage import imutils # 读取图像并应用均值漂移滤波来平滑图像,减少噪点 image = cv2.imread('/coins/1.jpg') shifted = cv2.pyrMeanShiftFiltering(image, 21, 51) # 将图像转换为灰度图,然后使用Otsu算法自动确定阈值进行二值化 gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 计算每个二值像素到最近零像素的精确欧几里得距离,然后找到此距离图中的局部峰值 # 这些峰值将作为分水岭算法的初始标记 D = ndimage.distance_transform_edt(thresh) localMax = peak_local_max(D, footprint=np.ones((3, 3)), min_distance=40, labels=thresh) # 根据找到的局部峰值创建标记数组,标记数组的值对应于每个硬币的序号 markers = np.zeros_like(thresh, dtype=np.int32) markers[tuple(localMax.T)] = np.arange(1, len(localMax) + 1) # 应用分水岭算法,将图像分割为不同的区域 labels = watershed(-D, markers, mask=thresh) # 遍历分割出的不同区域,绘制出每个硬币的轮廓和标签 for label in np.unique(labels): if label == 0: continue # 创建一个掩码图像,将当前标签对应的区域设置为白色,其他区域设置为黑色 mask = np.zeros(gray.shape, dtype="uint8") mask[labels == label] = 255 # 查找掩码图像中的轮廓,并找到最大的轮廓(即硬币区域) cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) c = max(cnts, key=cv2.contourArea) # 计算最小外接圆的圆心坐标和半径 ((x, y), r) = cv2.minEnclosingCircle(c) # 在原始图像上绘制圆形轮廓和标签 cv2.circle(image, (int(x), int(y)), int(r), (0, 255, 0), 2) cv2.putText(image, "{}".format(label), (int(x) - 10, int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) # 显示最终的结果图像 cv2.imshow("Output", image) cv2.waitKey(0) cv2.destroyAllWindows()
分割结果如下:
霍夫变换(Hough Transform)是图像处理中的一种重要技术,用于检测图像中的几何形状。霍夫圆检测(Hough Circle Transform)是霍夫变换的一个具体应用,用于检测图像中的圆形物体。
边缘检测:
参数空间定义:
投票累加:
在边缘检测后的二值图像中,每个边缘点 (x, y) 都会在参数空间中投票支持可能的圆心和半径组合。具体而言,对于每个边缘点 (x, y) 和每个可能的半径 r,可以根据圆的方程计算圆心坐标 (a, b):
在参数空间中累加 (a, b) 的投票次数。
检测局部最大值:
绘制检测到的圆:
以下是一个使用OpenCV进行霍夫圆检测的示例代码:
import cv2 import numpy as np # 读取图像 image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 应用高斯模糊,减少噪声 blurred = cv2.GaussianBlur(gray, (9, 9), 2) # 使用霍夫圆检测 circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=20, param1=50, param2=30, minRadius=15, maxRadius=30) # 如果检测到圆 if circles is not None: circles = np.round(circles[0, :]).astype("int") for (x, y, r) in circles: # 绘制圆的轮廓 cv2.circle(image, (x, y), r, (0, 255, 0), 4) # 绘制圆心 cv2.rectangle(image, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1) # 显示结果图像 cv2.imshow("output", image) cv2.waitKey(0) cv2.destroyAllWindows()
读取图像并转换为灰度图:
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
应用高斯模糊:
blurred = cv2.GaussianBlur(gray, (9, 9), 2)
使用霍夫圆检测:
cv2.HoughCircles
函数进行霍夫圆检测。参数解释如下:
blurred
:输入的灰度图像。cv2.HOUGH_GRADIENT
:检测方法,使用梯度信息。dp=1.2
:累加器分辨率与图像分辨率的反比关系。minDist=20
:检测到的圆之间的最小距离。param1=50
:Canny边缘检测的高阈值。param2=30
:累加器阈值,用于检测圆的阈值,越小越容易检测到不明显的圆。minRadius=15
和 maxRadius=30
:检测圆的半径范围。circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=20,
param1=50, param2=30, minRadius=15, maxRadius=30)
绘制检测到的圆:
if circles is not None:
circles = np.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
cv2.circle(image, (x, y), r, (0, 255, 0), 4)
cv2.rectangle(image, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
显示结果图像:
cv2.imshow("output", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
通过上述步骤和代码,霍夫圆检测可以在图像中自动识别和绘制圆形目标。
识别图中硬币的完整代码如下:
import cv2 import numpy as np # 读取图像并转换为灰度图像 image = cv2.imread('/coins/1.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 应用高斯模糊 gray = cv2.GaussianBlur(gray, (15, 15), 0) # 使用霍夫圆变换检测圆 circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1.2, minDist=50, param1=50, param2=30, minRadius=20, maxRadius=60) # 确保至少检测到一个圆 if circles is not None: circles = np.round(circles[0, :]).astype("int") for (i, (x, y, r)) in enumerate(circles): # 绘制圆圈和中心点 cv2.circle(image, (x, y), r, (0, 255, 0), 2) cv2.putText(image, str(i + 1), (x - 10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) # 显示最终结果图像 cv2.imshow("Detected Coins", image) cv2.waitKey(0) cv2.destroyAllWindows()
检测结果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。