OpenCV findContours无法检测物体实际轮廓,仅生成圆形区域问题排查
问题:Unity+OpenCV生成实例分割掩码后,findContours提取轮廓不符合预期
我用Unity和OpenCV for Unity搭建自动实例分割数据集生成器,能从不同角度、光照条件下拍摄物体并导出图像,同时单独导出物体掩码——原本以为掩码能降低findContours()的检测难度,结果实际提取的轮廓完全不符合预期。试过更换不同轮廓检测模式,也用Python重写了提取逻辑,都没解决问题,怀疑是图像本身的问题,求分析原因。
C# 处理掩码的代码
void ProcessMaskImage(Mat maskImage, string fileName) { Mat gray = new Mat(); Imgproc.cvtColor(maskImage, gray, Imgproc.COLOR_BGR2GRAY); List<MatOfPoint> contours = new List<MatOfPoint>(); Mat hierarchy = new Mat(); Imgproc.findContours(gray, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); StringBuilder sb = new StringBuilder(); foreach (MatOfPoint contour in contours) { List<Vector2> normalizedContour = new List<Vector2>(); foreach (Point point in contour.toArray()) { float x = (float)point.x / gray.width(); float y = (float)point.y / gray.height(); normalizedContour.Add(new Vector2(x, y)); } sb.Append($"0 "); // 后续替换为实际类别ID foreach (Vector2 point in normalizedContour) { sb.Append($"{point.x.ToString(CultureInfo.InvariantCulture)} {point.y.ToString(CultureInfo.InvariantCulture)} "); } sb.AppendLine(); } SaveYOLOFormat(sb.ToString(), fileName); }
Python 轮廓提取代码
def convert_mask_to_yolo(mask_image_path, output_path, class_id=0): mask = cv2.imread(mask_image_path, cv2.IMREAD_GRAYSCALE) height, width = mask.shape contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) yolo_format = "" for contour in contours: normalized_contour = [] for point in contour: x = point[0][0] / width y = point[0][1] / height normalized_contour.append((x, y)) yolo_format += f"{class_id} " + " ".join([f"{x} {y}" for x, y in normalized_contour]) + "\n" file_name = os.path.splitext(os.path.basename(mask_image_path))[0] + '.txt' with open(os.path.join(output_path, file_name), 'w') as file: file.write(yolo_format)
可能的图像问题原因
- 掩码二值化不彻底:如果掩码不是严格的黑白二值图(存在灰度过渡、噪点),
findContours会将这些灰度变化误判为轮廓。Unity导出的掩码可能未做阈值处理,或导出时因压缩导致原本纯黑/纯白的区域出现灰度值波动。 - 掩码通道/像素值错误:C#代码中把BGR转灰度,但如果Unity导出的掩码本身是单通道灰度图,重复转换可能引入错误;同时要确认掩码像素值是否正确——物体区域应为255(白色)、背景为0(黑色),若反过来,
findContours会检测背景轮廓。 - 图像与掩码尺寸不匹配:检查导出的图像和掩码尺寸是否完全一致,若Unity拍摄的图像与掩码导出时被缩放,会导致归一化坐标错误,甚至轮廓提取区域完全错位。
- 掩码存在噪点或孔洞:物体掩码上的细小白点(噪点)或内部孔洞,会让
RETR_EXTERNAL模式将噪点当成独立轮廓,或孔洞边缘被检测为额外轮廓,导致结果混乱。可先对掩码做形态学操作(开运算去噪、闭运算补孔洞)再提取轮廓。 - 导出格式错误:若用JPG格式导出掩码,压缩会导致像素值失真;必须使用PNG这类无损格式导出掩码,避免灰度值被压缩改变。
内容的提问来源于stack exchange,提问作者Philipp
相关产品推荐
相关产品推荐

