OpenCV的Watershed算法进行数量检测
分水岭算法数量检测(对复杂任务更通用)
1. 概述
- 目标:通过
Watershed算法检测图像中的物体数量,适用于处理重叠或紧密接触的物体。 - 使用技术:
2. 环境准备
与前面相同,确保安装以下库:
pip install opencv-python numpy
3. 图像读取与预处理
与之前的步骤相同,我们先读取图像并进行灰度化、模糊和二值化。
import cv2
import numpy as np
# 读取图像
img = cv2.imread('objects.jpg')
# 转为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 应用高斯模糊
blurred = cv2.GaussianBlur(gray, (11, 11), 0)
# 二值化处理
_, thresh = cv2.threshold(blurred, 150, 255, cv2.THRESH_BINARY_INV)
# 显示预处理结果
cv2.imshow('Threshold Image', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
4. 应用形态学操作
我们使用形态学操作对物体进行膨胀操作,以帮助分离连在一起的物体。
# 定义核
kernel = np.ones((3, 3), np.uint8)
# 应用开运算(先腐蚀后膨胀)去除噪声
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 膨胀操作
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# 显示膨胀后的背景
cv2.imshow('Sure Background', sure_bg)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明:
- 开运算:通过腐蚀再膨胀去除小噪声点。
- 膨胀:进一步扩展物体边界,确保可以识别出物体的背景。
5. 应用距离变换
使用距离变换来帮助区分相邻的物体。
# 距离变换
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
# 对结果进行阈值化,确保只有物体的中心区域被保留
_, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# 转换为uint8类型
sure_fg = np.uint8(sure_fg)
# 找到未知区域(背景减去前景)
unknown = cv2.subtract(sure_bg, sure_fg)
# 显示距离变换后的前景
cv2.imshow('Sure Foreground', sure_fg)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明:
- 距离变换:根据物体中心的距离将其标记为前景区域。
- 阈值化:通过设置阈值,仅保留物体的核心区域。
6. 应用 Watershed 算法
我们使用 Watershed 来区分相邻或重叠的物体。
# 标记连通区域
_, markers = cv2.connectedComponents(sure_fg)
# 对marker加1,确保背景为0
markers = markers + 1
# 将未知区域标记为0
markers[unknown == 255] = 0
# 应用Watershed算法
markers = cv2.watershed(img, markers)
# 边界处的标记为-1
img[markers == -1] = [0, 0, 255]
# 显示分割后的图像
cv2.imshow('Watershed Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明:
- 连通区域标记:我们为每个物体分配一个唯一的标签。
- Watershed算法:通过
cv2.watershed对图像进行分割,重叠物体的边界会被正确识别。
7. 检测物体数量
通过检测分割后的标记区域,统计物体数量。
# 统计物体数量(去除背景和边界标记)
num_objects = np.max(markers) - 1 # 减去背景和边界的标记
print(f"检测到的物体数量: {num_objects}")
代码说明:
np.max(markers):标记值的最大值代表了物体的数量。- 减去1是为了排除背景的标记。
8. 完整代码
下面是完整的代码,使用 Watershed 算法进行物体数量检测。
import cv2
import numpy as np
# 读取图像
img = cv2.imread('objects.jpg')
# 转为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 应用高斯模糊
blurred = cv2.GaussianBlur(gray, (11, 11), 0)
# 二值化处理
_, thresh = cv2.threshold(blurred, 150, 255, cv2.THRESH_BINARY_INV)
# 定义核
kernel = np.ones((3, 3), np.uint8)
# 应用开运算去除噪声
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 膨胀操作
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# 距离变换
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
# 对结果进行阈值化,确保只有物体的中心区域被保留
_, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# 转换为uint8类型
sure_fg = np.uint8(sure_fg)
# 找到未知区域(背景减去前景)
unknown = cv2.subtract(sure_bg, sure_fg)
# 标记连通区域
_, markers = cv2.connectedComponents(sure_fg)
# 对marker加1,确保背景为0
markers = markers + 1
# 将未知区域标记为0
markers[unknown == 255] = 0
# 应用Watershed算法
markers = cv2.watershed(img, markers)
# 边界处的标记为-1
img[markers == -1] = [0, 0, 255]
# 显示分割后的图像
cv2.imshow('Watershed Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 统计物体数量(去除背景和边界标记)
num_objects = np.max(markers) - 1
print(f"检测到的物体数量: {num_objects}")
9. 总结
通过结合 Watershed 算法,我们能够有效地分离重叠或紧密接触的物体,并进行数量检测。这种方法特别适用于需要分割物体边界的复杂场景,例如硬币、细胞等。
评论
目录