使用 C# 裁剪图像的特定区域






4.64/5 (32投票s)
通用的图像裁剪 GUI。
介绍
首先,我必须解释为什么我们需要这种方法来裁剪图像。我准备并编码了这个简单的应用程序 GUI,以满足我的 需求,因为在我们的大项目中,我们需要关注我们感兴趣的图像的某个区域。 因此,当我开始研究这个 需求 以及如何实现它时,我只遇到了矩形、圆形或正方形区域来裁剪图像。如果我们感兴趣的区域不是矩形、正方形、圆形等,我们该怎么办?我们应该能够选择图像中我们区域的所有点。 从现在开始,您可以裁剪您想要的特定 区域。
图-1: 裁剪图像的特定 区域 GUI
背景
首先,我必须解释 GUI。在本文中,我分享了一个图像裁剪 GUI 应用程序的截图。如您在图 1 中所见,我们需要确定我们的图像样本的哪个区域。在这个例子中,我们选择湖边岩石上的一块木头,并希望将这张图片分成两部分。一个只是岩石上的木头,另一个只是图像样本。正如您所见,标记为裁剪图像的是一个,标记为原始图像的是另一个。 标记为图像名称的 PictureBox 是选择裁剪点的区域。当然,您必须通过文件菜单栏的打开选项来选择要裁剪的图像。正如您所看到的,红线是由鼠标点击选择的点组成的。在上面的 GUI 屏幕上,裁剪按钮用于在您选择点之后创建裁剪图像。如果您不喜欢您选择的点,也许您手滑了,撤销按钮可以让您撤销您的选择并提供选择正确点的功能。您可以从选项菜单栏中选择这些功能,然后可以通过文件菜单栏的保存选项将裁剪后的图像保存起来以供使用。鼠标点文本框显示您在图像中的鼠标坐标,多边形点文本框显示您将创建的最大和最小点。
让我们解释一些方法来理解这个简单的 GUI 应用程序。在后台,我们使用非常简单的方法来裁剪图像。我们使用非常流行的图像处理方法,即掩蔽两个图像。源图像是原始图像,第二个图像只是一个完全黑色的图像(黑色图像的 RGB 值为 '0'),其大小与原始图像相同。但这种方法的诀窍是多边形由我们选择的点形成。我们没有只有 RGB 值为 '0' 的黑色图像,只有多边形内部的 RGB 值为 '1'。然后我们相乘(掩蔽)这两个图像,我们就得到了裁剪后的图像。就是这样,非常简单。
使用代码
代码被分成两个主要部分。其中之一是选择多边形点,我们使用 pictureBox1 _Mouse_Click() 事件和 pictureBox1_MouseMove() 事件。MouseMove 事件让我们知道我们正在哪个坐标值,当我们拖动鼠标光标到包含我们图像的 PictureBox 上时。MouseClick 事件允许我们通过单击鼠标左键添加多边形点,并且可以通过单击鼠标右键进行撤销。我们需要一些临时变量来绘制多边形。
//to choose points of crop region
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left:
temp_point = new System.Drawing.Point(e.X, e.Y);
temp_count = polygonPoints.Count;
polygonPoints.Add(new System.Drawing.Point(e.X, e.Y));
if (polygonPoints.Count > 1)
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
temp_im = bmp.Clone(rect, PixelFormat.Format24bppRgb);
this.DrawLine(polygonPoints[polygonPoints.Count - 2], polygonPoints[polygonPoints.Count - 1]);
}
break;
// in this point we can undo easily, with pushing mouse right click
case MouseButtons.Right:
if (polygonPoints.Count > 0)
{
undo();
}
break;
}
pictureBox1.Image = bmp;
}
第二个主要部分是 crop() 方法,我们用它来裁剪图像区域。我们首先填充矩形以创建与原始图像大小相同的黑色图像,并在多边形内部填充“1”的 RGB 值。之后,我们使用 Cv.Mul(CvArr src1,CvArr src2, CvArr dst, double scale) 方法将两个图像相乘。
private void crop()
{
timer1.Stop();
IplImage accc = Cv.CreateImage(new CvSize(bmp.Width, bmp.Height), BitDepth.U8, 3);
Graphics Ga = Graphics.FromImage(bmp);
//the black image
Ga.FillRectangle(new SolidBrush(Color.Black), new Rectangle(0, 0, bmp.Width, bmp.Height));
//draw from the last point to first point
Ga.DrawLine(new Pen(Color.Red, 3), polygonPoints[polygonPoints.Count - 1], polygonPoints[0]);
//all of the rgb values are being set 1 inside the polygon
SolidBrush Brush = new SolidBrush(Color.FromArgb(1, 1, 1));
//we have to prepare one mask of Multiplying operation for cropping region
G.FillClosedCurve(Brush, polygonPoints.ToArray());
Cv.Mul(BitmapToIplImage(Source), BitmapToIplImage(bmp), accc, 1);
computecrop();
croplast = accc.ToBitmap().Clone(rectcrop, Source.PixelFormat);//just show cropped region part of image
pictureBox2.Image = croplast; // crop region of image
}
当然,我们需要一个方法来将 Bitmap 转换为 IplImage,所以 BitmapToIplImage(Bitmap src) 方法为此目的工作。
// we have to conversion from bitmap to IplImage to use OpenCvSharp methods
public static IplImage BitmapToIplImage(Bitmap bitmap)
{
IplImage tmp, tmp2;
Rectangle bRect = new Rectangle(new System.Drawing.Point(0, 0), new Size((int)bitmap.Width, (int)bitmap.Height));
BitmapData bmData = bitmap.LockBits(bRect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
tmp = Cv.CreateImage(Cv.Size(bitmap.Width, bitmap.Height), BitDepth.U8, 3);
tmp2 = Cv.CreateImage(Cv.Size(bitmap.Width, bitmap.Height), BitDepth.U8, 1);
tmp.ImageData = bmData.Scan0; ;
bitmap.UnlockBits(bmData);
// Cv.CvtColor(tmp, tmp2, ColorConversion.RgbToGray);
return tmp;
}
然后,我们必须使用一些刷新方法来释放内存并使用一些临时变量。临时变量用于使用 Graphics 类的方法并创建掩蔽对象来相乘两个图像。
// we have refresh some assignments operators for new image or cropping new region
private void first_refresh_im()
{
Rectangle rect = new Rectangle(0, 0, resim.Width, resim.Height);
resimi = resim.ToBitmap() ;
bmp = resimi.Clone(rect, resimi.PixelFormat);
Source = resimi.Clone(rect, resimi.PixelFormat);
pictureBox1.Image = bmp;
G = Graphics.FromImage(bmp);
polygonPoints.Clear();
}
// when we undo point of region, we have to create new rectangular object with using ex-points
// and we have to need new bmp Source object
private void refresh_im()
{
Rectangle rect = new Rectangle(0, 0, resim.Width, resim.Height);
bmp = resimi.Clone(rect, resimi.PixelFormat);
Source = resimi.Clone(rect, resimi.PixelFormat);
pictureBox1.Image = bmp;
}
关注点
我希望这个 GUI 对从事图像处理方法的人有用。我使用了一些 opencvsharp 方法,因为在图像处理实现中,大多数人都使用这个库和源代码。本文将为人们提供 opencvsharp 简单方法的第一级教程。
结论
在本文中,我们学习了一些图像处理方法以及如何在 .NET 平台上使用它们,并且我们已经接触了 opencvsharp 方法。从现在开始,我们不再需要其他程序来进行特定的区域图像裁剪处理。并且我们可以裁剪图像中我们想要的特定区域,而不仅仅是矩形、正方形、圆形形状。