Где взять алгоритм псевдокода для проецирования параллелограмма RGB в треугольник RGB - PullRequest
2 голосов
/ 08 января 2011

Какой будет алгоритм псевдокода для проецирования параллелограмма (2d массив точек (RGB)) в треугольник (2d массив точек (RGB)) (в моем конкретном случае прямоугольник в прямоугольный треугольник с таким же размером стороны (равнобедренный), и в моем случае Гипотенуза имеет тот же размер, который имеет наибольшую сторону прямоугольника), качество может быть потеряно.Итак, как выполнить такую ​​вещь в псевдокоде?

Так, в общем, у нас было, например, 300x200

alt text

Мы хотим исказить его в треугольник высоты 150 и ширины 200

с фейерверком CS5 - неправильный результат для меня

alt text

С фотошопом CS5 правильный результат

alt text

ИтакИнтересно, какой псевдокод для преобразований делает фотошоп?

1 Ответ

2 голосов
/ 12 января 2011

Я не уверен, что неправильно понял ваш вопрос, однако вот мои мысли. Я предполагаю, что проекция будет такой, что гипотенуза треугольника ориентирована в том же направлении, что и самая длинная сторона прямоугольника, поскольку вы сказали, что они будут одного размера. Некоторые грубые картинки (не в масштабе):

Прямоугольник 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 отдельных пикселей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...