自由形式的农作物选择无法正常工作 [英] free-form crop selection doesn't work properly
问题描述
我制作了一个程序,可以让您进行随机选择,然后将所选区域保存到新图像中,但是我遇到了一个问题,那就是它不起作用,因为它本来应该...我将在此处发布代码,所以您可以看看:
private List< Point>分数=空;
private bool选择=否;
private Bitmap SelectedArea = null;
private void pictureBox5_MouseDown(对象发送者,MouseEventArgs e)
{
Points = new List< Point>();
选择= true;
}
private void pictureBox5_MouseMove(对象发送者,MouseEventArgs e)
{
if(!Selecting)return;
Points.Add(new Point(e.X,e.Y));
pictureBox5.Invalidate();
}
private void pictureBox5_MouseUp(object sender,MouseEventArgs e)
{
Selecting = false;
//复制所选区域。
SelectedArea = GetSelectedArea(pictureBox5.Image,Color.Transparent,Points);
SelectedArea.Save(@ C:\Users\User\Desktop\Gallery\image + NumberOfClick.ToString()+ cropped.jpeg,ImageFormat.Jpeg);
字符串文件名= @ C:\Users\User\Desktop\Gallery\image + NumberOfClick.ToString()+ cropped.jpeg;
if(File.Exists(filename))
{
button1.Visible = true;
pictureBox5.Visible = false;
}
}
private void pictureBox5_Paint(object sender,PaintEventArgs e)
{
if((Points!= null)&&( Points.Count> 1))
{
使用(笔dashed_pen =新的Pen(Color.Black))
{
dashed_pen.DashPattern =新的float [] {5, 5};
e.Graphics.DrawLines(Pens.White,Points.ToArray());
e.Graphics.DrawLines(dashed_pen,Points.ToArray());
}
}
}
私人位图GetSelectedArea(图像源,Color bg_color,List< Point>点)
{
//制作一个新的位图,其背景为
// //所选区域除外。
位图big_bm =新位图(源);
使用(Graphics gr = Graphics.FromImage(big_bm))
{
//设置背景色。
gr.Clear(bg_color);
//从原始图像中进行笔刷。
using(Brush br = new TextureBrush(source))
{
//用画笔填充所选区域。
gr.FillPolygon(br,points.ToArray());
//查找所选区域的边界。
Rectangle source_rect = GetPointListBounds(points);
//制作仅保留所选区域的位图。
位图结果=新位图(
source_rect.Width,source_rect.Height);
//将所选区域复制到结果位图。
使用(Graphics result_gr = Graphics.FromImage(result))
{
Rectangle dest_rect = new Rectangle(0,0,
source_rect.Width,source_rect.Height);
result_gr.DrawImage(big_bm,dest_rect,
source_rect,GraphicsUnit.Pixel);
}
//返回结果。
的返回结果;
}
}
}
私人矩形GetPointListBounds(List< Point> points)
{
int xmin = points [0]。 X;
int xmax = xmin;
int ymin = points [0] .Y;
int ymax = ymin;
(int i = 1; i< points.Count; i ++)
{
if(xmin> points [i] .X)xmin = points [i ]。X;
if(xmax if(ymin> points [i] .Y)ymin = points [i] .Y;
if(ymax }
返回新的Rectangle(xmin,ymin,xmax-xmin,ymax-ymin);
}
这就是我所做的并保存裁剪后的图像。
这也是我上传图片的方式:
OpenFileDialog f = new OpenFileDialog();
f.Filter =图像文件(* .jpg,*。jpeg,*。jpe,*。jfif,*。png)| * .jpg; * .jpeg; * .jpe; * .jfif; * .png;
if(f.ShowDialog()== DialogResult.OK)
{
currentImage = Image.FromFile(f.FileName);
pictureBox1.Image = currentImage;
}
pictureBox1.Image.Save(@ C:\Users\User\Desktop\Gallery\image1.jpeg,ImageFormat.Jpeg);
DialogResult结果= MessageBox.Show(裁剪图像,信息,MessageBoxButtons.OK);
if(result == DialogResult.OK)
{
pictureBox5.Visible = true;
button1.Visible = false;
pictureBox5.Image = pictureBox1.Image;
}
在pictureBox5中,我正在选择并裁剪图片。
情况1:如果存储点,请按以下步骤存储:在您的 GetSelectedArea
方法中,使用此点列表代替:
私有位图GetSelectedArea (图像源,Color bg_color,List< Point>点)
{
var unzoomedPoints =
points.Select(x => Point.Round((unZoomed(Point.Round(x) ,缩放,偏移量))))
.ToList();
//创建一个新的位图,其背景为
在此之后,替换每个对<将方法中的code>点加1到 unzoomedPoints
。实际上,它们只有两个。
情况2:如果存储的点已经未缩放:
Points.Add(unZoomed(e.Location,zoom,offset));
您可以直接使用列表。
I made a program that lets you do a random selection then the selected area to save into a new image, but I got a problem it doesn't work how it's supposed to... I will post my code here so you can have a look:
private List<Point> Points = null;
private bool Selecting = false;
private Bitmap SelectedArea = null;
private void pictureBox5_MouseDown(object sender, MouseEventArgs e)
{
Points = new List<Point>();
Selecting = true;
}
private void pictureBox5_MouseMove(object sender, MouseEventArgs e)
{
if (!Selecting) return;
Points.Add(new Point(e.X, e.Y));
pictureBox5.Invalidate();
}
private void pictureBox5_MouseUp(object sender, MouseEventArgs e)
{
Selecting = false;
// Copy the selected area.
SelectedArea = GetSelectedArea(pictureBox5.Image, Color.Transparent, Points);
SelectedArea.Save(@"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg", ImageFormat.Jpeg);
string filename = @"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg";
if(File.Exists(filename))
{
button1.Visible = true;
pictureBox5.Visible = false;
}
}
private void pictureBox5_Paint(object sender, PaintEventArgs e)
{
if ((Points != null) && (Points.Count > 1))
{
using (Pen dashed_pen = new Pen(Color.Black))
{
dashed_pen.DashPattern = new float[] { 5, 5 };
e.Graphics.DrawLines(Pens.White, Points.ToArray());
e.Graphics.DrawLines(dashed_pen, Points.ToArray());
}
}
}
private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
{
// Make a new bitmap that has the background
// color except in the selected area.
Bitmap big_bm = new Bitmap(source);
using (Graphics gr = Graphics.FromImage(big_bm))
{
// Set the background color.
gr.Clear(bg_color);
// Make a brush out of the original image.
using (Brush br = new TextureBrush(source))
{
// Fill the selected area with the brush.
gr.FillPolygon(br, points.ToArray());
// Find the bounds of the selected area.
Rectangle source_rect = GetPointListBounds(points);
// Make a bitmap that only holds the selected area.
Bitmap result = new Bitmap(
source_rect.Width, source_rect.Height);
// Copy the selected area to the result bitmap.
using (Graphics result_gr = Graphics.FromImage(result))
{
Rectangle dest_rect = new Rectangle(0, 0,
source_rect.Width, source_rect.Height);
result_gr.DrawImage(big_bm, dest_rect,
source_rect, GraphicsUnit.Pixel);
}
// Return the result.
return result;
}
}
}
private Rectangle GetPointListBounds(List<Point> points)
{
int xmin = points[0].X;
int xmax = xmin;
int ymin = points[0].Y;
int ymax = ymin;
for (int i = 1; i < points.Count; i++)
{
if (xmin > points[i].X) xmin = points[i].X;
if (xmax < points[i].X) xmax = points[i].X;
if (ymin > points[i].Y) ymin = points[i].Y;
if (ymax < points[i].Y) ymax = points[i].Y;
}
return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin);
}
This is how I am doing and saving the cropped images.
And also this is how I am uploading the pictures:
OpenFileDialog f = new OpenFileDialog();
f.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png";
if (f.ShowDialog() == DialogResult.OK)
{
currentImage = Image.FromFile(f.FileName);
pictureBox1.Image = currentImage;
}
pictureBox1.Image.Save(@"C:\Users\User\Desktop\Gallery\image1.jpeg", ImageFormat.Jpeg);
DialogResult result = MessageBox.Show("Crop your image", "Information", MessageBoxButtons.OK);
if(result == DialogResult.OK)
{
pictureBox5.Visible = true;
button1.Visible = false;
pictureBox5.Image = pictureBox1.Image;
}
In pictureBox5 I am selecting and cropping the picture.
You need to calculate the zoom and the offset of the image when it is zoomed.
Here is how to do that; this assumes the PictureBox
is indeed in Zoom
mode, not in Stretch
mode. If you stretch it you need to calculate the zooms for x and y separately..
SizeF sp = pictureBox5.ClientSize;
SizeF si = pictureBox5.Image.Size;
float rp = sp.Width / sp.Height; // calculate the ratios of
float ri = si.Width / si.Height; // pbox and image
float zoom = (rp > ri) ? sp.Height / si.Height : sp.Width / si.Width;
float offx = (rp > ri) ? (sp.Width - si.Width * zoom) / 2 : 0;
float offy = (rp <= ri)? (sp.Height - si.Height * zoom) / 2 : 0;
Point offset = Point.Round(new PointF(offx, offy));
You calculate this after setting the Image
and after resizing the PictureBox
..
Now you can transform each drawn point into a zoomed or an unzoomed coordinate:
PointF zoomed(Point p1, float zoom, Point offset)
{
return (new PointF(p1.X * zoom + offset.X, p1.Y * zoom + offset.Y));
}
PointF unZoomed(Point p1, float zoom, Point offset)
{
return (new PointF((p1.X - offset.X) / zoom, (p1.Y - offset.Y) / zoom));
}
Here is a demo the draws on to either a normal (left) or a zoomed in (middle) image. To the right is the result of placing your GetSelectedArea
bitmap onto a PictureBox
with a checkerbox background:
Case 1: If you store the points as they come in: In your GetSelectedArea
method use this point list instead:
private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
{
var unzoomedPoints =
points.Select(x => Point.Round((unZoomed(Point.Round(x), zoom, offset))))
.ToList();
// Make a new bitmap that has the background
After this replace each reference to points
in the method by one to unzoomedPoints
. Actually there are just two of them..
Case 2: If you store the points already 'unZoomed' :
Points.Add(unZoomed(e.Location, zoom, offset));
you can use the list directly..
这篇关于自由形式的农作物选择无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!