最小外接矩形
最小外接矩形一、技术背景最小外接矩形Bounding Rectangle是包围目标轮廓的最小矩形区域。在SEM图像分析中最小外接矩形用于测量目标的宽度和高度确定目标的空间位置计算目标的长宽比OpenCV提供两种最小外接矩形正交外接矩形边界与图像坐标轴对齐的矩形旋转外接矩形可任意角度旋转的最小面积矩形二、数学原理2.1 正交外接矩形BoundingRect正交外接矩形定义为R[xmin,ymin,w,h]R [x_{min}, y_{min}, w, h]R[xmin,ymin,w,h]其中xminminixix_{min} \min_{i} x_ixminminixi最小x坐标yminminiyiy_{min} \min_{i} y_iyminminiyi最小y坐标wxmax−xminw x_{max} - x_{min}wxmax−xmin宽度hymax−yminh y_{max} - y_{min}hymax−ymin高度2.2 旋转外接矩形minAreaRect旋转外接矩形是面积最小的外接矩形通过遍历所有可能的角度求解minθA(θ)\min_{\theta} A(\theta)θminA(θ)其中A(θ)A(\theta)A(θ)为角度θ\thetaθ时的外接矩形面积。2.3 算法原理正交外接矩形计算所有点的x、y极值复杂度O(n)O(n)O(n)旋转外接矩形基于凸包计算使用旋转卡壳算法复杂度O(nlogn)O(n \log n)O(nlogn)2.4 参数说明类型返回值参数含义BoundingRectRectx, y, width, heightminAreaRectRotatedRectcenter, size, angle三、代码实现3.1 MainForm中的正交外接矩形文件路径:e:\SEM\Forms\MainForm.cs// 正交外接矩形计算for(inti0;iprocessingImageInfo.contours.Length;i){varcountourprocessingImageInfo.contours[i];doublearea_pxCv2.ContourArea(countour);if(area_px200){// 正交外接矩形RectbboxCv2.BoundingRect(countour);// 单位换算像素 → μmvarmetricnewimageUtils.ContourMetric{Indexi1,Area_um2areaUm2,Perimeter_umperi_um,BBoxX_umbbox.X,BBoxY_umbbox.Y,BBoxWidth_umMath.Round(bbox.Width*umPerPixel,2),BBoxHeight_umMath.Round(bbox.Height*umPerPixel,2)};processingImageInfo.ContourMetrics.Add(metric);}}3.2 报告导出中的应用文件路径:e:\SEM\Forms\MainForm.cs// 报告导出中的外接矩形参数for(inti0;iinfo.contours.Length;i){varcontourinfo.contours[i];// 面积过滤doubleareaThreshold200*areaPixelToUm2;if(areaareaThreshold)continue;// 正交外接矩形RectbboxCv2.BoundingRect(contour);// 单位换算后的参数doublewidth_umbbox.Width*umPerPixel;doubleheight_umbbox.Height*umPerPixel;varrownewListstring{Path.GetFileName(imgPath),area.ToString(F2),bbox.X.ToString(),bbox.Y.ToString(),(bbox.Width*umPerPixel).ToString(),(bbox.Height*umPerPixel).ToString(),// ... 其他参数};}3.3 硬垫分割中的外接矩形文件路径:e:\SEM\Forms\MainForm.cs// 硬垫分割结果处理for(inti0;iprocessingImageInfo.contours.Length;i){varcontourprocessingImageInfo.contours[i];doublearea_pxCv2.ContourArea(contour);if(area_px200){// 正交外接矩形RectbboxCv2.BoundingRect(countour);// 椭圆拟合如果点数足够if(contour.Length5){RotatedRectellipseCv2.FitEllipse(contour);}varmetricnewimageUtils.ContourMetric{Indexi1,Area_um2area_um2,Perimeter_umperi_um,BBoxX_umbbox.X,BBoxY_umbbox.Y,BBoxWidth_umMath.Round(bbox.Width*umPerPixel,2),BBoxHeight_umMath.Round(bbox.Height*umPerPixel,2)};processingImageInfo.ContourMetrics.Add(metric);}}3.4 ContourMetric结构体文件路径:e:\SEM\Utils\imageUtils.cspublicclassContourMetric{publicintIndex{get;set;}publicdoubleArea_um2{get;set;}publicdoublePerimeter_um{get;set;}publicdoubleBBoxX_um{get;set;}// 外接矩形左上角XpublicdoubleBBoxY_um{get;set;}// 外接矩形左上角YpublicdoubleBBoxWidth_um{get;set;}// 外接矩形宽度publicdoubleBBoxHeight_um{get;set;}// 外接矩形高度publicdoubleMajorAxis_um{get;set;}publicdoubleMinorAxis_um{get;set;}publicdoubleAngle_deg{get;set;}}四、参数调优4.1 单位换算文件路径:e:\SEM\Methods\MicroscopeScale.cs// 放大倍率与像素尺寸对应MicroscopeScalescaleToolnewMicroscopeScale();intmagnification200;doubleumPerPixelscaleTool.GetUmPerPixel(magnification);// 宽度像素 → μmdoublewidth_umbbox.Width*umPerPixel;// 高度像素 → μmdoubleheight_umbbox.Height*umPerPixel;4.2 放大倍率对应关系放大倍数μm/pixel说明X60~2.5每像素约2.5μmX100~1.58每像素约1.58μmX200~0.79每像素约0.79μm4.3 测量精度影响测量精度的因素图像分辨率放大倍率标定精度轮廓检测精度提高精度方法// 方法1使用高分辨率// 方法2亚像素边缘检测// 方法3多次测量取平均五、常见问题Q1: BoundingRect与minAreaRect的区别对比项BoundingRectminAreaRect方向固定与坐标轴对齐可旋转面积较大最小计算速度快O(n)O(n)O(n)较慢O(nlogn)O(n \log n)O(nlogn)适用场景快速定位精确测量示例对斜椭圆BoundingRect面积较大包含空白区域minAreaRect面积最小紧密包围Q2: 如何选择使用哪种外接矩形选择依据快速筛选使用BoundingRect精确测量使用minAreaRect方向分析使用minAreaRect获取角度Q3: 外接矩形的坐标原点在哪里OpenCV图像坐标系原点左上角X轴向右为正Y轴向下为正外接矩形的(x,y)(x, y)(x,y)表示左上角坐标。Q4: 如何计算长宽比RectbboxCv2.BoundingRect(contour);// 正交外接矩形的长宽比doubleaspectRatio(double)bbox.Width/bbox.Height;// 或者使用minAreaRectRotatedRectminRectCv2.MinAreaRect(contour);doublemajorAxisMath.Max(minRect.Size.Width,minRect.Size.Height);doubleminorAxisMath.Min(minRect.Size.Width,minRect.Size.Height);doubleaspectRatiomajorAxis/minorAxis;Q5: 外接矩形参数如何转换单位单位换算公式长度μm长度pixel×umPerPixel\text{长度}_{\mu m} \text{长度}_{pixel} \times \text{umPerPixel}长度μm长度pixel×umPerPixel面积μm2面积pixel2×(umPerPixel)2\text{面积}_{\mu m^2} \text{面积}_{pixel^2} \times (\text{umPerPixel})^2面积μm2面积pixel2×(umPerPixel)2// 长度换算doublewidth_umbbox.Width*umPerPixel;doubleheight_umbbox.Height*umPerPixel;// 坐标换算如果需要实际位置doublex_umbbox.X*umPerPixel;doubley_umbbox.Y*umPerPixel;Q6: 如何绘制外接矩形// 绘制正交外接矩形RectbboxCv2.BoundingRect(contour);Cv2.Rectangle(image,bbox,newScalar(0,255,0),2);// 绘制旋转外接矩形RotatedRectminRectCv2.MinAreaRect(contour);Point[]verticesCv2.BoxPoints(minRect).Select(pnewPoint((int)p.X,(int)p.Y)).ToArray();for(inti0;i4;i){Cv2.Line(image,vertices[i],vertices[(i1)%4],newScalar(255,0,0),2);}// 同时绘制两种矩形对比效果Cv2.Rectangle(image,bbox,newScalar(0,255,0),1);// 绿色正交矩形Cv2.Polylines(image,new[]{vertices},true,newScalar(0,0,255),2);// 红色旋转矩形