I am looking for a way to get the bitwise XOR of two images on the command line (or in another way that can be implemented in a program or script).
This should result in the same final picture as using the XOR blending mode in picture editors that support it (Paint.NET, Photoshop, etc)
As an example, say I have Image A:
and Image B:
then the result should look like this:
The fun part of this is of course, that when you XOR image C with image B again, you will get an exact copy of image A.
Now, I have been looking all over the internet for a way to do this programmatically, but I have found nothing. Even ImageMagick does not support doing a bitwise XOR on images.
Does somebody know a way to do this?
ImageMagick can do it, although it's a bit convoluted. One way is:
convert img1 img2 -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" img_out
(img1
,img2
,img_out
are the two input and single output file names respectively).
It's a bit ugly (I'm sure someone with more ImageMagick-fu than me could clean it up but it works like this:
-fx "xxx"
basically says "perform the operation xxx
on the image".
In the expression above, u
and v
stand for the first and second input images respectively.
Now, -fx
only has bitwise AND &
and bitwise OR |
in the way of bitwise operators.
To reconstruct bitwise XOR, we need
convert img1 img2 -fx "(u & NOT v) | (NOT u & v)" img_out
To get the NOT
(there is a logical NOT
but no bitwise NOT
), we remember that NOT x = 255-x
if x
is 8-bit.
So to get NOT u
we can just do 255-u
, assuming image u
is 8-bit.
Hence, the ImageMagick command would be:
convert img1.png img2.img -fx "((255-u)&v)|(u&(255-v))" image_xor.png
The one problem here is that when ImageMagick does fx
it normalises all the pixels in u
and v
in the range [0,1]
instead of [0,255]
as we expect, and doing bitwise on non-integers screws stuff up.
Hence, we have to multiply all occurrences of u
and v
in the above expression by 255 (so the bitwise operations work), and divide by 255 at the very end to get back in the range [0,1]
that ImageMagick expects.
This gives us the original command,
convert img1 img2 -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" img_out
Voila!