从两点裁剪图像(C#)

Posted

技术标签:

【中文标题】从两点裁剪图像(C#)【英文标题】:Crop image out of two points (C#) 【发布时间】:2015-10-13 13:43:24 【问题描述】:

更新:

添加了更新的代码。

但由于某种原因,它仍然无法正常工作。如果坐标是位图坐标,可能是什么原因?我放在这里的第一个代码示例不能正常工作,第二个给我一个 OutOfMemoryException。

我在尝试裁剪两点之间的图像时遇到了问题。在我的项目中,我有一个图片框(名为 AP),一般的想法是用户单击两个点,程序会在这两个角之间裁剪图像。我尝试了两种方法,一种使用 Bitmap.Crop,另一种使用 Graphics.DrawImage,但两种方法似乎都因相同的原因而失败并且根本不起作用(裁剪了图像的一小部分)。

代码:

    private void AP_Click(object sender, EventArgs e)
    
        // Setting the corners
        else if (mark_shape == 0)
        
            var mouseEventArgs = e as MouseEventArgs;
            if (picture_corners_set == 0)
            
                northEast = AP.PointToClient(new Point(mouseEventArgs.X, mouseEventArgs.Y));
                picture_corners_set = 1;
            
            else if (picture_corners_set == 1)
            
                southWest = AP.PointToClient(new Point(mouseEventArgs.X, mouseEventArgs.Y));
                Rectangle imageRectangle = new Rectangle(southWest.X, northEast.Y, (northEast.X - southWest.X), (southWest.Y - northEast.Y));
                var bmp = new Bitmap(imageRectangle.Width, imageRectangle.Height);
                using (var gr = Graphics.FromImage(bmp))
                
                    gr.DrawImage(AP.Image, 0, 0, imageRectangle, GraphicsUnit.Pixel);
                
                AP.Image = bmp;
                enableAllButtons();
            
        
    

【问题讨论】:

点坐标是相对于屏幕、表单还是图片框? 到屏幕上,我想;我将它们初始化为 northEast = new Point(mouseEventArgs.X, mouseEventArgs.Y); 由于位图裁剪坐标是相对于位图的,您是否将鼠标坐标从屏幕坐标转换为客户端(图片框)坐标? Picturebox.PointToClient 将屏幕坐标转换为客户端(控制)坐标,参见msdn.microsoft.com/en-us/library/… 我会避免在构造函数中嵌套太多调用(使事情变得困难),但是是的,类似的事情。将这两个点转换为TopLeft.X/YBottomRight.X/Y。请注意,PointToScreen 采用 Point,而不仅仅是单个 x 或 y 值。 【参考方案1】:

由于您裁剪的位图图像大小与用户选择的宽度/高度相同,我猜您希望该裁剪图像位于新位图的顶部/左侧并填充它。实际上,您是在告诉 DrawImage() 方法在同一位置绘制位图的该部分,尽管位图尺寸较小。

这样做的正确方法是在 (0, 0) 处绘制源矩形图像:

    private Point pt1, pt2;

    private void AP_Click(object sender, EventArgs e)
    

        // ... obviously other code here ...            

        else if (mark_shape == 0) // Setting the corners
        
            Point pt = AP.PointToClient(Cursor.Position);
            if (picture_corners_set == 0)
            
                pt1 = new Point(pt.X, pt.Y);
                picture_corners_set = 1;
            
            else if (picture_corners_set == 1)
            
                pt2 = new Point(pt.X, pt.Y);
                picture_corners_set = 0;

                Rectangle imageRectangle = new Rectangle(new Point(Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y)), new Size(Math.Abs(pt2.X - pt1.X) + 1, Math.Abs(pt2.Y - pt1.Y) + 1));
                var bmp = new Bitmap(imageRectangle.Width, imageRectangle.Height);
                using (var gr = Graphics.FromImage(bmp))
                
                    gr.DrawImage(AP.Image, 0, 0, imageRectangle, GraphicsUnit.Pixel);
                
                AP.Image = bmp;
                enableAllButtons();
            
        
    

您可以使用其他几个重载来执行此操作,但上面的一个非常清楚地表明 imageRectangle 是在 (0, 0) 处绘制的。

【讨论】:

感谢您的回复,我已经使用 PointToClient 转换了坐标,但它仍然会占用图像的一小部分并对其进行拉伸。我注意到图像的宽度和高度实际上大于我的屏幕分辨率——这可能是个问题吗?我的电脑是1366*768,高1280,宽1832... 使用您用来设置积分的事件代码更新您的原始帖子。

以上是关于从两点裁剪图像(C#)的主要内容,如果未能解决你的问题,请参考以下文章

c# 自动裁剪图像

如何在c#中用多边形裁剪图像

通过在 C# 中切割边缘从图像中提取对象

使用 C# 裁剪图像

使用 c# 在 Windows Store App 中裁剪和保存图像(UIElement)

如何使用 C# 裁剪图像?