在缩放模式Picturebox中翻译矩形位置

问题描述 投票:2回答:2

我正在确定图像中的矩形区域并在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);

但是确定的帧/矩形位置不正确。 我做错了什么?

c# .net winforms picturebox system.drawing
2个回答
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();
}

这是输入图像:

enter image description here

这就是结果:

enter image description here


2
投票

考虑这是Reza Aghaei answer的补充。


一个专门的类,它提供一些辅助工具来确定选择的缩放因子,并将选择坐标转换为缩放的Bitmap坐标。 此版本仅适用于缩放图像。

ZoomFactor类提供以下方法:

PointF TranslateZoomPosition(PointF Coordinates, SizeF ContainerSize, SizeF ImageSize): 将容器内Point点位置的PointF转换坐标返回到Bitmap内的Point位置,放大容器。

RectangleF TranslateZoomSelection(RectangleF Selection, SizeF ContainerSize, SizeF ImageSize): 返回表示在Container内创建的选择的RectangleF,转换为Bitmap坐标。

RectangleF TranslateSelectionToZoomedSel(RectangleF SelectionRect, SizeF ContainerSize, SizeF ImageSize): 返回一个RectangleF,表示原始位图的预选区域,转换为Container内的缩放选择图像。

PointF GetImageScaledOrigin(SizeF ContainerSize, SizeF ImageSize): 返回Container内缩放的Image原点坐标的PointF引用。

SizeF GetImageScaledSize(SizeF ContainerSize, SizeF ImageSize): 在Container内缩放时返回Image的SizeF引用。

示例用法,显示如何使用在Container控件内创建的选择矩形来裁剪位图。 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();
}

上述行为的示例:

PictureBox Zoom Selection

注意:在示例中,在Portrait中预先选择图像会反转WidthHeight

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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.