从自定义PictureBox控件翻译不同大小的图像的点(X,Y)
我必须批量处理几个图像。我必须在特定点(X,Y)放置一些文本。有一个从图片框派生的自定义控件,允许用户拖动文本并将其放在所需的位置。
有两种类型的图像,我以不同的方式设置PictureBoxSizeMode
垂直图像
我设置> PictureBoxSizeMode.Zoom;
横
对于填充PictureBox的水平图像,我设置了> PictureBoxSizeMode.StretchImage
用户可以通过在该图片框控件上拖动文本来选择放置文本的位置。将原始图像调整为控件大小(对于水平图像),并且用户将文本拖动到该图像上。
基于Picturebox的SizeMode,使用以下代码将所选点转换为原始图像内的点
if (sizemode == 1) { transpoint = TranslateStretchImageMousePosition(new Point(eX - 20, eY -20)); } else if (sizemode == 2) { transpoint = TranslateZoomMousePosition(new Point(eX - 20, eY - 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 (pX < (ClientSize.Width - pX)) { LaunchOrigin.Xedge = 1; LaunchOrigin.Xspacing = pX; LaunchOrigin2.closestedge.Text = " "; LaunchOrigin2.closestedge.Text = LaunchOrigin2.closestedge.Text + " left"; } else { LaunchOrigin.Xedge = 2; LaunchOrigin.Xspacing = (ClientSize.Width - pX); LaunchOrigin2.closestedge.Text = " "; LaunchOrigin2.closestedge.Text = LaunchOrigin2.closestedge.Text + " right"; } //Finding closest Top/Bottom Edge if (pY < (ClientSize.Height - pY)) { LaunchOrigin.Yedge = 1; LaunchOrigin.Yspacing =pY; LaunchOrigin2.closestedge.Text = LaunchOrigin2.closestedge.Text + " top"; } else { LaunchOrigin.Yedge = 2; LaunchOrigin.Yspacing = (ClientSize.Height - pY); 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);
对于Logo我也是这样做的
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;
这非常有效,直到我将文本和徽标紧密放置。在自定义图片框中,控件文本和徽标正确显示。在主窗口中,对于垂直图像,它们显示正常,但对于水平图像,两者都重叠……这里出了什么问题? 请指教..
UPDATE
这很有效。但是我如何将点从主窗口转换为自定义图片框控件(带有允许拖动的文本)。
我尝试了以下代码。但这并没有给出精确的定位
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; }