哪里可以获得将 RGB 平行四边形投影为 RGB 三角形的伪代码算法

发布于 2024-10-11 14:12:14 字数 509 浏览 3 评论 0原文

将平行四边形(RGB 点的二维数组)投影到三角形(RGB 点的二维数组)中的伪代码算法是什么(在我的特定情况下,将矩形投影到具有相同边尺寸(等腰)的直角三角形中,并且在我的例子中,斜边的大小与矩形的最大边相同)质量可能会丢失。那么如何用伪代码执行这样的事情呢?

因此,通常我们有例如 300x200

alt text

我们想

用 Fireworks CS5 将其扭曲成 150 高度和 200 宽度的三角形 - 不是对我来说正确的结果

alt text

使用 Photoshop CS5 正确的结果

alt text

所以我想知道 Photoshop 的变换伪代码是什么?

What would be pseudo code algorithm fo projecting a parallelogram (2d array of (RGB) points) into a triangle (2d array of (RGB) points) (in my particular case a Rectangle into a Right Triangle with same side size (isosceles) and in my case Hypotenuse is same size that has biggest side of a Rectangle) qualyty may be lost. So how to perform such thing in pseudocode?

So generally we had for example 300x200

alt text

We eant to distort it into 150 height and 200 width triangle

with fireworks CS5 - not correct result for me

alt text

With photoshop CS5 correct result

alt text

So I wonder what would be pseudocode for transformations photoshop does?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

¢蛋碎的人ぎ生 2024-10-18 14:12:15

我不确定我是否误解了你的问题,但这是我的想法。我假设投影将使得三角形的斜边与矩形的最长边的方向相同,因为您说它们的大小相同。一些粗略的图片(未按比例):

矩形 H=4,W=10

---------
|       |
|       |
---------

三角形 Hyp=10,S1=8,S2=6

      .
   .   |
.      |
--------

所以我的建议是进行映射,使矩形的“块”等同于具有三角形,每个三角形点是相关矩形块的 RGB 平均值,请注意,根据原始对象的比例,块可能会重叠。

更具体地说,回到上面的例子,首先是比率,高度比率将是固定的,矩形的高度为4,三角形的高度为6,因此对于三角形中垂直的每个像素考虑6/4,或者矩形中的1.5。现在有两个选项来处理“.5”,您可以考虑向上舍入或向下舍入并仅使用整个块,或者您可以对小数部分使用权重。由于后一种情况不那么简单,我们将进一步研究它。

当我们垂直移动时,任何小数部分都将转换为该行像素的小数权重,因此,如果我们垂直平均并且像素为 128 和 137(为简单起见,仅查看一个组件),那么我们的平均值将为

(128+(0.5 *137))/1.5 = (128+68.5)/1.5 = 196.5/1.5 = 131

现在,由于我们正在查看小数部分,因此我们需要跟踪未使用的小数部分,因此如果上面的下一个像素是 100我们想看看

((137*0.5)+100)/1.5 = (68.5+100)/1.5 = 168.5/1.5 = 112.3

现在我们遵循类似的策略,在三角形上垂直向上逐行移动,调整比率为三角形的宽度减小,因此对于斜边 = 矩形的底边,这将是 1。再往上,您可能会得到一个比率,例如 1.23,并且可以进行上述计算。

最后是一些粗略的伪代码:

map(rectangle, triangle) {

  decimal yRatio = triangle.height / rectangle.height
  decimal lastY = 0;//we need decimal indeices for fractional averages

  for each line in dest height (yIndex, 0 based) {
    //here you could even find the average width of the rectangle
    //over the block height, but we won't bother
    decimal xRatio = triangle[yIndex].width / rectangle[floor(yIndex*yRatio)].width
    decimal lastX = 0;    //again a decimal for fractional averages

    for each pixel in dest line width (xIndex, 0 based) {

        decimal pixelAverage = 0;
        decimal tempYRatio = yRatio;
        decimal destY = yRatio * yIndex;

        //Here we calculate the source pixel block average
        while(tempYRatio > 0) {
          //the portion of this row of pixels we use is the minimum
          //of the distance to the next integer, and what we need
          decimal yFraction = minimum(tempYRatio, nextInt(destY) - destY);

          decimal tempXRatio = xRatio;
          decimal destX = xRatio * xIndex;
          while(tempXRatio > 0) {
            decimal xFraction = minimum(tempXRatio, nextInt(destX) - destX);
            //now add the weighted pixel to the average
            average += rectangle[floor(destY)][floor(destX)]*xFraction*yFraction;

            tempXRatio -= xFraction;  //reduce the block size
            destX += xFraction;       //and shift the source index
          }

          tempYRatio -= yFraction;  //reduce the block size
          destY += yFraction;       //and shift the source index
        }

        destination[yIndex][xIndex] = average / (xRatio*yRatio);
    }
  }
}
//a helper function to find the next integer value
integer nextInt(decimal d) {
  integer ret = ceiling(d);
  return d == ret ? d+1 : ret;
}

