如何正确使用Graphics处理AForge.IntPoint解决类型转换报错
问题描述
借助AForge的BlobCounter函数实现椭圆对象检测时,调用Graphics类绘制检测结果触发错误,具体报错信息如下:
Argument 2:cannot covert from 'AForge.IntPoint' to 'System.Drawing.PointF'
对应实现代码如下:
namespace blobdnm { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { OpenFileDialog sfd = new OpenFileDialog(); sfd.Filter = "Image Files|*.bmp|All Files|*.*"; sfd.InitialDirectory = "."; if (sfd.ShowDialog() != DialogResult.OK) { return; } pictureBox1.ImageLocation = sfd.FileName; } private void button2_Click(object sender, EventArgs e) { Bitmap bmp = new Bitmap(pictureBox1.Image); BitmapData BmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] data = new byte[bmp.Width*bmp.Height*3]; IntPtr ptr = BmpData.Scan0; Marshal.Copy(ptr, data, 0, data.Length); for (int i = 0; i < bmp.Width*bmp.Height*3; i=i+3) { double a = data[i] * 0.2125 + data[i + 1] * 0.7154 + data[i + 2] *0.0721; if(a>100) { data[i] = 0; data[i+1] = 0; data[i+2] = 0; } } Bitmap bmp2 = new Bitmap(bmp.Width,bmp.Height,PixelFormat.Format24bppRgb); BitmapData BmpData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); Marshal.Copy(data, 0,BmpData2.Scan0, data.Length); bmp2.UnlockBits(BmpData2); ColorFiltering colorFilter = new ColorFiltering(); BlobCounter blobCounter = new BlobCounter(); blobCounter.FilterBlobs = true; blobCounter.MinWidth = 5; blobCounter.MinHeight = 5; blobCounter.MaxWidth = 3000; blobCounter.MaxHeight = 3000; blobCounter.ProcessImage(BmpData2); Blob[] blobs = blobCounter.GetObjectsInformation(); Graphics g = Graphics.FromImage(bmp2); Pen redPen = new Pen(Color.Red, 2); List<IntPoint> edgePoints=null; for (int i = 0; i < blobs.Length; i++) { edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]); for (int k = 0; k < edgePoints.Count; k++) { g.DrawPolygon(redPen, edgePoints[k]); //报错位置 } } redPen.Dispose(); g.Dispose(); pictureBox1.Image = bmp2; } private System.Drawing.Point[] ToPointsArray(List<IntPoint> points) { System.Drawing.Point[] array = new System.Drawing.Point[points.Count]; for (int i = 0, n = points.Count; i < n; i++) { array[i] = new System.Drawing.Point(points[i].X, points[i].Y); } return array; } } }
错误原因
Graphics.DrawPolygon方法的第二个参数要求传入点类型数组(System.Drawing.Point[]或System.Drawing.PointF[]),但代码中循环传入单个AForge.IntPoint对象,参数结构不符合方法要求。- AForge自定义的
IntPoint类型和System.Drawing命名空间下的Point/PointF不存在隐式转换规则,无法直接作为GDI+绘制方法的参数传入。 - 代码中已经实现了
ToPointsArray类型转换方法,但绘制逻辑中未调用该方法做类型适配。 - 额外隐患:加载的原图
bmp调用LockBits后未执行UnlockBits,会引发图像资源锁定问题。
修复方法
- 删除遍历单个边缘点的内层循环,每个Blob的边缘点是一组闭合轮廓,不需要逐个点传入绘制方法。
- 调用已实现的
ToPointsArray方法,将AForge的IntPoint列表转换为System.Drawing.Point数组,再传入DrawPolygon完成绘制。 - 补全原图的
UnlockBits调用,避免资源锁定问题。
修改后的核心代码片段如下:
// 拷贝完图像数组后立刻解锁原图bmp Marshal.Copy(ptr, data, 0, data.Length); bmp.UnlockBits(BmpData); // 补全缺失的解锁调用 // --- 省略中间图像处理逻辑 --- for (int i = 0; i < blobs.Length; i++) { edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]); // 转换点类型后直接传入绘制,删除内层遍历单个点的循环 System.Drawing.Point[] drawPoints = ToPointsArray(edgePoints); g.DrawPolygon(redPen, drawPoints); }
可选优化:将Pen、Graphics、Bitmap等实现了IDisposable接口的对象放入using块中,可自动完成资源释放,避免手动调用Dispose遗漏导致的内存问题。
内容的提问来源于stack exchange,提问作者stck_w
相关产品推荐
相关产品推荐

