【问题标题】:How can I transform XY coordinates and height/width on a scaled image to an original sized image?如何将缩放图像上的 XY 坐标和高度/宽度转换为原始大小的图像?
【发布时间】:2011-06-27 01:15:27
【问题描述】:

Related Question

我正在尝试做与链接问题相同的事情,但使用 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;
}

【问题讨论】:

  • 缩放图像的零在哪里?左上角还是左下角?
  • 您使用变换(2x2 矩阵)缩放图像。您使用该矩阵的逆矩阵执行坐标转换。请提供原始图像大小、位置和转换后图像大小、位置的具体数值示例 - 这让一些人更容易这样想,而且消除了一些歧义。
  • 这是 WPF 还是 Winfomrs?
  • @Conrad,它实际上在浏览器中。我正在使用 jquery 库在我的缩放图像上进行裁剪选择,并将其发送回服务器。
  • 矩阵变换无法处理像素表示不是点表示这一事实。像素是用于表示一个点的矩形。在用户选择的 (top,left) 像素的情况下,所表示的点是该像素的 (top,left) POINT。在(底部,右侧)像素的情况下,像素代表像素的(底部,右侧)点。只有将一个像素点转化为一个点,矩阵变换才能成功。我觉得这很难简洁地解释,如果我错了,请看我的回答并击落我:)

标签: c# image-scaling


【解决方案1】:

没有更多细节,我猜您实际上遇到了舍入错误...
- 当您将(上、左)坐标缩放回原始坐标时,您需要向下舍入(朝向左上角)。
- 当您将(底部,右侧)坐标缩放回原始坐标时,您需要向上取整(向右下方)

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

如果要简单地乘以相同的比例因子,则会得到 (3,3):(6,6)。


OriginalTop = INT(ScaledTop * YScalingFactor);
OriginalLeft = INT(ScaledLeft * XScalingFactor);

OriginalBottom = INT((ScaledBottom + 1) * YScalingFactor) - 1;
OriginalRight = INT((ScaledRight + 1) * XScalingFactor) - 1;


编辑:

更好的解释我想说的方法是画一张图片。我很讨厌 ASCII Art。所以这里是另一个单词的尝试。

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

当您使用像素来表示矩形的左上角时,您将包括从像素的最左上角开始的区域。

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


再次使用 (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;


唯一的考虑是确保在乘法之后不会溢出数据类型。但是有了图像,你就不会,除非它是一个地狱般的图像。

【讨论】:

  • 这可能是真的。我的作物出现在一般区域,但排列不正确。
  • 如何确定比例因子?只是 scaledY/origY?
  • 是的,只要确保将其保留为 Double 或其他漂亮且准确的东西。 (并计算不同的 X 和 Y 缩放因子)
  • 更好的是,您使用的数字足够小,可以仅使用整数来完成...请参阅我的下一个编辑...
  • 你让我对最后一点新/旧与原始/缩放感到困惑。
【解决方案2】:

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

pX1 = scaledX1/scaled_width
pY1 = scaledY1/scaled_height

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

【讨论】:

  • 虽然直观,但不处理右下角坐标。一个像素不是一个点,它是它自己的一个小矩形。您想要捕获像素矩形右下角的新坐标表示。
  • 使用这种方法似乎让我知道我在哪里。它仍然在一般区域,但不完全。
猜你喜欢
  • 2011-04-09
  • 2015-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多