我正在寻找一种方法来在命令行上获取两个图像的按位异或(或以可以在程序或脚本中实现的其他方式)。
这应该会产生与在支持 XOR 混合模式的图片编辑器(Paint.NET、Photoshop 等)中使用 XOR 混合模式相同的最终图片
举个例子,假设我有图像A:
和图像B:
那么结果应该是这样的:
其中有趣的部分当然是,当您再次将图像 C 与图像 B 进行异或时,您将获得图像 A 的精确副本。
现在,我一直在互联网上寻找一种以编程方式执行此操作的方法,但我一无所获。即使 ImageMagick 也不支持对图像进行按位异或。
有人知道如何做到这一点吗?
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
按位运算符的方式只有按位AND &
和按位OR |
。
为了重建按位异或,我们需要
convert img1 img2 -fx "(u & NOT v) | (NOT u & v)" img_out
为了得到
NOT
(有逻辑 NOT
但没有按位 NOT
),我们记住 NOT x = 255-x
if 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
瞧!
我发现图像上需要
xor
,并且 G'MIC 工具适合我。 G'MIC 非常强大,与 Image Magick 一样,但在解决一些棘手的图像处理问题方面值得一看。
gmic a.png b.png -blend xor -o result.png
G'MIC 也可以直接作用于上面发布的图像。
gmic https://i.stack.imgur.com/Ws6e8.png https://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 且非 B)或(非 A 且 B)。
大多数常见的图像处理工具都有 and、or 和 not 操作,剩下的就很简单了:)
在 Python 中工作,您可以使用一个简单的脚本来执行操作,甚至可以将其作为插件添加到 gimp 中;)
OpenCV 使用 bitwise_# 在图像和 numpy 图像上具有所有逻辑运算符,其中 # 可以是异或、和、和、不...请参阅 OpenCV - 两个二值图像之间的交集