这超出了我的想象,所以我不能保证它完全正确,但至少应该是一个好的开始,对个体的每个 RGB 分量进行适当的平均像素。

I'm not sure if I am misinterpreting your question, however here are my thoughts. I am assuming that the projection will be such that the hypotenuse of the triangle is oriented in the same direction as the longest side of the rectangle, since you said they will be the same size. Some crude pictures (not to scale):

Rectangle H=4, W=10

---------
|       |
|       |
---------

Triangle Hyp=10, S1=8, S2=6

      .
   .   |
.      |
--------

So my suggestion is to do the mapping such that "blocks" of the rectangle are equated to points with the triangle, and each triangle point is an RGB average of the associated rectangle blocks, noting that the blocks may overlap depending on the scale of the original objects.

More concrete, back to the above example first the ratios, the height ratio will be fixed, the rectangle is height 4, the triangle is height 6, so for each pixel vertically in the triangle consider 6/4, or 1.5 in the rectangle. Now there are two options to deal with the ".5", you could either consider rounding up, or down and using only whole blocks, or you could use weights for fractional sections. Since the latter case is less trivial we will look into it further.

As we move vertically any fractional portion will be converted to a fractional weight of that row's pixel so if we are averaging vertically and our pixels are 128 and 137 (only looking at one component for simplicity) then our average would be

(128+(0.5*137))/1.5 = (128+68.5)/1.5 = 196.5/1.5 = 131

Now, since we are looking fractionally we need to keep track of the fractional portion we haven't used, so if the next pixel above is 100 we would want to look at

((137*0.5)+100)/1.5 = (68.5+100)/1.5 = 168.5/1.5 = 112.3

Now we follow a similar strategy moving line by line vertically up the triangle adjusting the ratio as the width of the triangle decreases, so for the base where hypotenuse=rectangle this would trivially be 1. Farther up you may have a ratio such as 1.23 and can do the calculations as above.

Finally some rough pseudocode:

map(rectangle, triangle) {

  decimal yRatio = triangle.height / rectangle.height
  decimal lastY = 0;//we need decimal indeices for fractional averages

  for each line in dest height (yIndex, 0 based) {
    //here you could even find the average width of the rectangle
    //over the block height, but we won't bother
    decimal xRatio = triangle[yIndex].width / rectangle[floor(yIndex*yRatio)].width
    decimal lastX = 0;    //again a decimal for fractional averages

    for each pixel in dest line width (xIndex, 0 based) {

        decimal pixelAverage = 0;
        decimal tempYRatio = yRatio;
        decimal destY = yRatio * yIndex;

        //Here we calculate the source pixel block average
        while(tempYRatio > 0) {
          //the portion of this row of pixels we use is the minimum
          //of the distance to the next integer, and what we need
          decimal yFraction = minimum(tempYRatio, nextInt(destY) - destY);

          decimal tempXRatio = xRatio;
          decimal destX = xRatio * xIndex;
          while(tempXRatio > 0) {
            decimal xFraction = minimum(tempXRatio, nextInt(destX) - destX);
            //now add the weighted pixel to the average
            average += rectangle[floor(destY)][floor(destX)]*xFraction*yFraction;

            tempXRatio -= xFraction;  //reduce the block size
            destX += xFraction;       //and shift the source index
          }

          tempYRatio -= yFraction;  //reduce the block size
          destY += yFraction;       //and shift the source index
        }

        destination[yIndex][xIndex] = average / (xRatio*yRatio);
    }
  }
}
//a helper function to find the next integer value
integer nextInt(decimal d) {
  integer ret = ceiling(d);
  return d == ret ? d+1 : ret;
}

This is off the top of my head, so I can't guarantee it is completely correct, but it should be a good start at the very least performing the averages as appropriate with each of the RGB components of the individual pixels.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文