繁体   English   中英

从自定义PictureBox控件转换不同尺寸图像的点(X,Y)

[英]Translating a Point(X,Y) for Images of Different Sizes from a Custom PictureBox Control

我必须批量处理几张图像,我必须在特定点(X,Y)上放置一些文本。有一个自定义控件,该控件衍生自图片框,允许用户拖动文本并将其放置在所需位置。

我为PictureBoxSizeMode设置了两种不同的图像类型

垂直图像

在此处输入图片说明

我设置> PictureBoxSizeMode.Zoom;

卧式

对于填满PictureBox的水平图像,我设置> PictureBoxSizeMode.StretchImage

在此处输入图片说明

用户可以通过在此图片框控件上拖动文本来选择放置文本的位置。原始图像将调整为控件大小(对于水平图像),并且用户将文本拖动到该图像上。

根据Picturebox的SizeMode,使用以下代码将所选点转换为原始图像中的点

    if (sizemode == 1)
    {

     transpoint = TranslateStretchImageMousePosition(new Point(e.X - 20, e.Y -20));

    }

    else if (sizemode == 2)
    {
        transpoint = TranslateZoomMousePosition(new Point(e.X - 20, e.Y - 20));

    }

public Point TranslateStretchImageMousePosition(Point coordinates)
        {
            // test to make sure our image is not null
            if (Image == null) return coordinates;
            // Make sure our control width and height are not 0
            if (Width == 0 || Height == 0) return coordinates;
            // First, get the ratio (image to control) the height and width
            float ratioWidth = (float)Image.Width / Width;
            //MessageBox.Show(ratioWidth.ToString());

            float ratioHeight = (float)Image.Height / Height;
           // MessageBox.Show(ratioHeight.ToString());
            // Scale the points by our ratio
            float newX = coordinates.X;
            float newY = coordinates.Y;
            newX *= ratioWidth;
            newY *= ratioHeight;
            return new Point((int)newX, (int)newY);
        }

public Point TranslateZoomMousePosition(Point coordinates)
        {
            // test to make sure our image is not null
            if (Image == null) return coordinates;
            // Make sure our control width and height are not 0 and our 
            // image width and height are not 0
            if (Width == 0 || Height == 0 || Image.Width == 0 || 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)Image.Width / Image.Height;
            float controlAspect = (float)Width / 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)Image.Width / Width;
                newX *= ratioWidth;
                float scale = (float)Width / Image.Width;
                float displayHeight = scale * Image.Height;
                float diffHeight = 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)Image.Height / Height;
                newY *= ratioHeight;
                float scale = (float)Height / Image.Height;
                float displayWidth = scale * Image.Width;
                float diffWidth = Width - displayWidth;
                diffWidth /= 2;
                newX -= diffWidth;
                newX /= scale;
            }
            return new Point((int)newX, (int)newY);
        }

现在,在获取Point之后,我必须在Main Form中调用另一个方法以获取近似的文本位置

    point= translatemanualpoint(transpoint, img, refimgsize.Width, refimgsize.Height);

其中refimgsize是用于放置文本的原始图像(未缩放)的大小。

 private Point translatemanualpoint(Point coordinates, Bitmap Image, int Width, int Height)
        {

            //---------------------------------
            // test to make sure our image is not null
            if (Image == null) return coordinates;
            // Make sure our control width and height are not 0
            if (Width == 0 || Height == 0) return coordinates;
            // First, get the ratio (image to control) the height and width
            float ratioWidth = (float)Image.Width / Width;


            float ratioHeight = (float)Image.Height / Height;

            // Scale the points by our ratio
            float newX = coordinates.X;
            float newY = coordinates.Y;
            newX *= ratioWidth;
            newY *= ratioHeight;
            return new Point((int)newX, (int)newY);  

        }

问题是这种方法不准确。当我使用水平图像作为参考放置文本时,以及当点被转换为垂直图像中的点时,该点的位置不正确。使用垂直图像作为参考,并完成对水平图像中某个点的平移

