我希望找到一种方法在命令行(或者其他可用于程序或脚本)上获取两张图片的按位异或。
这应该会得到与支持XOR混合模式的图片编辑器(Paint.NET,Photoshop等)中使用相同的最终图片。
举个例子,假设我有图像A:
和图像B:
现在,我已经在互联网上搜索了很久,想找到一种以编程方式实现这个过程的方法,但我什么也没找到。即使是ImageMagick也不支持对图像进行按位异或运算。
有人知道如何做吗?
我希望找到一种方法在命令行(或者其他可用于程序或脚本)上获取两张图片的按位异或。
这应该会得到与支持XOR混合模式的图片编辑器(Paint.NET,Photoshop等)中使用相同的最终图片。
举个例子,假设我有图像A:
和图像B:
ImageMagick可以实现,虽然有点复杂。其中一种方法是:
convert img1 img2 -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" img_out
(img1
, img2
, img_out
分别是两个输入文件和一个输出文件的文件名。)
这段代码有点混乱(我相信某些比我更懂ImageMagick的人可以整理得更好,但它就是这样运作的:
-fx "xxx"
基本上表示“对图像执行操作xxx
”。
在上面的表达式中,u
和v
分别代表第一个和第二个输入图像。
现在,-fx
只有位与&
和位或|
这两种按位运算符。
要重建位异或运算,我们需要使用
convert img1 img2 -fx "(u & NOT v) | (NOT u & v)" img_out
要获取NOT
(有逻辑非但没有按位非),我们要记住如果x
是8位,那么NOT x = 255-x
。
因此,要获取 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,255]
标准化为 [0,1]
范围,而对非整数进行位运算会导致出现问题。
因此,我们需要将上述表达式中所有的 u
和 v
的出现次数乘以 255(这样位运算才能正常工作),并在最后除以 255,以恢复到 ImageMagick 所期望的 [0,1]
范围。
这给了我们原始命令,
convert img1 img2 -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" img_out
这就是了!
我发现需要在图像上使用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
以下是我在Java中的做法:
同时迭代两个图像的所有像素(在for循环(y)内部使用for循环(x))。当然,要使用 BufferedImage
。您可以通过以下方法获取像素的颜色:
int color = img.getRGB(x, y);
同样的方法也要用在另一张图片上,并将两种颜色进行异或操作,将结果值存储在一个新的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"));
如果你想要自己做,就要一像素一像素地完成。如果你需要一个库,我推荐 OpenCV
。这是一个非常好的开源库,在图像处理领域支持大量运算。它支持使用 ^
运算符进行直接的 XOR 运算。祝好运。
知道
A XOR B = (A AND NOT B) OR (NOT A AND B)。
而且,大多数常见的图像处理工具都具有and、or和not操作,因此其余部分非常容易 :)
在Python中工作,您可以编写一个简单的脚本执行该操作,甚至将其添加为gimp的插件 ;)
OpenCV具有对图像和numpy图像进行位运算的所有逻辑运算符,其中#可以是xor、and、or、not等... 请参见OpenCV - 两个二进制图像之间的交集。