基于OpenCV & EmguCV的黑色矩形检测及真实位置计算求助
先让Emgu CV形状检测示例跑通的核心排查点
- 版本与平台对齐:用NuGet安装对应版本的
Emgu.CV和运行时包(如Emgu.CV.runtime.windows),项目平台设为x64(禁用Any CPU),确保和运行时包架构匹配——版本不兼容是最常见的失效原因。 - 补全必要引用:代码中必须包含这些命名空间:
using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using Emgu.CV.Util; - 调优轮廓检测参数:
- 调整
Canny边缘检测的高低阈值(比如从50, 150开始测试,亮图调高、暗图调低),边缘检测失效会直接导致轮廓丢失。 - 修改
ApproxPolyDP的epsilon系数(示例默认0.04,可在0.02~0.05区间调整),该参数决定轮廓近似精度,系数错误会导致矩形被识别为其他形状。 - 使用
RetrType.External模式查找轮廓,过滤内部杂轮廓,只保留最外层形状。
- 调整
适配黑色矩形检测的关键调整
示例跑通后,针对你的黑色矩形测试图做以下修改:
- 反向二值化预处理:黑色矩形属于暗区域,转灰度后做反向二值化,让矩形变为白色前景、背景变黑,大幅降低轮廓检测难度:
Mat gray = new Mat(); CvInvoke.CvtColor(inputImage, gray, ColorConversion.Bgr2Gray); Mat binary = new Mat(); // 阈值根据图像亮度调整,低于阈值的黑色区域转为白色 CvInvoke.Threshold(gray, binary, 50, 255, ThresholdType.BinaryInv); - 形态学消噪:若矩形边缘有碎点或空洞,用闭运算消除噪点、填充缝隙:
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3,3)); CvInvoke.MorphologyEx(binary, binary, MorphOp.Close, kernel); - 严格矩形验证:检测到4顶点轮廓后,增加角度校验,确保四个角为接近90度的直角,避免误判梯形或不规则四边形:
private bool IsRectangle(List<Point> points) { for (int i = 0; i < 4; i++) { var p1 = points[i]; var p2 = points[(i+1)%4]; var p3 = points[(i+2)%4]; // 向量点积计算夹角 var v1 = new System.Numerics.Vector2(p1.X - p2.X, p1.Y - p2.Y); var v2 = new System.Numerics.Vector2(p3.X - p2.X, p3.Y - p2.Y); var dot = System.Numerics.Vector2.Dot(v1, v2); var mag = v1.Length() * v2.Length(); var cosTheta = dot / mag; var angle = Math.Acos(cosTheta) * 180 / Math.PI; // 允许5度误差范围 if (Math.Abs(angle - 90) > 5) return false; } return true; }
真实世界位置计算的核心步骤
拿到矩形的四个像素坐标后,结合相机标定数据计算真实位置:
- 准备世界坐标点:已知矩形真实宽高为W、H,将左下角设为原点,四个角的世界坐标为
(0,0,0)、(W,0,0)、(W,H,0)、(0,H,0)。 - 调用
SolvePnP求解位姿:// cameraMatrix和distCoeffs为相机标定得到的内参矩阵与畸变系数 Mat cameraMatrix = new Mat(3, 3, DepthType.Cv64F); Mat distCoeffs = new Mat(5, 1, DepthType.Cv64F); // 填充你的相机标定数据... var objectPoints = new VectorOfPoint3D32f( new Point3D32f(0,0,0), new Point3D32f(W,0,0), new Point3D32f(W,H,0), new Point3D32f(0,H,0) ); var imagePoints = new VectorOfPoint2D32f(rectanglePixelPoints); Mat rvec = new Mat(); // 旋转向量 Mat tvec = new Mat(); // 平移向量 CvInvoke.SolvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec); - 平移向量
tvec中的数值即为矩形在世界坐标系中的X、Y、Z位置。
内容的提问来源于stack exchange,提问作者s4rge
相关产品推荐
相关产品推荐