我做错了吗?请提出建议。

请让我知道是否需要发布控件的完整代码。

更新:

这就是我想要实现的。下面图片中的徽标和文本是手动放置的。您可以看到徽标和文本在不同长宽比的图像中的大致相同位置如何显示。

更新:根据@Taw的评论,我采用以下方法来找到2个最接近的边并使用各自的间距。

void findclosestedges(Point p)
        {         

            //Xedge=1 -- Left Edge is closer to Point 2--Right Edge 

            //Finding closest Left/Right Edge
            if (p.X < (ClientSize.Width - p.X))
            {

                LaunchOrigin.Xedge = 1;
                LaunchOrigin.Xspacing = p.X;
                LaunchOrigin2.closestedge.Text = " ";
                LaunchOrigin2.closestedge.Text = LaunchOrigin2.closestedge.Text + " left";
            }
            else
            {
                LaunchOrigin.Xedge = 2;
                LaunchOrigin.Xspacing = (ClientSize.Width - p.X);
                LaunchOrigin2.closestedge.Text = " ";
                LaunchOrigin2.closestedge.Text = LaunchOrigin2.closestedge.Text + " right";
            }

            //Finding closest Top/Bottom Edge

            if (p.Y < (ClientSize.Height - p.Y))
            {
                LaunchOrigin.Yedge = 1;
                LaunchOrigin.Yspacing =p.Y;
                LaunchOrigin2.closestedge.Text = LaunchOrigin2.closestedge.Text + " top";
            }
            else
            {
                LaunchOrigin.Yedge = 2;
                LaunchOrigin.Yspacing = (ClientSize.Height - p.Y);
                LaunchOrigin2.closestedge.Text = LaunchOrigin2.closestedge.Text + " bottom";
            }
            LaunchOrigin.ewidth = Width;
            LaunchOrigin.eheight = Height;
        }

现在在主窗体中,执行以下操作

  int wratio = img.Width / ewidth;
    int hratio = img.Height / eheight;
    if (Xedge == 1)
    {

            cpoint.X = Xspacing*wratio;


    }
    else
    {

        cpoint.X = img.Width - Xspacing * wratio;



    }
    if (Yedge == 1)
    {

        cpoint.Y = Yspacing * hratio;




    }
    else
    {


            cpoint.Y = img.Height - Yspacing*hratio;


    }

我仍然没有得到正确的定位。

我做错了什么?

这就是我想要实现的...

在此处输入图片说明 在此处输入图片说明

更新:

根据@ Abion47回答,我使用了以下方法

在自定义图片框控件中

Point src = e.Location;
PointF ratio = new PointF((float)src.X / Width, (float)src.Y / Height);
LaunchOrigin.ratio = ratio;
Point origin = new Point((int)(backupbit1.Width * ratio.X), (int)(backupbit1.Height * ratio.Y));
LaunchOrigin.origin = origin;
point.X = src.X - origin.X;
point.Y = src.Y - origin.Y;

在主窗口中

Point pos2 = new Point((int)(ratio.X * img.Width), (int)(ratio.Y * img.Height));
cpoint.X = pos2.X  - origin.X;
cpoint.Y = pos2.Y  - origin.Y;

除底部右边缘外,这几乎可以正常工作。

在自定义图片框中

在此处输入图片说明

以主要形式

在此处输入图片说明

我做错了什么? 请指教。

更新:

我所做的是从图片框控件计算比例,并在主窗体中使用这样的比例来翻译点

Point origin = new Point((int)(bitmap.Width * textratio.X), (int)(bitmap.Height * textratio.Y));
Point pos2 = new Point((int)(textratio.X * img.Width), (int)(textratio.Y * img.Height));
cpoint.X = pos2.X - (int)(origin.X);
cpoint.Y = pos2.Y - (int)(origin.Y);

对于徽标,我也这样做

