如何基于OpenCV实现精准蚕卵计数?现有方法存缺陷
精准蚕卵计数的优化方案
针对你遇到的蚕卵计数难题——尤其是小尺寸、重叠椭圆/圆形卵的情况,我有几个针对性的优化方向,比单纯的轮廓检测鲁棒性更强:
一、优化距离变换+非极大值抑制(NMS)
你最初用的距离变换思路其实很适合处理圆形/椭圆目标,但参数调整和峰值过滤环节可以优化,尤其是针对小目标和重叠场景:
import cv2 import numpy as np im = cv2.imread('eggs1.png') gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # 预处理:高斯模糊去噪,适配小目标 blurred = cv2.GaussianBlur(gray, (3, 3), 0) # 自适应阈值,应对光照不均的情况 bw = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 形态学闭运算填补小缝隙,缩小核适配小卵 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2)) morph = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel) # 距离变换提取目标中心 dist = cv2.distanceTransform(morph, cv2.DIST_L2, cv2.DIST_MASK_PRECISE) # 非极大值抑制过滤重复峰值 local_max = cv2.dilate(dist, np.ones((3, 3), np.uint8)) peaks = np.where(dist == local_max, dist, 0) # 阈值筛选有效峰值(降低阈值捕捉小卵) peak_thresh = np.max(dist) * 0.3 peaks[peaks < peak_thresh] = 0 # 标记并计数峰值 peak_coords = np.argwhere(peaks > 0) count = 0 for y, x in peak_coords: # 避免邻近峰值重复计数 if cv2.contourArea(cv2.findContours((dist[y-2:y+2, x-2:x+2] > peak_thresh).astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]) > 0: cv2.circle(im, (x, y), int(dist[y, x]), (255, 0, 0), 1) count += 1 print(f"计数结果:{count}") cv2.imshow('Counted Eggs', im) cv2.waitKey(0) cv2.destroyAllWindows()
这个方案通过自适应阈值解决光照不均问题,缩小形态学核适配小卵,再用非极大值抑制过滤重叠区域的重复峰值,比原版本更精准。
二、分水岭算法分割重叠卵
如果你的图像中卵重叠非常严重,分水岭算法能有效分割粘连的目标:
import cv2 import numpy as np im = cv2.imread('eggs_overlap.png') gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # 预处理去噪 blurred = cv2.GaussianBlur(gray, (5, 5), 0) thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # 确定背景:膨胀操作确保完全覆盖背景区域 kernel = np.ones((3, 3), np.uint8) sure_bg = cv2.dilate(thresh, kernel, iterations=3) # 确定前景:距离变换+阈值筛选目标中心 dist_transform = cv2.distanceTransform(thresh, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.2 * dist_transform.max(), 255, 0) sure_fg = np.uint8(sure_fg) # 找到未知区域(卵的粘连部分) unknown = cv2.subtract(sure_bg, sure_fg) # 标记连通区域 ret, markers = cv2.connectedComponents(sure_fg) # 给标记加1,避免背景被标记为0 markers = markers + 1 # 未知区域标记为0 markers[unknown == 255] = 0 # 应用分水岭算法分割 markers = cv2.watershed(im, markers) im[markers == -1] = [255, 0, 0] # 分割线标记为红色 # 计数:统计标记数量(减去背景和未知区域) count = len(np.unique(markers)) - 2 print(f"计数结果:{count}") cv2.imshow('Watershed Result', im) cv2.waitKey(0) cv2.destroyAllWindows()
分水岭的核心是区分确定前景、确定背景和未知区域,能把粘连的卵精准分开,适合重叠严重的场景。
三、轻量目标检测模型(适合批量复杂图像)
如果你的数据集有一定数量的标注图,用YOLOv8这类轻量模型会是长期最优解,它对小目标、重叠目标的检测精度远高于传统方法:
首先安装依赖:pip install ultralytics
然后编写代码:
from ultralytics import YOLO # 加载预训练模型(可自行标注数据微调) model = YOLO('yolov8n.pt') # yolov8n是最小模型,适配小目标检测 # 若有标注数据,训练命令:model.train(data='eggs.yaml', epochs=50, imgsz=640) # 预测并计数 results = model('eggs_test.png') count = len(results[0].boxes) print(f"计数结果:{count}") # 可视化检测结果 results[0].show()
只需要用LabelImg工具标注几十张蚕卵图像,训练后模型就能精准识别各种复杂场景下的蚕卵,包括小尺寸、重叠的情况。
通用预处理技巧
不管用哪种方法,以下步骤能进一步提升效果:
- 高斯模糊:去除图像噪声,避免误检测小噪点
- 自适应阈值:代替OTSU阈值,应对光照不均匀的图像
- 尺寸归一化:把图像缩放到固定尺寸,确保参数适配所有图像
内容的提问来源于stack exchange,提问作者Levi
相关产品推荐
相关产品推荐

