如何将经过缩放的图像上的XY坐标和高度/宽度转换为原始大小的图像?

15

相关问题

我试图在 C# 中完成与链接问题中相同的操作。我正在显示一个缩放后的图像,并允许用户选择要裁剪的区域。然而,我不能仅从缩放图像的选择中取得 x1y1、x2y2 坐标并从原始图像中进行裁剪。我尝试了一些基本的数学计算,比如在其他问题中,但显然这不是正确的方法(它肯定更接近)。

编辑

原始图像尺寸:w = 1024 h = 768

缩放图像尺寸:w = 550 h = 412

我开始有一张图片,比如1024x768。我想将其尽可能地放在一个550x550的盒子中。我使用以下方法获取缩放后的图像大小(同时保持纵横比)。然后我对这些新尺寸进行了基本的调整。

至于选择区域,它可以是任何东西(0,0)到(100,100)。

private static Rectangle MaintainAspectRatio(Image imgPhoto, Rectangle thumbRect)
{
    int sourceWidth = imgPhoto.Width; int sourceHeight = imgPhoto.Height; int sourceX = 0; int sourceY = 0; int destX = 0; int destY = 0;

    float nPercent = 0;
    float nPercentW = 0;
    float nPercentH = 0;

    nPercentW = ((float)thumbRect.Width / (float)sourceWidth);
    nPercentH = ((float)thumbRect.Height / (float)sourceHeight);

    //if we have to pad the height pad both the top and the bottom
    //with the difference between the scaled height and the desired height
    if (nPercentH < nPercentW)
    {
        nPercent = nPercentH;
        destX = (int)((thumbRect.Width - (sourceWidth * nPercent)) / 2);
    }
    else
    {
        nPercent = nPercentW;
        destY = (int)((thumbRect.Height - (sourceHeight * nPercent)) / 2);
    }

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);

    Rectangle retRect = new Rectangle(thumbRect.X, thumbRect.Y, destWidth, destHeight);
    return retRect;
}

1
缩放后的图像的零点在哪里?在左上角还是左下角? - Felice Pollano
1
你可以使用转换(2x2矩阵)来缩放图像。你可以通过该矩阵的逆进行坐标转换。请提供原始图像大小、位置和变换后图像大小、位置的具体数字示例,这样更容易理解,也能消除一些不确定性。 - Hamish Grubijan
这是WPF还是WinForms? - Conrad Frix
@Conrad,实际上是在浏览器中。我正在使用jquery库在我的缩放图像上获取裁剪选择,并将其发送回服务器。 - scottm
矩阵变换无法处理像素表示不是点表示的事实。像素是用于表示点的矩形。对于用户选择的(顶部,左侧)像素,所表示的点是该像素的(顶部,左侧)点。而对于(底部,右侧)像素,则表示像素的(底部,右侧)点。只有当像素被转换为点时,矩阵变换才能成功。我发现很难简洁地解释这一点,请查看我的答案,如果我错了请指出 :) - MatBailie
2个回答

13
缺乏更多细节,我猜想您实际上正在遭受舍入误差的困扰...
- 当你将(top,left)坐标缩放回原始大小时,需要向下舍入(靠近左上角)。
- 当你将(bottom,right)坐标缩放回原始大小时,需要向上舍入(靠近右下角)。

以12x12网格为原始版本,4x4网格为缩放版本的简单示例。
- 缩放版本上的(1,1):(2,2)=原始版本上的(3,3):(8,8)
- 2x2像素=缩放版本面积的25%
- 6x6像素=原始版本面积的25%

如果简单地乘以相同的比例因子,这将给出(3,3):(6,6)。


原始顶部=INT(已缩放顶部* YScalingFactor);
原始左侧=INT(已缩放左侧* XScalingFactor);

原始底部=INT((已缩放底部+1)* YScalingFactor)-1;
原始右侧=INT((已缩放右侧+1)* XScalingFactor)-1;


编辑

更好的解释我想要说的话是画一张图片。 ASCII艺术我很菜。 因此,这里有另一种尝试。

像素不是点。 它本身就是一个小矩形。

当您使用像素表示矩形的左上角时,您包括来自该像素最左上角点的区域。

当您使用像素表示矩形的< strong>右下角 时,您包括一直到像素最< strong>右下角 点的区域。


再次使用(12x12)=>(4x4)示例,每个缩放像素表示原始图像中整个3x3像素组。 在谈论左上角时,选择原始3x3像素组的左上角像素。 谈到右下时,选择原始3x3像素组的右下。


编辑:仅使用整数。

NewTop    = ((   OldTop    ) * NewHeight / OldHeight);
NewLeft   = ((   OldLeft   ) * NewWidth  / OldWidth );

NewBottom = ((OldBottom + 1) * NewHeight / OldHeight) - 1;
NewRight  = ((OldRight  + 1) * NewWidth  / OldWidth ) - 1;

唯一需要考虑的是确保在乘法后不会造成数据类型溢出。但对于图像来说,除非是一个极其大的图像,否则不会发生。


这可能是真的。我的作物出现在一般区域,但没有完全对齐。 - scottm
你如何确定缩放因子?只是scaledY/origY吗? - scottm
是的,只需确保将其保持为Double或其他精度较高的浮点数。 (并计算不同的X和Y缩放因子) - MatBailie
更好的是,你使用的数字足够小,可以仅使用整数来完成...请看我的下一个修改... - MatBailie
你让我对最后那一段新/旧与原版/缩放感到困惑了。 - scottm
显示剩余2条评论

0

您可以获取缩放图像的百分比位置,并将它们转换回未缩放图像的坐标:

pX1 = scaledX1/scaled_width
pY1 = scaledY1/scaled_height

unscaledX1 = ceiling(unscaled_width * pX1)
unscaledY1 = ceiling(unscaled_height * pY1)

1
虽然直观,但它无法处理右下坐标。像素不是点,而是自己的小矩形。您需要捕获像素矩形底部右侧的新坐标表示。 - MatBailie
使用这种方法似乎让我达到了大致的位置,但还不够准确。 - scottm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接