Point origin = new Point((int)(worktag.Width * logoratio.X), (int)(worktag.Height * logoratio.Y));
Point logopositionpoint = new Point((int)(logoratio.X * img.Width), (int)(logoratio.Y * img.Height));
imgpoint.X = logopositionpoint.X - origin.X;
imgpoint.Y = logopositionpoint.Y - origin.Y;

在我将文本和徽标紧密放置之前,此方法效果很好。在自定义图片框控件中,文本和徽标正确显示。在主窗口中,对于垂直图像,它们看起来没问题,但对于水平图像,它们却重叠...这里出了什么问题? 请指教..

更新

效果很好。但是如何将点从主窗口转换为自定义图片框控件(带有允许拖动的文本)。

我已经尝试了以下代码,但这不能给出精确的位置

  private Point translatetextpoint(Point mpoint,Bitmap bitmap)
        {

            PointF ratio = new PointF((float)LaunchOrigin.cpoint.X /LaunchOrigin.img.Width, (float)LaunchOrigin.cpoint.Y /LaunchOrigin.img.Height);
            Point origin = new Point((int)(endPointPictureBox1.bit.Width * ratio.X), (int)(endPointPictureBox1.bit.Height * ratio.Y));
            Point pos2 = new Point((int)(ratio.X * endPointPictureBox1.Width), (int)(ratio.Y * endPointPictureBox1
                .Height));
            pos2.X = pos2.X - (int)(origin.X);
            pos2.Y = pos2.Y - (int)(origin.Y);
            return pos2;
        }

请指教..

我无法通读所有代码,无法确切地告诉您应该如何编码,但是下面是一些示例代码:

PointF GetReferencePoint(Point absoluteReferencePoint)
{
    PointF referencePointAsRatio = new Point();

    referencePointAsRatio.X = (float)absoluteReferencePoint.X / referenceImage.Width;
    referencePointAsRatio.Y = (float)absoluteReferencePoint.Y / referenceImage.Height;

    return referencePointAsRatio;
}

...

Point GetTargetPoint(PointF referencePointAsRatio)
{
    Point targetPoint = new Point();

    targetPoint.X = (int)(referencePointAsRatio.X * targetImage.Width);
    targetPoint.Y = (int)(referencePointAsRatio.Y * targetImage.Height);

    return targetPoint;
}

在您的实践中,您可能还需要进行一些偏移以说明边框的厚度或其他任何原因。

编辑:

您可以“纠正”位置的一件事是根据文本元素在图像中的位置来偏移文本元素的位置。 例如,左上角的文本将相对于其自己的左上角定位,右下角的文本将位于其自己的右下角,图像中心的文本将相对于其中心定位。

以我在示例项目中给出的示例(注释中的下载链接)为基础,您可以这样做:

private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    Point src = e.Location;
    PointF ratio = new PointF((float)src.X / pictureBox1.Width, (float)src.Y / pictureBox1.Height);
    Point origin = new Point((int)(label1.Width * ratio.X), (int)(label1.Height * ratio.Y));

    label1.Left = src.X - origin.X;
    label1.Top = src.Y - origin.Y;

    Point pos2 = new Point((int)(ratio.X * pictureBox2.Width), (int)(ratio.Y * pictureBox2.Height));
    label2.Left = pos2.X + pictureBox2.Left - origin.X;
    label2.Top = pos2.Y + pictureBox2.Top - origin.Y;

    Point pos3 = new Point((int)(ratio.X * pictureBox3.Width), (int)(ratio.Y * pictureBox3.Height));
    label3.Left = pos3.X + pictureBox3.Left - origin.X;
    label3.Top = pos3.Y + pictureBox3.Top - origin.Y;

    Point pos4 = new Point((int)(ratio.X * pictureBox4.Width), (int)(ratio.Y * pictureBox4.Height));
    label4.Left = pos4.X + pictureBox4.Left - origin.X;
    label4.Top = pos4.Y + pictureBox4.Top - origin.Y;
}

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM