如何用C#的Emgu.CV在平面图中检测房间门并修改颜色?
问题:平面图门检测误判的解决思路
我有平面图图片和GeoJSON文件,需要把GeoJSON叠加到图片上,修改房间和门的颜色。已经用Emgu.CV实现了房间检测和颜色修改,但卡在门的检测与颜色修改环节:只有房间坐标,尝试通过房间的黄色检测门,会误检房间内其他区域,不确定是否需要门的坐标,求解决思路。
现有C#代码
static void DetectAndDrawDoors(Image<Bgr, byte> image, List<PolygonData> polygonDataList) { Mat hsvImage = new Mat(); CvInvoke.CvtColor(image, hsvImage, ColorConversion.Bgr2Hsv); ScalarArray lowerBound = new ScalarArray(new MCvScalar(20, 50, 0)); ScalarArray upperBound = new ScalarArray(new MCvScalar(29, 255, 100)); Mat yellowMask = new Mat(); CvInvoke.InRange(hsvImage, lowerBound, upperBound, yellowMask); CvInvoke.GaussianBlur(yellowMask, yellowMask, new Size(5, 5), 0); CvInvoke.MorphologyEx(yellowMask, yellowMask, MorphOp.Open, CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(5, 5), new Point(-1, -1)), new Point(-1, -1), 1, BorderType.Default, new MCvScalar()); VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); CvInvoke.FindContours(yellowMask, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); // Iterate over contours using a for loop for (int i = 0; i < contours.Size; i++) { VectorOfPoint approxContour = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contours[i], approxContour, 10, false); if (CvInvoke.ContourArea(approxContour) > 20) { Rectangle boundingBox = CvInvoke.BoundingRectangle(approxContour); // Check if the current contour is part of any active polygon foreach (var polygonData in polygonDataList.Where(pd => pd.Active == "True")) { if (IsContourInActivePolygon(approxContour, polygonData.Coordinates)) { CvInvoke.Rectangle(image, boundingBox, new MCvScalar(0, 255, 0), 20); } } } } } static bool IsContourInActivePolygon(VectorOfPoint contour, List<Coordinate> polygonCoordinates) { // Convert contour points to coordinates List<Coordinate> contourCoordinates = contour.ToArray().Select(point => new Coordinate { Latitude = point.Y, Longitude = point.X }).ToList(); // Check if any point of the contour is inside the polygon return contourCoordinates.Any(point => IsPointInPolygon(point, polygonCoordinates)); } static bool IsPointInPolygon(Coordinate point, List<Coordinate> polygonCoordinates) { // Implementation of point in polygon algorithm int count = polygonCoordinates.Count; bool inside = false; for (int i = 0, j = count - 1; i < count; j = i++) { if (((polygonCoordinates[i].Latitude > point.Latitude) != (polygonCoordinates[j].Latitude > point.Latitude)) && (point.Longitude < (polygonCoordinates[j].Longitude - polygonCoordinates[i].Longitude) * (point.Latitude - polygonCoordinates[i].Latitude) / (polygonCoordinates[j].Latitude - polygonCoordinates[i].Latitude) + polygonCoordinates[i].Longitude)) { inside = !inside; } } return inside; }
34号房间GeoJSON示例
{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ [768,74], [768,322], [851,322], [875,346], [872,349], [872,350], [931,409], [934,406], [935,406], [959,430], [959,522], [1102,522], [1102,74] ] }, "properties": { "active": true, "roomname": "34", "disp_label": "", "arch_ref": "" } }
解决思路
1. 优化颜色检测与轮廓筛选
仅靠黄色范围过滤容易误检,可增加多重约束:
- 缩小HSV参数范围:比如把明度上限从100调低,过滤房间内偏亮的黄色干扰区域;
- 增加形状判断:门通常是细长矩形,计算轮廓的宽高比,只保留宽高比大于3(根据实际门的比例调整)的轮廓,排除方形/圆形的误检区域;
- 限制面积范围:添加面积上限(比如200像素),过滤房间内大面积黄色区域。
2. 结合房间边界的位置校验
门必然位于房间多边形的边界上,而非内部,可修改判断逻辑:
- 计算黄色轮廓的重心点,判断其是否在房间内;
- 检查轮廓的顶点是否靠近房间多边形的边缘(比如距离≤5像素),只有同时满足这两个条件的轮廓才判定为门。
3. 补充门的GeoJSON数据(最优方案)
直接在GeoJSON中添加门的Feature(类型为Polygon或LineString),完全避免颜色检测的误判。示例格式:
{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[x1,y1],[x2,y2],[x3,y3],[x4,y4]] }, "properties": { "roomname": "34", "type": "door" } }
之后直接遍历门的Feature,在图片上绘制颜色即可。
4. 调整形态学操作参数
当前的开运算可能过度处理或不足,可:
- 改用更小的结构元素(比如
Size(3,3)矩形),避免侵蚀门的轮廓; - 添加闭运算,填补门轮廓的微小缺口,提升检测稳定性。
内容的提问来源于stack exchange,提问作者Monisha
相关产品推荐
相关产品推荐

