在图像上画线 [英] Draw lines on the image

查看:64
本文介绍了在图像上画线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我需要在图像上绘制线条,即可以拖动.通过单击任意行,我应该能够沿着图像移动该特定行,并最终用行保存图像.

我正在使用Windows窗体和图片框.

请帮助

Hi,

I need to draw lines on the image which can be dragable, ie. by clicking on any line, I should be able to move that particular line along the image and finally save the image with lines.

I am using windows Form and picture box.

Please help

推荐答案

这不是一个简单的问题,它分为两个部分:
在图像上进行绘制并保存:容易,只需为图像获得一个Graphics对象,绘制线条并保存文件即可:
That is not a simple question, it has two parts:
Drawing on an Image, and saving it: Easy, just get a Graphics object for the image, draw your lines, and save the file:
using (Graphics g = Graphics.FromImage(myImage))
    {
    g.DrawLine(pen, new Point(0, 0), new Point(myImage.Width, myImage.Height));
    }
myImage.Save(@"F:\temp\myimage.jpg", ImageFormat.Jpeg);


第二部分比较复杂:
您如何绘制可移动的线条?
您将必须处理PictureBox Paint事件,并记住行的位置.
您将不得不处理PictureBox鼠标事件,并检测您是在现有的行中还是在新的行中-仅在末端接起它们可能比尝试计算出一条行要容易得多通过在中间捡起来.

我不会在这里尝试为您提供说明:快速答案远远不止于此.

Google提供了有关WinForms的基本图形,并按照您可以找到的所有教程或其他说明进行操作.


The second part is more complex:
How do you draw moveable lines?
You will have to handle the PictureBox Paint event, and remember where your lines are.
You will have to handle the PictureBox mouse events, and detect if you are on an existing line, or a new line - it is probably easier to pick them up at the ends only, rather than trying to work out if you are on a line by picking it up in the middle.

I''m not going to try and give you instructions for that here: it is far to much for a quick answer.

Google for basic drawing on WinForms, and follow any tutorial or other instructions you can find.


OriginalGriff回答了第一部分.我将提出第二个想法.

我以为这些线是垂直线,每条线的x位数存储在xLines数组中.
在表单中还添加一个成员int selectedLineIndex;来存储当前行索引.

在您的表单构造函数中,为您的PictureBox添加以下处理程序:
OriginalGriff answered the first part. I will give the idea for the second one.

I supposed the lines are vertical lines, and the x potisions for each line are stored in an xLines array.
Add also a member int selectedLineIndex; in your form to store the current line index.

In your form constructor, add the following handlers for your PictureBox:
//paint handler
pictureBox1.Paint += (sender, e) =>
{
    foreach (int x in xLines)
    {
        //draw the line
        e.Graphics.DrawLine(Pens.Red, x, 0, x, pictureBox1.Height);
    }
};
//mouse down handler
//this function will update selectedLineIndex
pictureBox1.MouseDown += (sender, e) =>
{
    //find the closest line from the current mouse position
    int minDistance = int.MaxValue;
    selectedLineIndex = 0;
    for (int k = 0; k < xLines.Length; k++)
    {
        int dist = Math.Abs(e.X - xLines[k]);
        if (dist < minDistance)
        {
            minDistance = dist;
            selectedLineIndex = k;
        }
    }
};
//mouse move handler
pictureBox1.MouseMove += (sender, e) =>
{
    //if the left button is not clicked, exit
    if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left)
        return;
    //update the selected line position
    xLines[selectedLineIndex] = e.X;
    //redraw the picture box
    pictureBox1.Invalidate();
};



------------------------------------------------

处理水平线和垂直线:



------------------------------------------------

To handle both horizontal and vertical lines:

public partial class Form1 : Form
{
   int[] xLines;
   int[] yLines;
   int selectedLineIndex;
   //true to move vertical lines, false to move horizontal lines
   bool xline = false;

   public Form1()
   {
       InitializeComponent();

       int xmid = pictureBox1.Width / 2;
       int ymid = pictureBox1.Height / 2;
       xLines = new int[] { xmid, xmid / 2 };
       yLines = new int[] { ymid, ymid / 2 };
   }

