Как наложить два изображения (в виде байтовых массивов) - PullRequest
3 голосов
/ 06 февраля 2010

Люди, я уверен, что это довольно просто, но Google не помог ...

Вот задача - у меня есть два байтовых массива (как ARGB), представляющих мои изображения. Они имеют одинаковый размер. Какую операцию я должен выполнить (побайтно), чтобы наложить одно изображение на другое? Второе изображение имеет некоторую прозрачность, которую необходимо учитывать.

Чтобы очистить, я ищу код, подобный этому:

          bytes[] result = new bytes[first.Length];
          for(i = 0; i< first.Lenght;i++)
          {
               result[i] = first[i] !!%SOMETHING%!! second[i];
          }

Простые догадки, такие как побитовое ИЛИ (я знаю - это глупо;)) не работают.

Спасибо за ваши ответы.

edit: я не могу использовать стандартную библиотеку из-за проблем безопасности (все эти странные манипуляции происходят в Silverlight).

Ответы [ 2 ]

7 голосов
/ 06 февраля 2010

Предполагая, что вы на самом деле работаете с растровыми изображениями, вам, вероятно, будет проще просто позволить библиотеке сделать это за вас.

Класс System.Drawing.Graphics имеет свойство CompositingMode, которое можно установить либо на SourceCopy (по умолчанию - перезаписывает цвет фона), либо на SourceOver (смешивается с цветом фона).

Подробнее см. MSDN: как использовать режим наложения для управления альфа-смешиванием .

Если вам нужна только математика, альфа-смешивание довольно простое. Для альфа-значения a между 0,0 и 1,0 результат должен быть:

(aOld * oldValue) + ((1 - aOld) * aNew * newValue)

Где oldValue - предыдущее значение перед наложением, newValue - то, с чем вы хотите наложить, а aOld и aNew - старое и новое альфа-значения соответственно. Очевидно, что вам нужно выполнить этот расчет для значений R, G и B. отдельно.

См. Также: Альфа-композитинг (вики-ссылка) для более подробного объяснения.


Обновление: я думаю, что должно быть легко понять, как адаптировать это к коду в OP, но я думаю, что не все математики.

Я собираюсь предположить, что byte[] является повторяющейся последовательностью значений A, R, G, B (поэтому Length будет кратным 4). Если это не так, вам придется адаптировать этот код к любому формату хранения, который вы используете.

bytes[] result = new bytes[first.Length];
for(i = 0; i < first.Length; i += 4)
{
    byte a1 = first[i];
    byte a2 = second[i];
    byte r1 = first[i+1];
    byte r2 = second[i+1];
    byte g1 = first[i+2];
    byte g2 = second[i+2];
    byte b1 = first[i+3];
    byte b2 = second[i+3];

    byte a = a1 + (255 - a1) * a2 / 255;
    byte r = r1 * a1 / 255 + r2 * (255 - a1) * a2 / 65025;
    byte g = g1 * a1 / 255 + g2 * (255 - a1) * a2 / 65025;
    byte b = b1 * a1 / 255 + b2 * (255 - a1) * a2 / 65025;

    result[i] = a;
    result[i+1] = r;
    result[i+2] = g;
    result[i+3] = b;
}
0 голосов
/ 06 февраля 2010

Я думаю, у вас правильная идея. Используемая вами операция зависит от того, что вы хотите для вывода. Вот некоторые полезные операции:

  1. средний - общий способ объединения
  2. минимум
  3. максимальный
  4. побитовая замена
  5. исключающее
  6. или
  7. добавить
  8. вычитать
  9. умножить значение изображения 1 на (изображение 2 масштабируется от 0 до 1). Это позволит разместить больше изображения 1 на ярких местах изображения 2, а не на темных местах. Попробуйте их и посмотрите, что вам больше нравится, или еще лучше, дайте пользователю выбрать.

Можно добавить или байты прозрачности, и использовать одну из других операций для каждого из трех цветов.

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