Используйте ImageMagick для получения оригинальной маски из двух составных изображений - PullRequest
1 голос
/ 14 мая 2011

Когда-то было изображение, возможно с альфа-прозрачностью, наложенное как на белый, так и на черный фон. У меня есть доступ к двум полученным изображениям, но не к оригиналу, и я хочу получить оригинал.

У меня есть некоторый код на Ruby, написанный для этого, но я думаю, просто потому, что нахожусь в Ruby, это не так быстро, как должно быть. Вот основная логика, перебирая пиксель за пикселем:

if pixel_on_black == pixel_on_white
  # Matching pixels indicate 100% opacity in the original.
  original_pixel = pixel_on_black
elsif color_on_black == BLACK && color_on_white == WHITE
  # Black on black and white on white indicate 0% opacity in the original.
  original_pixel = TRANSPARENT
else
  # Since it's not one of the simple cases, then we'll do some math.
  # Fancy algebra tells us the following. (MAX_VALUE is the largest value
  # a channel can have. So, in most cases, 255.)

  # First, find the alpha value. This equation follows from the equations
  # for composing on black and composing on white.
  alpha = pixel_on_black.red - pixel_on_white.red + MAX_VALUE

  # Now that we know the alpha value, undo its multiplicative effect on the
  # pixel on black. By dividing. Ta da.
  alpha_ratio = alpha / MAX_VALUE
  original_pixel = Pixel.new
  original_pixel.red   = pixel_on_black.red   / alpha_ratio
  original_pixel.green = pixel_on_black.green / alpha_ratio
  original_pixel.blue  = pixel_on_black.blue  / alpha_ratio
  original_pixel.alpha = alpha
end

Так это хорошо, и это работает, и все. Однако этот код должен в конечном итоге работать молниеносно, и итерация пикселей в Ruby недопустима. Похоже, если эта функция где-то уже не существует, в моих интересах было бы предложить серию опций ImageMagick, которые бы сработали.

Я сейчас исследую инструмент командной строки ImageMagick, потому что он выглядит действительно очень мощным и выглядит как -fx или ряд причудливых -function аргументов, которые будут делать то же самое, что и мой код выше. Я тоже буду пытаться, но есть ли профессионалы ImageMagick, которые уже знают, как собрать все это вместе?

РЕДАКТИРОВАТЬ: У меня есть -fx версия работает сейчас:)

convert image_on_black.png image_on_white.png -matte -channel alpha -fx "u.r + 1 - v.r" -channel RGB -fx "(u.a == 0) ? 1 : (u / u.a)" output.png

Практически точный перевод оригинального кода, разбитого на каналы. Выполните итерацию по альфа-каналу и установите правильные альфа-значения. Затем выполните итерацию по каналам RGB и разделите канал по альфа-значению (если только он не равен нулю, в этом случае мы можем установить его на что угодно, поскольку при делении на ноль выдается ошибка - в данном случае я выбрал 1 для белого). 1018 *

Теперь настало время поработать над их преобразованием в более явные аргументы, поскольку выражение -fx переоценивается для каждого пикселя, что не очень хорошо.

1 Ответ

0 голосов
/ 14 мая 2011

Mkay, я удивил себя здесь, и я думаю, что нашел ответ. Это четыре команды ImageMagick, хотя, может быть, их можно как-то объединить ... хотя я в этом сомневаюсь.

convert input_on_white.png -channel RGB -negate /tmp/convert_negative.png && \
convert input_on_black.png /tmp/convert_negative.png -alpha Off -compose Plus -composite /tmp/convert_alpha.png && \
composite plasma2.png /tmp/convert_alpha.png -alpha Off -channel RGB -compose Divide /tmp/convert_division.png && \
convert /tmp/convert_division.png /tmp/convert_alpha.png -compose CopyOpacity -composite plasma_output.png

(Очевидно, когда это будет сделано, очистите эти временные файлы. Кроме того, используйте реальную систему временных файлов вместо жестко закодированных путей.)

Стратегия заключается в том, чтобы сначала создать изображение в градациях серого, представляющее альфа-маску. Мы будем эмулировать строку кода alpha = pixel_on_black.red - pixel_on_white.red + MAX_VALUE, которую можно переписать как alpha = pixel_on_black.red + (MAX_VALUE - pixel_on_white.red).

Итак, строка 1: мы создаем изображение, представляющее второй член этого уравнения, отрицательную версию RGB-каналов изображения на белом. Мы сохраняем его как временный файл.

Затем, строка 2: мы хотим добавить это негативное изображение к изображению на черном. Используйте композицию ImageMagick's Plus и сохраните ее как временную альфа-маску. В результате получается изображение в градациях серого, где белый представляет области, которые должны иметь непрозрачность 100% в конечном изображении, а черный представляет области, которые впоследствии будут полностью прозрачными.

Затем, строка 3: вернуть изображение на черном цвете к исходным цветам RGB. Поскольку изображение на черном было создано путем наложения каналов RGB на альфа-отношение, мы делим изображение альфа-маски, чтобы отменить этот эффект.

Наконец, строка 4: возьмите изображение с цветовой коррекцией из строки 3 и примените альфа-маску из строки 2, используя функцию композиции ImageOagick CopyOpacity. Та да!

Моя оригинальная стратегия заняла где-то 5-10 секунд. Эта стратегия занимает меньше секунды. Намного, намного, намного лучше.

Неудивительно, что просьба о помощи - вот что заставило меня найти ответ самому. В любом случае, я оставлю этот вопрос открытым на 48 часов, чтобы посмотреть, найдет ли кто-нибудь чуть более оптимальное решение. Спасибо!

...