我正在确定图像中的矩形区域,并在PictureBox中将其显示给用户。
由于图像有时可能非常大,因此我使用的PictureBox的SizeMode
设置为Zoom
。
我正在使用以下代码转换矩形(X,Y)坐标:
public Point TranslateZoomMousePosition(Point coordinates)
{
// test to make sure our image is not null
if (pictureBox5.Image == null) return coordinates;
// Make sure our control width and height are not 0 and our
// image width and height are not 0
if (pictureBox5.Width == 0 || pictureBox5.Height == 0 || pictureBox5.Image.Width == 0 || pictureBox5.Image.Height == 0) return coordinates;
// This is the one that gets a little tricky. Essentially, need to check
// the aspect ratio of the image to the aspect ratio of the control
// to determine how it is being rendered
float imageAspect = (float)pictureBox5.Image.Width / pictureBox5.Image.Height;
float controlAspect = (float)pictureBox5.Width / pictureBox5.Height;
float newX = coordinates.X;
float newY = coordinates.Y;
if (imageAspect > controlAspect)
{
// This means that we are limited by width,
// meaning the image fills up the entire control from left to right
float ratioWidth = (float)pictureBox5.Image.Width / pictureBox5.Width;
newX *= ratioWidth;
float scale = (float)pictureBox5.Width / pictureBox5.Image.Width;
float displayHeight = scale * pictureBox5.Image.Height;
float diffHeight = pictureBox5.Height - displayHeight;
diffHeight /= 2;
newY -= diffHeight;
newY /= scale;
}
else
{
// This means that we are limited by height,
// meaning the image fills up the entire control from top to bottom
float ratioHeight = (float)pictureBox5.Image.Height / pictureBox5.Height;
newY *= ratioHeight;
float scale = (float)pictureBox5.Height / pictureBox5.Image.Height;
float displayWidth = scale * pictureBox5.Image.Width;
float diffWidth = pictureBox5.Width - displayWidth;
diffWidth /= 2;
newX -= diffWidth;
newX /= scale;
}
return new Point((int)newX, (int)newY);
}
在确定的位置添加框架控件:
pictureBox5.Controls.Clear();
var c = new FrameControl();
c.Size = new Size(myrect.Width, myrect.Height);
c.Location=TranslateZoomMousePosition(newPoint(myrect.Location.X,myrect.Location.Y));
pictureBox5.Controls.Add(c);
但是确定的框架/矩形位置不正确。
我在做什么错了?
答案 0 :(得分:3)
您可以通过以下方式将图片框上的选定矩形转换为图像上的矩形:
public RectangleF GetRectangeOnImage(PictureBox p, Rectangle selectionRect)
{
var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var imageRect = (Rectangle)method.Invoke(p, new object[] { p.SizeMode });
if (p.Image == null)
return selectionRect;
var cx = (float)p.Image.Width / (float)imageRect.Width;
var cy = (float)p.Image.Height / (float)imageRect.Height;
var r2 = Rectangle.Intersect(imageRect, selectionRect);
r2.Offset(-imageRect.X, -imageRect.Y);
return new RectangleF(r2.X * cx, r2.Y * cy, r2.Width * cx, r2.Height * cy);
}
注意:您可以找到ImageRectangleFromSizeMode
方法source code here并将其用作编写此方法的一部分,作为您的应用程序代码的一部分。
示例-具有SizeMode = Zoom的PictureBox的裁剪图像
作为示例,以下代码将裁剪图片框1的给定矩形,并将结果设置为图片框2的图像:
var selectedRectangle = new Rectangle(7, 30, 50, 40);
var result = GetRectangeOnImage(pictureBox1, selectedRectangle);
using (var bm = new Bitmap((int)result.Width, (int)result.Height))
{
using (var g = Graphics.FromImage(bm))
g.DrawImage(pictureBox1.Image, 0, 0, result, GraphicsUnit.Pixel);
pictureBox2.Image = (Image)bm.Clone();
}
这是输入图像:
这是结果:
答案 1 :(得分:2)
请考虑将其添加到Reza Aghaei answer中。
一个专门的类,提供一些帮助工具来确定选择的比例因子,并将选择坐标转换为缩放的Bitmap
坐标。
此版本仅适用于缩放的图像。
ZoomFactor
类提供了以下方法:
PointF TranslateZoomPosition(PointF Coordinates, SizeF ContainerSize, SizeF ImageSize)
:
将容器内某个Point位置的PointF
转换后的坐标返回到位图内该Point位置的缩放坐标。
RectangleF TranslateZoomSelection(RectangleF Selection, SizeF ContainerSize, SizeF ImageSize)
:
返回RectangleF
,代表在Container中创建的选择,并转换为位图坐标。
RectangleF TranslateSelectionToZoomedSel(RectangleF SelectionRect, SizeF ContainerSize, SizeF ImageSize)
:
返回 RectangleF
,代表原始位图的预选区域,该区域已转换为容器内缩放后的选择图像。
PointF GetImageScaledOrigin(SizeF ContainerSize, SizeF ImageSize)
:
返回容器内缩放的图像原点坐标的PointF
参考。
SizeF GetImageScaledSize(SizeF ContainerSize, SizeF ImageSize)
:
在容器内缩放时,返回图像的SizeF
参考。
示例用法,显示如何使用在Container控件内创建的选择Rectangle裁剪位图。 TranslateZoomSelection
方法返回与选择区域相对应的Bitmap部分:
ZoomFactor ZoomHelper = new ZoomFactor()
Bitmap originalBitmap;
RectangleF currentSelection = [Current Selection Rectangle];
RectangleF bitmapRect = ZoomHelper.TranslateZoomSelection(currentSelection, [Container].Size, originalBitmap.Size);
using (Bitmap croppedBitmap = new Bitmap((int)bitmapRect.Width, (int)bitmapRect.Height, originalBitmap.PixelFormat))
using (Graphics g = Graphics.FromImage(croppedBitmap))
{
g.DrawImage(originalBitmap, new Rectangle(Point.Empty, Size.Round(bitmapRect.Size)),
bitmapRect, GraphicsUnit.Pixel);
[Container].Image = (Bitmap)croppedBitmap.Clone();
}
上述行为的示例:
注意:在该示例中,“人像”中的图像预选择会反转Width
和Height
ZoomFactor
类:
public class ZoomFactor
{
public ZoomFactor() { }
public PointF TranslateZoomPosition(PointF Coordinates, SizeF ContainerSize, SizeF ImageSize)
{
PointF imageOrigin = TranslateCoordinatesOrigin(Coordinates, ContainerSize, ImageSize);
float scaleFactor = GetScaleFactor(ContainerSize, ImageSize);
return new PointF(imageOrigin.X / scaleFactor, imageOrigin.Y / scaleFactor);
}
public RectangleF TranslateZoomSelection(RectangleF SelectionRect, SizeF ContainerSize, SizeF ImageSize)
{
PointF selectionTrueOrigin = TranslateZoomPosition(SelectionRect.Location, ContainerSize, ImageSize);
float scaleFactor = GetScaleFactor(ContainerSize, ImageSize);
SizeF selectionTrueSize = new SizeF(SelectionRect.Width / scaleFactor, SelectionRect.Height / scaleFactor);
return new RectangleF(selectionTrueOrigin, selectionTrueSize);
}
public RectangleF TranslateSelectionToZoomedSel(RectangleF SelectionRect, SizeF ContainerSize, SizeF ImageSize)
{
float scaleFactor = GetScaleFactor(ContainerSize, ImageSize);
RectangleF zoomedSelectionRect = new
RectangleF(SelectionRect.X * scaleFactor, SelectionRect.Y * scaleFactor,
SelectionRect.Width * scaleFactor, SelectionRect.Height * scaleFactor);
PointF imageScaledOrigin = GetImageScaledOrigin(ContainerSize, ImageSize);
zoomedSelectionRect.Location = new PointF(zoomedSelectionRect.Location.X + imageScaledOrigin.X,
zoomedSelectionRect.Location.Y + imageScaledOrigin.Y);
return zoomedSelectionRect;
}
public PointF TranslateCoordinatesOrigin(PointF Coordinates, SizeF ContainerSize, SizeF ImageSize)
{
PointF imageOrigin = GetImageScaledOrigin(ContainerSize, ImageSize);
return new PointF(Coordinates.X - imageOrigin.X, Coordinates.Y - imageOrigin.Y);
}
public PointF GetImageScaledOrigin(SizeF ContainerSize, SizeF ImageSize)
{
SizeF imageScaleSize = GetImageScaledSize(ContainerSize, ImageSize);
return new PointF((ContainerSize.Width - imageScaleSize.Width) / 2,
(ContainerSize.Height - imageScaleSize.Height) / 2);
}
public SizeF GetImageScaledSize(SizeF ContainerSize, SizeF ImageSize)
{
float scaleFactor = GetScaleFactor(ContainerSize, ImageSize);
return new SizeF(ImageSize.Width * scaleFactor, ImageSize.Height * scaleFactor);
}
internal float GetScaleFactor(SizeF Scaled, SizeF Original)
{
return (Original.Width > Original.Height) ? (Scaled.Width / Original.Width)
: (Scaled.Height / Original.Height);
}
}