C# AForge BlobCounter形状检测索引越界异常修复方案
AForge BlobCounter形状检测索引越界异常修复
运行基于AForge库BlobCounter组件编写的形状检测代码,尝试统计物体边缘像素总数时,在shapeChecker.IsConvexPolygon(edgePoints, out corners)行抛出异常:
System.ArgumentOutOfRangeException: 'Index was out of range. It must not be a negative value and must be smaller than the size of the collection.'
异常原因
- Blob过滤阈值设置不合理:
MinWidth=1、MinHeight=1、MaxWidth=8、MaxHeight=8的配置会筛选出大量尺寸极小的噪点Blob,这类Blob提取出的边缘点数量不足3个。IsConvexPolygon方法要求传入的边缘点集合至少包含3个有效点才能构成多边形,点数量不足时内部访问集合索引就会触发越界。 - 锁位操作存在错误:第一次调用
LockBits锁定BmpData1后未做任何操作就直接解锁,属于冗余代码;灰度、阈值处理后生成的是8位灰度图,第二次锁位时错误指定PixelFormat.Format24bppRgb格式,会导致内存读取错位,提取的边缘点数据异常。 - 缺少入参校验:未对提取到的边缘点集合做有效性判断,直接传入形状检测方法,空集合或点数量不足的集合会直接触发内部逻辑错误。
- 冗余的颜色过滤操作:阈值处理后已经得到二值图,再调用RGB三通道颜色过滤属于无效操作,还可能破坏已经处理好的二值数据。
修复方案
- 调整Blob过滤阈值,过滤过小噪点,修正锁位时的像素格式参数,删除冗余的无效锁位、颜色过滤代码。
- 在调用形状检测方法前增加边缘点、角点的数量校验,点数量不足3个无法构成多边形,直接跳过当前Blob避免越界。
- 若需要统计物体边缘像素总数,直接读取
edgePoints.Count属性即可,该集合存储的就是BlobCounter提取的所有边缘像素坐标。
修改后的核心代码如下:
private void button2_Click(object sender, EventArgs e) { Bitmap bmp = new Bitmap(pictureBox1.Image); // 删除冗余的第一次无效LockBits操作 Grayscale gfilter = new Grayscale(0.2125, 0.7154, 0.0721); Invert ifilter = new Invert(); BradleyLocalThresholding thfilter = new BradleyLocalThresholding(); bmp = gfilter.Apply(bmp); thfilter.ApplyInPlace(bmp); ifilter.ApplyInPlace(bmp); // 8位灰度图锁位需指定匹配的像素格式,不能使用24位RGB格式 BitmapData BmpData2 = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); BlobCounterBase blobCounter = new BlobCounter(); blobCounter.FilterBlobs = true; // 调整Blob尺寸阈值过滤噪点,可根据实际检测目标大小调整数值 blobCounter.MinWidth = 10; blobCounter.MinHeight = 10; blobCounter.MaxWidth = bmp.Width; blobCounter.MaxHeight = bmp.Height; // 二值化后无需做RGB通道颜色过滤,删除冗余ColorFilter逻辑 blobCounter.ProcessImage(BmpData2); bmp.UnlockBits(BmpData2); Blob[] blobs = blobCounter.GetObjectsInformation(); SimpleShapeChecker shapeChecker = new SimpleShapeChecker(); Bitmap bmp3 = new Bitmap(bmp.Width, bmp.Height); Graphics g = Graphics.FromImage(bmp3); Pen redPen = new Pen(Color.Red, 2); Pen brownPen = new Pen(Color.Brown, 2); Pen greenPen = new Pen(Color.Green, 2); Pen bluePen = new Pen(Color.Blue, 2); for (int i = 0; i < blobs.Length; i++) { List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]); // 新增前置校验:边缘点不足3个无法构成多边形,直接跳过 if (edgePoints == null || edgePoints.Count < 3) { continue; } List<IntPoint> corners; if (shapeChecker.IsConvexPolygon(edgePoints, out corners)) { // 校验角点数量,避免后续绘制多边形出错 if (corners == null || corners.Count < 3) { continue; } PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners); Pen pen; if (subType == PolygonSubType.Unknown) { pen = (corners.Count == 4) ? redPen : bluePen; } else { pen = (corners.Count == 4) ? brownPen : greenPen; } g.DrawPolygon(pen, ToPointsArray(corners)); } } redPen.Dispose(); greenPen.Dispose(); bluePen.Dispose(); brownPen.Dispose(); g.Dispose(); Clipboard.SetDataObject(bmp3); pictureBox1.Image = bmp3; }
内容的提问来源于stack exchange,提问作者stck_w
相关产品推荐
相关产品推荐

