使用Cyotek.ImageBox

时间:2017-10-06 20:15:16

标签: c# image winforms draw

我想要的功能是让用户使用鼠标在图像上绘制几个对象的轮廓。显示图像上的轮廓,并能够导出轮廓数据。我在这里使用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;?

时,怎么会发生这种情况

1 个答案:

答案 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!