我想要的功能是让用户使用鼠标在图像上绘制几个对象的轮廓。显示图像上的轮廓,并能够导出轮廓数据。我在这里使用cyotek.imagebox https://github.com/cyotek/Cyotek.Windows.Forms.ImageBox,这是一个用于显示图像的自定义控件。 这是我的方法。
private List<List<Point>> contours = new List<List<Point>>(); //a list to store all contours
private List<Point> contour_temp= new List<Point>(); //a list to store the contour the user is drawing
private bool mousedown // a flag that change when mouse up/mouse down event is triggered
private void imageBox_MouseDown(object sender, MouseEventArgs e)
{
mousedown = true;
}
private void imageBox_MouseUp(object sender, MouseEventArgs e)
{
mousedown = false;
}
private void imageBox_MouseMove(object sender, MouseEventArgs e)
{
//drawing occurs when mouse is down, a contour is finish drawing when mouse is up
// when a contour finish drawing. it will be added to the contours list and the contour temp will be clear
if (draw_on) // a flag for this function to be active
{
if (contour_temp.Count > 0)
{
if (mousedown)
{
if (imageBox.IsPointInImage(e.Location)) //function cyotek.imagebox provides , it translate the mouse location to pixel location
{
Point p = this.imageBox.PointToImage(e.Location);
if (p != contour_temp[contour_temp.Count - 1])
contour_temp.Add(p);
}
}
else
{
if (contour_temp.Count > 2)
{
contours.Add(contour_temp);
contour_temp.Clear();
}
}
}
else
{
if (mousedown)
{
contour_temp = new List<Point>();
Point p = this.imageBox.PointToImage(e.Location);
contour_temp.Add(p);
}
}
imageBox.Invalidate();
}
}
private void imageBox_Paint(object sender, PaintEventArgs e)
{
//at the painting function, always paint all the contours stored
//if mouse is down, print the temporary contour the user is currently drawing
foreach (List<Point> contour in contours)
{
Point p0 = contour[0];
foreach (Point p1 in contour)
{
e.Graphics.DrawLine(new Pen(Color.Red), imageBox.GetOffsetPoint(p0), imageBox.GetOffsetPoint(p1));//Cyotek.ImageBox provided, get the correct point even after zooming
p0 = p1;
} //draw all contours
}
if(draw_on && mousedown && contour_temp.Count>0)
{
Point p0 = contour_temp[0];
foreach (Point p1 in contour_temp)
{
e.Graphics.DrawLine(new Pen(Color.Green), imageBox.GetOffsetPoint(p0), imageBox.GetOffsetPoint(p1));
p0 = p1;
}// draw the contour user is drawing
}
}
绘制contour_temp部分工作正常。但是当轮廓完成绘制时程序崩溃,在&#39; mscorlib.dll&#39;上抛出System.ArgumentOutOfRangeException, 经过一些测试,我发现绘制所有轮廓的东西都在绘画功能 不知何故错了。我已经对该例外进行了一些研究,称该指数 列表超出范围。但是当我使用&#34; foreach&#34;?
时,怎么会发生这种情况答案 0 :(得分:0)
问题在于这些线路:
contours.Add(contour_temp);
contour_temp.Clear();
在第一种情况下,您要将临时点列表contour_temp
添加到主列表contours
,但由于List<T>
是reference type,您不是添加点的副本,但引用相同列表 - 然后将其清除,导致contours
实际上只包含空列表。但是你的绘图例程希望这些列表总是至少包含一个点,因此在尝试绘制时会ArgumentOutOfRangeException
,因为你试图获得列表中没有项目的第一个项目。
我通过将第一行更改为
来修复您的演示程序contours.Add(new List<Point>(contour_temp));
这将创建列表的副本,从而保留点。我用这个校正测试了你的演示程序,它运行良好。
希望这会有所帮助。并感谢您使用ImageBox!