从自定义PictureBox控件转换不同大小的图像的点(X,Y) [英] Translating a Point(X,Y) for Images of Different Sizes from a Custom PictureBox Control

查看:261
本文介绍了从自定义PictureBox控件转换不同大小的图像的点(X,Y)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have to process several images in bulk.I have to place some text at a particular point(X, Y).There is a custom control that is derived from picturebox that allows the user to drag the text and place it at the desired location.

对于两种图像,我分别设置了PictureBoxSizeMode

There are two types of images for which I set the PictureBoxSizeMode differently

垂直图像

我设置了PictureBoxSizeMode.Zoom;

水平

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

For Horizontal Images that fill up the PictureBox i set > PictureBoxSizeMode.StretchImage

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

The user can select the location to place the text by dragging the text over this picturebox control.The original image is resized to the control size(for horizontal images) and the user drags the text over this image.

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

Based on the SizeMode of the Picturebox the selected point is translated to point within the original image using the following code

    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中调用另一个方法来获取大致的文本位置


Now after getting the Point I have to call another method within the Main Form to get the approximate text location

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

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

Where refimgsize is the size of the original image(unscaled) used to place the text.

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

        }

问题是此方法不正确.当我使用水平图像作为参考放置文本时,以及在将点转换为垂直图像中的点时,该点的位置不正确当我使用垂直图像作为参考并完成对水平图像中某个点的翻译时,会发生同样的事情

我做错了什么?请提出建议.

What I'm I doing wrong?Please advice.

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

Please let me know if I need to post the full code of the control.

更新:

这是我想要实现的.下面图片中的徽标和文本是手动放置的.您可以看到徽标和文本在不同纵横比的图像中的大致相同位置的显示方式.

This is what i want to achieve.The Logo and the Text in the pictures below are manually placed.You can see that how the logo and the text appears in approximately same locations in images of different aspect ratios.

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

UPDATE: As per @Taw's comments i have taken the following approach to find the 2 closest edges and use the respective spacing.

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


现在在主表单中,我将执行以下操作


Now in the Main Form i do the following

  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;


    }

仍然我没有找到合适的位置.

Still i don't get the proper positioning.

我做错了什么?

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

This is what i want to achieve...

更新:

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

As per @Abion47 answer i have used the following approach

在自定义图片框控件中

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;

这几乎可以用..除了右下边缘.

This works almost okay.. except the Bottom-Right edge.

在自定义图片框中

以主要形式

我在做什么错?请指教.

What i'm i doing wrong? Please advice.

更新:

UPDATE:

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

What i have done is calculate the ratio from the picturebox control and use the ratio like this in the Main form to translate the point

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;

这很好,直到我将文本和徽标紧密放置.在自定义图片框控件中,文本和徽标正确显示.在主窗口中,对于垂直图像,它们看起来没问题,但对于水平图像,它们重叠...在这里错了吗?请指教.

This works pretty well until i place the text and logo closely.In the custom picturebox control text and logo appears correctly.In the Main window,For vertical images they appear alright,but for horizontal images both overlaps... What's going wrong here? Please advice..

UPDATE

UPDATE

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

This works well.But how do i translate the point from the Main window to the custom picturebox control( with the text that allows dragging).

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

I have tried the following code.But this is not giving precise positioning

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

请提出建议.

推荐答案

我无法阅读所有代码来确切地告诉您应该如何编码,但是这里有一些示例代码:

I can't read through all your code to tell you exactly how you should code this, but here is some example code as a possibility:

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

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

In your practice, you will probably need to do some offsetting as well to account for border thicknesses or whatever.

您可能要做的一件事就是纠正"位置,即根据文本元素在图像中的位置来偏移文本元素的位置.例如,左上角的文本将相对于其自己的左上角定位,右下角的文本将位于其自己的右下角,图像中心的文本将相对于其中心而定位.

One thing you can possibly do to "correct" the position is to offset the positions of the text elements depending on where they are in the image. For example, text in the top left corner will be positioned relative to its own top left corner, those in the lower right will be positioned to their own lower right, and those in the center of the image will be positioned relative to their center.

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

Building off of the example I gave in my sample project (download link in the comments), you can do it like so:

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

这篇关于从自定义PictureBox控件转换不同大小的图像的点(X,Y)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