Создание линейного градиента в 2D массиве - PullRequest
5 голосов
/ 06 февраля 2009

У меня есть двумерный растровый массив, скажем, 500 * 500 значений. Я пытаюсь создать линейный градиент на массиве, поэтому полученное растровое изображение будет выглядеть примерно так (в оттенках серого): Example gradient
(источник: showandtell-graphics.com )

Входными данными будут массив для заполнения, две точки (например, начальная и конечная точка для инструмента Градиент в Photoshop / GIMP) и диапазон значений, которые будут использоваться.

Мой лучший лучший результат:

альтернативный текст http://img222.imageshack.us/img222/1733/gradientfe3.png

... что далеко не то, чего я хотел бы достичь. Это больше похоже на радиальный градиент.

Какой самый простой способ создать такой градиент? Я собираюсь реализовать это на C ++, но мне нужен какой-то общий алгоритм.

Ответы [ 4 ]

14 голосов
/ 06 февраля 2009

Это действительно математический вопрос, поэтому может быть спорным, действительно ли он «принадлежит» при переполнении стека, но в любом случае: вам необходимо спроецировать координаты каждой точки изображения на ось вашего градиента и использовать эту координату определить цвет.

Математически я имею в виду:

  1. Скажите, что ваша начальная точка (x1, y1), а ваша конечная точка (x2, y2)
  2. Вычислить A = (x2 - x1) и B = (y2 - y1)
  3. Рассчитать C1 = A * x1 + B * y1 для начальной точки и C2 = A * x2 + B * y2 для конечной точки (C2 должно быть больше C1)
  4. Для каждой точки изображения рассчитайте C = A * x + B * y
  5. Если C <= C1, используйте начальный цвет; если C >= C2, используйте конечный цвет; в противном случае используйте средневзвешенное значение:

    (start_color * (C2 - C) + end_color * (C - C1))/(C2 - C1)

Я провел несколько быстрых тестов, чтобы убедиться, что это в основном работает.

3 голосов
/ 06 февраля 2009

На вашем примере изображения похоже, что у вас есть радиальный градиент. Вот мое импровизированное математическое объяснение шагов, которые вам понадобятся. Извините за математику, остальные ответы лучше с точки зрения реализации.

  1. Определите линейную функцию (например, y = x + 1) с доменом (то есть x) от цвета, с которого вы хотите начать, до цвета, которым вы хотите закончить. Вы можете думать об этом с точки зрения диапазона от Ox0 до OxFFFFFF (для 24-битного цвета). Если вы хотите работать с такими вещами, как яркость, вам придется проделать некоторые трюки с диапазоном (то есть значением y).
  2. Затем вам нужно отобразить вектор на имеющуюся у вас матрицу, так как это определяет направление, в котором будут меняться цвета. Кроме того, значения цвета, определенные вашей линейной функцией, будут назначаться в каждой точке вдоль вектора. Начальная и конечная точки вектора также определяют минимальное и максимальное значения области в 1. Вы можете думать о векторе как о одной линии вашего градиента.
  3. Для каждой ячейки в матрице цветам может быть присвоено значение из вектора, где перпендикулярная линия из ячейки пересекает вектор. См. Диаграмму ниже, где c - положение ячейки и. это точка пересечения. Если вы делаете вид, что цвет на. Красный, то это то, что вы назначите на ячейку.
             |
             c
             |
             |
    Vect:____.______________
             |
             |

1 голос
/ 09 февраля 2009

Я просто опубликую свое решение.

int ColourAt( int x, int y )
{
  float imageX = (float)x / (float)BUFFER_WIDTH;
  float imageY = (float)y / (float)BUFFER_WIDTH;

  float xS = xStart / (float)BUFFER_WIDTH;
  float yS = yStart / (float)BUFFER_WIDTH;
  float xE = xEnd / (float)BUFFER_WIDTH;
  float yE = yEnd / (float)BUFFER_WIDTH;
  float xD = xE - xS;
  float yD = yE - yS;

  float mod = 1.0f / ( xD * xD + yD * yD );

  float gradPos = ( ( imageX - xS ) * xD + ( imageY - yS ) * yD ) * mod;

  float mag = gradPos > 0 ? gradPos < 1.0f ? gradPos : 1.0f : 0.0f;

  int colour = (int)( 255 * mag );
  colour |= ( colour << 16 ) + ( colour << 8 );
  return colour;
}

Для ускорения кэшируйте полученные значения «направления» (подсказка: предварительно умножьте на mag).

0 голосов
/ 23 сентября 2010

Эта проблема состоит из двух частей.

  1. Учитывая два цвета A и B и некоторый процент p, определите, какой цвет лежит p в «процентах пути» от A до B.

  2. Для заданной точки на плоскости найдите ортогональную проекцию этой точки на данную линию.

Данная строка в части 2 является вашей градиентной линией. Для любой точки P спроецируйте ее на градиентную линию. Допустим, его проекция равна R. Затем выясните, как далеко R от начальной точки вашего градиентного сегмента, в процентах от длины градиентного сегмента. Используйте этот процент в вашей функции из части 1 выше. Вот такого должен быть цвет P.

Обратите внимание, что вопреки тому, что говорили другие люди, вы не можете просто рассматривать свои цвета как обычные числа в своей функции из части 1. Это почти наверняка не даст того, что вы хотите. То, что вы делаете, зависит от используемого вами цветового пространства. Если вам нужен градиент RGB, то вам нужно рассмотреть компоненты красного, зеленого и синего цветов отдельно.

Например, если вам нужен цвет "на полпути между" чисто красным и синим, то в шестнадцатеричной записи вы имеете дело с

ff 00 00

и

00 00 и далее

Возможно, нужный вам цвет - это что-то вроде

80 00 80

это хороший фиолетовый цвет. Вы должны усреднить каждый компонент цвета отдельно. Если вы попытаетесь просто усреднить шестнадцатеричные числа 0xff0000 и 0x0000ff напрямую, вы получите 0x7F807F, который имеет средний серый цвет. Я предполагаю, что это объясняет, по крайней мере, часть проблемы с изображением выше.

В качестве альтернативы, если вы находитесь в цветовом пространстве HSV, вы можете настроить только компонент оттенка и оставить остальные как есть.

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