   private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
   {
       //find the closest vertical line from the current mouse position
       int xminDistance = int.MaxValue;
       int xSelectedLineIndex = 0;
       for (int i = 0; i < xLines.Length; i++)
       {
           int dist = Math.Abs(e.X - xLines[i]);
           if (dist < xminDistance)
           {
               xminDistance = dist;
               xSelectedLineIndex = i;
           }
       }
       //find the closest horizontal line from the current mouse position
       int yminDistance = int.MaxValue;
       int ySelectedLineIndex = 0;
       for (int i = 0; i < yLines.Length; i++)
       {
           int dist = Math.Abs(e.Y - yLines[i]);
           if (dist < yminDistance)
           {
               yminDistance = dist;
               ySelectedLineIndex = i;
           }
       }
       //keep the closest line
       if (xminDistance < yminDistance)
       {
           selectedLineIndex = xSelectedLineIndex;
           xline = true;
       }
       else
       {
           selectedLineIndex = ySelectedLineIndex;
           xline = false;
       }
   }
   private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
   {
       //if the left button is not clicked, exit
       if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left)
           return;
       //update the selected line position
       if (xline)
           xLines[selectedLineIndex] = e.X;
       else
           yLines[selectedLineIndex] = e.Y;
       //redraw the picture box
       pictureBox1.Invalidate();
   }
}


有多种方法可以实现这一点,我将寻求一种解决方案,其中存储一个Line 个对象的列表,并在PictureBox.
这样可以轻松移动和更改所有线条的样式.

保存图像非常简单,Image上有一个Save方法.

您可以尝试像这样扩展PictureBox,这是一个有效的示例;



There are various ways to achieve this, I would go for a solution where you store a list of Line objects and render them after the base render pass of the PictureBox.
This would make it easy to move and change the style of all lines.

To save a image is fairly simple, there''s a Save method on Image.

You could try extending PictureBox like this, this is a working example;



using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace LinesTest
{
    public class LinedPictureBox : PictureBox
    {
        private IList<Line> lines = new List<Line>();
        private Line currentLine = null;
        private bool holdsA = false;
        public LinedPictureBox()
        {
            DoubleBuffered = true;
            MouseDown += HandleMouseDown;
            MouseMove += HandleMouseMove;
            MouseUp += (s, e) => currentLine = null;
        }
        private static int GetDistance(Point a, Point b)
        {
            int dx = a.X - b.X;
            int dy = a.Y - b.Y;
            return (int)Math.Sqrt(dx * dx + dy * dy);
        }
        private void HandleMouseMove(object sender, MouseEventArgs e)
        {
            if (currentLine != null)
            {
                if (holdsA)
                    currentLine.A = e.Location;
                else
                    currentLine.B = e.Location;
                Invalidate();
            }
        }
        private void HandleMouseDown(object sender, MouseEventArgs e)
        {
            Line aLine = (from line in lines orderby GetDistance(line.A, e.Location) select line).FirstOrDefault();
            Line bLine = (from line in lines orderby GetDistance(line.B, e.Location) select line).FirstOrDefault();
            if (aLine != null && bLine != null)
            {
                int aDistance = GetDistance(aLine.A, e.Location);
                int bDistance = GetDistance(bLine.B, e.Location);
                if (Math.Min(aDistance, bDistance) < 8)
                {
                    if (aDistance < bDistance)
                    {
                        currentLine = aLine;
                        holdsA = true;
                    }
                    else
                    {
                        currentLine = bLine;
                        holdsA = false;
                    }
                    return;
                }
            }
            currentLine = new Line { A = e.Location, B = e.Location, Pen = Pens.Red };
            holdsA = false;
            lines.Add(currentLine);
            Invalidate();
        }
        private void PaintLines(Graphics graphics)
        {
            foreach (Line line in lines)
                graphics.DrawLine(line.Pen, line.A, line.B);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            PaintLines(e.Graphics);
        }
        public void Save(string filename)
        {
            Image image = new Bitmap(Width, Height);
            Graphics graphics = Graphics.FromImage(image);
            switch (SizeMode)
            {
                case PictureBoxSizeMode.AutoSize:
                case PictureBoxSizeMode.Normal:
                    graphics.DrawImage(Image, new Point());
                    break;
                case PictureBoxSizeMode.StretchImage:
                    graphics.DrawImage(Image, new Rectangle(0, 0, Width, Height), new Rectangle(0, 0, Image.Width, Image.Height), GraphicsUnit.Pixel);
                    break;
                case PictureBoxSizeMode.CenterImage:
                    {
                        int x = Math.Max(0, (Image.Width - Width) / 2);
                        int y = Math.Max(0, (Image.Height - Height) / 2);
                        graphics.DrawImage(Image, new Rectangle(0, 0, Width, Height), new Rectangle(x, y, Width, Height), GraphicsUnit.Pixel);
                    }
                    break;
            }
            PaintLines(graphics);
            image.Save(filename);
        }
    }
    public class Line
    {
        public Point A { get; set; }
        public Point B { get; set; }
        public Pen Pen { get; set; }
    }
}



希望这会有所帮助,
弗雷德里克(Fredrik)



Hope this helps,
Fredrik


这篇关于在图像上画线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