Поиск способа сделать битовое XOR на изображениях - PullRequest
16 голосов
/ 14 декабря 2011

Я ищу способ получить Битовое XOR двух изображений в командной строке (или другим способом, который может быть реализован в программе или скрипте).

Этодолжно привести к тому же окончательному изображению, что и в режиме смешивания XOR в графических редакторах, которые его поддерживают (Paint.NET, Photoshop и т. д.)

Image A(Seattle, from the paint.net documentation

и Изображение B:

ImageB(Apple, from the paint.net documentation)

, тогда результат должен выглядеть так:

Image C(Xor result of above images, from the paint.net documentation)

Самое интересное в том, что, когда вы снова создадите XOR изображение C с изображением B, вы получите точную копию изображения A.

Теперь,Я искал во всем Интернете способ сделать это программно, но я ничего не нашел.Даже ImageMagick не поддерживает создание побитового XOR для изображений.

Кто-нибудь знает способ сделать это?

Ответы [ 6 ]

20 голосов
/ 14 декабря 2011

ImageMagick может сделать это, хотя это немного запутанно. Один из способов:

convert img1 img2 -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" img_out

(img1, img2, img_out - два имени файла входного и одного выходного файла соответственно).

Объяснение

Это немного уродливо (я уверен, что кто-то с большим количеством ImageMagick-fu, чем я, мог бы его почистить, но это работает так:

  1. -fx "xxx" в основном говорит «выполнить операцию xxx над изображением». В приведенном выше выражении u и v обозначают первое и второе входные изображения соответственно.

  2. Теперь -fx имеет только побитовое И & и побитовое ИЛИ | в виде побитовых операторов. Для восстановления побитового XOR нам нужно

    convert img1 img2 -fx "(u & NOT v) | (NOT u & v)" img_out
    
  3. Чтобы получить NOT (есть логическое NOT, но не поразрядное NOT), мы помним, что NOT x = 255-x , если x - 8-битный. Таким образом, чтобы получить NOT u, мы можем просто сделать 255-u, предполагая, что u является 8-битным. Следовательно, команда ImageMagick будет:

    convert img1.png img2.img -fx "((255-u)&v)|(u&(255-v))" image_xor.png
    
    • Единственная проблема здесь в том, что когда ImageMagick делает fx, он нормализует все пиксели в u и v в диапазоне [0,1] вместо [0,255], как мы ожидаем, и выполняет побитовое нецелые винты заполняют.

    • Следовательно, мы должны умножить все вхождений u и v в приведенном выше выражении на 255 (так что побитовые операции работают) и разделить на 255 в самом конце чтобы вернуться в диапазон [0,1], который ожидает ImageMagick.

Это дает нам исходную команду,

convert img1 img2 -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" img_out

Voila!

11 голосов
/ 14 октября 2016

Я обнаружил потребность в xor на изображении, и инструмент G'MIC работает для меня. G'MIC невероятно мощен, как и Image Magick, но стоит взглянуть на решение некоторых сложных проблем с обработкой изображений.

gmic a.png b.png -blend xor -o result.png

G'MIC также работает непосредственно с изображениями, размещенными выше.

gmic http://i.stack.imgur.com/Ws6e8.png http://i.stack.imgur.com/hoBIM.png -blend xor -o result.png

За помощь,

gmic -h -blend

enter image description here

5 голосов
/ 14 декабря 2011

Вот как бы я делал в Java:

Итерация по всем пикселям двух изображений одновременно. (для цикла (x) внутри цикла for (y)). Конечно, используйте BufferedImage. Вы можете получить цвет пикселя, выполнив:

int color = img.getRGB(x, y);

Сделайте то же самое для другого изображения и выполните операцию xor для двух цветов. Сохраните полученное значение в новом BufferedImage с теми же размерами, что и у двух входных изображений.

Вот пример кода:

public static BufferedImage xorEffect(BufferedImage imageA, BufferedImage imageB) {
    if (imageA.getWidth() != imageB.getWidth() ||
        imageA.getHeight() != imageB.getHeight())
    {
        throw new IllegalArgumentException("Dimensions are not the same!");
    }
    BufferedImage img = new BufferedImage(imageA.getWidth(),
                                          imageA.getHeight(),
                                          BufferedImage.TYPE_INT_ARGB_PRE);

    for (int y = 0; y < imageA.getHeight(); ++y) {
        for (int x = 0; x < imageA.getWidth(); ++x) {
           int pixelA = imageA.getRGB(x, y);
           int pixelB = imageB.getRGB(x, y);
           int pixelXOR = pixelA ^ pixelB;
           img.setRGB(x, y, pixelXOR);
        }
    }
    return img;
}

Чтобы загрузить изображение из файла, используйте:

BufferedImage imageA = ImageIO.read(new File("/home/username/image.png"));
2 голосов
/ 14 марта 2014

Если вы хотите сделать это сами, делайте это попиксельно. Если вы хотите библиотеку, я рекомендую OpenCV. Это очень хорошая и открытая библиотека с огромными операциями, поддерживаемыми в области обработки изображений. Он поддерживает прямой XOR с использованием оператора ^. Удачи.

1 голос
/ 14 декабря 2011

Зная, что

A XOR B = (A И НЕ B) ИЛИ (НЕ A И B).

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

Работая в Python, вы можете иметь простой скрипт, выполняющий операцию и даже добавляющий ее в качестве плагина в gimp;)

0 голосов
/ 25 октября 2017

OpenCV имеет все логические операторы на изображениях и пустых изображениях, используя bitwise_ #, где # может быть xor, и, и, не ... См. OpenCV - пересечение между двумя двоичными изображениями

...