C# 在缩放模式下平移矩形位置Picturebox
我正在确定图像中的矩形区域,并在PictureBox中将其显示给用户。C# 在缩放模式下平移矩形位置Picturebox,c#,.net,winforms,picturebox,system.drawing,C#,.net,Winforms,Picturebox,System.drawing,我正在确定图像中的矩形区域,并在PictureBox中将其显示给用户。 由于图像有时可能非常大,我使用的是一个PictureBox,其SizeMode设置为Zoom 我使用以下代码来转换矩形(X,Y)坐标: public Point TranslateZoomMousePosition(Point coordinates) { // test to make sure our image is not null if (pictureBox5.Image == null) ret
由于图像有时可能非常大,我使用的是一个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);
但确定的帧/矩形位置不正确。我做错了什么?您可以通过以下方式将图片框上选定的矩形转换为图像上的矩形:
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);
}
注意:您可以在SizeMode中找到
ImageRectangleFromSizeMode
方法,并将其用作应用程序代码的一部分
示例-裁剪具有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();
}
以下是输入图像:
这就是结果:
一个专门的类,提供一些辅助工具来确定选择的缩放因子,并将选择坐标转换为缩放的
位图
坐标。此版本仅适用于缩放图像 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);
}
}
PointF TranslateZoomPosition(PointF坐标、SizeF ContainerSize、SizeF ImageSize)
:将容器内点位置的
PointF
转换坐标返回到位图内的点位置,并在容器中放大
矩形TranslateZoomSelection(矩形选择、SizeF ContainerSize、SizeF ImageSize)
:返回表示在容器内创建的选择的
矩形f
,并转换为位图坐标
矩形F TranslateSelection ToZoomedSell(矩形F SelectionRect,SizeF ContainerSize,SizeF ImageSize)
:返回矩形f,表示转换为容器内缩放选择图像的原始位图的预选区域
获取图像缩放起始点(SizeF ContainerSize,SizeF ImageSize)
:返回容器内缩放图像原点坐标的
PointF
参考
SizeF GetImageScaledSize(SizeF ContainerSize,SizeF ImageSize)
:在容器内缩放时,返回图像的
SizeF
参考
示例用法,显示如何使用在容器控件内创建的选择矩形裁剪位图。TranslateZoomSelection
方法返回与选择区域对应的位图部分:
ZoomFactor zoomHelper = new ZoomFactor()
Bitmap originalBitmap;
RectangleF currentSelection = [Current Selection Rectangle];
RectangleF bitmapRect = zoomHelper.TranslateZoomSelection(currentSelection, [Container].Size, originalBitmap.Size);
var croppedBitmap = new Bitmap((int)bitmapRect.Width, (int)bitmapRect.Height, originalBitmap.PixelFormat))
using (var g = Graphics.FromImage(croppedBitmap))
{
g.DrawImage(originalBitmap, new Rectangle(Point.Empty, Size.Round(bitmapRect.Size)),
bitmapRect, GraphicsUnit.Pixel);
[Container].Image = croppedBitmap;
}
上述行为的样本:
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);
}
}
注意:在该示例中,纵向图像的预选反转了宽度
和高度
缩放因子类类:
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);
}
}
ImageRectangleFromSizeMode
哇,这是在深入挖掘隐藏的金库@techno做了一些改动,以支持拉伸
模式。@TaW添加了ImageRectangleFromSizeMode
源代码的链接,以便将来的读者可以使用它并将该方法作为应用程序代码的一部分编写。哈ImageRectangleFromSizeMode
是堆栈跟踪中经常提到的内容(当出现问题时)。干得好@RezaAghaei实际上还需要做相反的操作,即:我在原始图像上有矩形坐标。当此图像显示在picturebox中时,我需要通过转换其在原始图像中的已知位置将可移动框架放置在正确的位置。非常感谢:)。我将看一看你的两个答案。实际上还需要做相反的事情,即:我在原始图像上有矩形坐标。当此图像显示在picturebox中时,我需要通过转换其在原始图像中的已知位置,将可移动框架放置在正确的位置。@techno请参阅编辑。我已经添加了一个从相对于原始图像的坐标到缩放图像的选择转换器(还有一个示例动画:)。我没有太多的时间,所以没有进行适当的测试,但我在不同的条件下做了一些调整,看起来还可以。我明天会修改它。如何检测控件在picturebox中是否已调整大小或移动?目前我使用picturebox鼠标事件。有更好的方法吗?什么是鼠标事件?:)我假设它是一个鼠标移动
。我不确定您是如何实现此控件的(可能是之前提到的TaW或Reza Aghaei的自定义控件),但当然,此自定义控件1)只能在PictureBox的边界内移动(如果不是,请参见此处:),2)公开属性或引发引用其在PictureBox中当前位置的事件。移动选择控件时(…)