代码之家  ›  专栏  ›  技术社区  ›  techno

在缩放模式下转换矩形位置图片框

  •  2
  • techno  · 技术社区  · 6 年前

    我正在确定图像中的矩形区域,并在图片框中显示给用户。
    由于图像有时可能非常大,因此我使用的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);
    

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

    2 回复  |  直到 6 年前
        1
  •  3
  •   Reza Aghaei    6 年前

    您可以这样将图片框中选定的矩形转换为图像中的矩形:

    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
  •  2
  •   Jimi    6 年前

    把这看作是对 Reza Aghaei answer .


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

    这个 ZoomFactor 类提供了这些方法 :

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

    RectangleF TranslateZoomSelection(RectangleF Selection, SizeF ContainerSize, SizeF ImageSize) :
    返回A RectangleF 表示在容器内创建的选定内容,并转换为位图坐标。

    RectangleF TranslateSelectionToZoomedSel(RectangleF SelectionRect, SizeF ContainerSize, SizeF ImageSize) :
    返回A 矩形F 表示转换为容器内缩放选择图像的原始位图的预选区域。

    PointF GetImageScaledOrigin(SizeF ContainerSize, SizeF ImageSize) 以下内容:
    返回 波因特 容器内缩放图像原点坐标的引用。

    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);
    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

    注释 以下内容: 在本例中,纵向图像的预选择反转 Width 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);
        }
    }