OpenCV自适应阈值处理后如何精准提取图像目标点坐标
问题背景
开发需求为定位图像中若干目标点的坐标位置,现有阈值方案存在明显缺陷:
- 固定阈值法:无法适配目标与背景对比度动态变化的场景,无法覆盖所有使用场景
- Otsu全局阈值法:部分场景计算得到的阈值偏低,会引入严重噪声干扰
测试发现adaptiveThreshold自适应阈值二值化效果稳定,但后续调用findContours接口检测轮廓时,单个目标点会被识别出多个冗余轮廓,需要可直接标记二值图像连通区域的算法解决该问题。
原有实现代码如下:
vector<Point2f> pointsImage; Mat gray; cvtColor(image, gray, COLOR_BGR2GRAY); Mat blur; GaussianBlur(gray, blur, cv::Size(5, 5), 0); Mat bw; cv::adaptiveThreshold(blur, bw, 255, cv::AdaptiveThresholdTypes::ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 7, 5); vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(bw, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); for (size_t i = 0; i < contours.size(); i++ ) { if (isContourConvex(contours[i])) { Moments M = moments(contours[i]); Point2f c(M.m10/M.m00, M.m01/M.m00); if (!isnan(c.x) && !isnan(c.y) && !isinf(c.x) && !isinf(c.y)) pointsImage.push_back(c); } }
解决方案
OpenCV原生提供二值图连通区域标记接口connectedComponentsWithStats,可直接替代findContours方案,从根源避免单目标多轮廓的问题。
问题原因
单个目标点被识别出多个冗余轮廓,是因为自适应阈值输出的二值图中,目标区域边缘可能存在细碎缺口、内部可能存在微小空洞,findContours在RETR_TREE模式下会将外轮廓、内部空洞轮廓全部识别输出,最终产生冗余结果。
实现代码
vector<Point2f> pointsImage; Mat gray; cvtColor(image, gray, COLOR_BGR2GRAY); Mat blur; GaussianBlur(gray, blur, cv::Size(5, 5), 0); Mat bw; cv::adaptiveThreshold(blur, bw, 255, cv::ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 7, 5); // 可选:形态学闭运算填补目标区域微小缺口、空洞,避免单个目标被拆分为多个连通域 Mat kernel = getStructuringElement(MORPH_RECT, cv::Size(3,3)); morphologyEx(bw, bw, MORPH_CLOSE, kernel); Mat labels, stats, centroids; // 8邻域连通域标记,输出标签图、连通域统计信息、连通域质心 int connectedCount = connectedComponentsWithStats(bw, labels, stats, centroids, 8, CV_32S); // 跳过标签为0的背景区域,遍历所有前景连通域 for (int i = 1; i < connectedCount; i++) { // 按连通域面积过滤噪声,面积阈值根据实际目标点大小调整 int area = stats.at<int>(i, CC_STAT_AREA); if (area < 2 || area > 100) { continue; } // 直接读取连通域质心坐标,无需额外计算轮廓矩 Point2f c(centroids.at<double>(i, 0), centroids.at<double>(i, 1)); pointsImage.push_back(c); }
方案优势
- 连通域标记会将邻域内相连的像素划分为同一区域,单个目标只要属于同一个连通块就只会输出一个质心,完全解决冗余轮廓问题
- 接口内置质心计算逻辑,无需手动计算轮廓矩,运行效率高于轮廓检测方案
- 可直接通过接口返回的连通域面积、宽高属性做噪声过滤,比原有的轮廓凸性判断逻辑鲁棒性更强
内容的提问来源于stack exchange,提问作者Chris Steffen
相关产品推荐
相关产品推荐

