WinForm使用鼠标裁剪图像

之前做一个试卷识别的项目的时候需要预先将各个部分裁剪开然后进行识别,而网上的裁剪函数都是记录鼠标的位置然后进行裁剪

public static Bitmap PartDraw(Image src, Rectangle cutpart)//切割图片
        {
            Bitmap rectbmp = new Bitmap(cutpart.Width, cutpart.Height, PixelFormat.Format24bppRgb);
            using (Graphics g = Graphics.FromImage(rectbmp))
            {
                g.DrawImage(src, new Rectangle(0, 0, cutpart.Width, cutpart.Height), cutpart, GraphicsUnit.Pixel);
                g.Dispose();
            }
            return rectbmp;
        }

但是这样做又带来了一个问题就是如果图片是zoom了的那么鼠标的位置和实际图像的位置就会出现偏移,导致实际截图的位置和你想截图的位置完全不一样。

最后采用了坐标比例换算的方法解决了这个问题。

本方法主要关联四个图片控件的事件

坐标换算的原型函数如下

int originalWidth = this.PicSource.Image.Width;
            int originalHeight = this.PicSource.Image.Height;

            PropertyInfo rectangleProperty = this.PicSource.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
            Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(this.PicSource, null);

            int currentWidth = rectangle.Width;
            int currentHeight = rectangle.Height;

            double rate = (double)currentHeight / (double)originalHeight;

            int black_left_width = (currentWidth == this.PicSource.Width) ? 0 : (this.PicSource.Width - currentWidth) / 2;
            int black_top_height = (currentHeight == this.PicSource.Height) ? 0 : (this.PicSource.Height - currentHeight) / 2;

            int zoom_x = e.X - black_left_width;
            int zoom_y = e.Y - black_top_height;

            double original_x = (double)zoom_x / rate;
            double original_y = (double)zoom_y / rate;

可以使用实际坐标来换算得出源坐标

所用到的全局变量如下

        bool blnDraw;
        Point start; //画框的起始点
        Rectangle rect;
        Point Pstart; //原图的起始点
        Rectangle Orect;//在原图中尺寸

然后为图片控件添加以下事件

 

private void PicSource_MouseDown(object sender, MouseEventArgs e)
        {
            int originalWidth = this.PicSource.Image.Width;
            int originalHeight = this.PicSource.Image.Height;

            PropertyInfo rectangleProperty = this.PicSource.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
            Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(this.PicSource, null);

            int currentWidth = rectangle.Width;
            int currentHeight = rectangle.Height;

            double rate = (double)currentHeight / (double)originalHeight;

            int black_left_width = (currentWidth == this.PicSource.Width) ? 0 : (this.PicSource.Width - currentWidth) / 2;
            int black_top_height = (currentHeight == this.PicSource.Height) ? 0 : (this.PicSource.Height - currentHeight) / 2;

            int zoom_x = e.X - black_left_width;
            int zoom_y = e.Y - black_top_height;

            double original_x = (double)zoom_x / rate;
            double original_y = (double)zoom_y / rate;

            Pstart = new Point((int)original_x, (int)original_y);

            start = e.Location;
            Invalidate();
            blnDraw = true;
        }
private void PicSource_MouseMove(object sender, MouseEventArgs e)
        {
            if (blnDraw)
            {
                if (e.Button != MouseButtons.Left)//判断是否按下左键
                    return;
                Point tempEndPoint = e.Location; //记录框的位置和大小
                rect.Location = new Point(
                Math.Min(start.X, tempEndPoint.X),
                Math.Min(start.Y, tempEndPoint.Y));
                rect.Size = new Size(
                Math.Abs(start.X - tempEndPoint.X),
                Math.Abs(start.Y - tempEndPoint.Y));
                //记录绘制大小

                int originalWidth = this.PicSource.Image.Width;
                int originalHeight = this.PicSource.Image.Height;

                PropertyInfo rectangleProperty = this.PicSource.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
                Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(this.PicSource, null);

                int currentWidth = rectangle.Width;
                int currentHeight = rectangle.Height;

                double rate = (double)currentHeight / (double)originalHeight;

                int black_left_width = (currentWidth == this.PicSource.Width) ? 0 : (this.PicSource.Width - currentWidth) / 2;
                int black_top_height = (currentHeight == this.PicSource.Height) ? 0 : (this.PicSource.Height - currentHeight) / 2;

                int zoom_x = e.X - black_left_width;
                int zoom_y = e.Y - black_top_height;

                double original_x = (double)zoom_x / rate;
                double original_y = (double)zoom_y / rate;

                Orect.Location = new Point(
                Math.Min(Pstart.X, (int)original_x),
                Math.Min(Pstart.Y, (int)original_y));
                Orect.Size = new Size(
                Math.Abs(Pstart.X - (int)original_x),
                Math.Abs(Pstart.Y - (int)original_y));

                PicSource.Invalidate();

            }
        }
private void PicSource_MouseUp(object sender, MouseEventArgs e)
        {
            blnDraw = false; //结束绘制
        }
private void PicSource_Paint(object sender, PaintEventArgs e)
        {
            if (blnDraw)
            {
                if (PicSource.Image != null)
                {
                    if (rect != null && rect.Width > 0 && rect.Height > 0)
                    {
                        e.Graphics.DrawRectangle(new Pen(Color.Red, 3), rect);//重新绘制颜色为红色
                    }
                }
            }
        }

最后效果如图

在Windows Form应用程序中,你可以使用.NET Framework的GDI+库来通过鼠标事件来绘制矩形。下面是一个简单的步骤说明: 1. **事件处理**:首先,你需要在Form上设置一个鼠标按下、移动和释放的事件处理器。可以使用MouseDown、MouseMove和MouseUp事件。 ```csharp private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { // 开始绘制 } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { // 移动鼠标时更新矩形位置 } private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { // 鼠标抬起结束绘制 } ``` 2. **初始状态**:在MouseDown事件中,记录下鼠标按下时的位置和形状信息。例如,创建一个Point用于存储初始点和一个Rectangle表示初始矩形。 3. **绘制过程**:在MouseMove事件中,每次鼠标移动,更新Rectangle的位置和大小。通常会在PictureBox或其他容器控件中画线,因为它们支持绘画操作。 4. **结束绘制**:当鼠标在PictureBox上抬起(MouseUp)时,根据鼠标的最后位置停止画线,并可能清空绘图区,如果需要的话。 5. **实际绘制**:使用Graphics对象的DrawRectangle方法来绘制矩形,它接受Pen对象(颜色和宽度)、Rectangle对象以及填充模式作为参数。 示例代码片段(简化版): ```csharp private Point startPoint; private Rectangle rect; private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { startPoint = e.Location; rect = new Rectangle(startPoint, Size.Empty); } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { rect.Width = e.X - startPoint.X; rect.Height = e.Y - startPoint.Y; pictureBox1.Invalidate(); } } private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { pictureBox1.Invalidate(); startPoint = Point.Empty; // 清除起点 } ``` 记得要在pictureBox1_Paint事件中处理绘制: ```csharp private void pictureBox1_Paint(object sender, PaintEventArgs e) { using (var pen = new Pen(Color.Black)) { e.Graphics.DrawRectangle(pen, rect); } } ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值