问题描述
我想逐个像素地减去两个图像,以检查它们的相似程度。图像具有相同的尺寸,一个稍暗,而在亮度旁边它们没有差别。但是我在结果中得到了那些小点。我是否减去了这两个图像?两者都是bmp文件。
I wanted to subtract two images pixel by pixel to check how much they are similar. Images have the same size one is little darker and beside brightness they don't differ. But I get those little dots in the result. Did I subtract those two images rigth? Both are bmp files.
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class Main2 {
public static void main(String[] args) throws Exception {
int[][][] ch = new int[4][4][4];
BufferedImage image1 = ImageIO.read(new File("1.bmp"));
BufferedImage image2 = ImageIO.read(new File("2.bmp"));
BufferedImage image3 = new BufferedImage(image1.getWidth(), image1.getHeight(), image1.getType());
int color;
for(int x = 0; x < image1.getWidth(); x++)
for(int y = 0; y < image1.getHeight(); y++) {
color = Math.abs(image2.getRGB(x, y) - image1.getRGB(x, y));
image3.setRGB(x, y, color);
}
ImageIO.write(image3, "bmp", new File("image.bmp"));
}
}
图片1
Image 1
图片2
结果
推荐答案
这里的问题是你无法直接减去颜色。每个像素由一个 int
值表示。此 int
值由4个字节组成。这4个字节代表颜色分量ARGB,其中
The problem here is that you can't subtract the colors direcly. Each pixel is represented by one int
value. This int
value consists of 4 bytes. These 4 bytes represent the color components ARGB, where
A = Alpha
R = Red
G = Green
B = Blue
(Alpha是像素的不透明度,始终为255( BMP图像中的最大值)。
(Alpha is the opacity of the pixel, and always 255 (that is, the maximum value) in BMP images).
因此,一个像素可以表示为
Thus, one pixel may be represented by
(255,0,254,0)
(255, 0, 254, 0)
当你从这个像素中减去另一个像素时,如(255,0,255,0),那么第三个字节将下溢:它会变成-1。但由于这是一个整数的一部分,因此产生的颜色将类似于
When you subtract another pixel from this one, like (255, 0, 255, 0), then the third byte will underflow: It would become -1. But since this is part of ONE integer, the resulting color will be something like
(255, 0, 254, 0) -
(255, 0, 255, 0) =
(255, 255, 255, 0)
因此,与你在这种情况下的预期相差甚远。
and thus, be far from what you would expect in this case.
关键点是您必须将颜色分成A,R,G和B组件,并对这些组件执行计算。在最一般的形式中,它可以这样实现:
The key point is that you have to split your color into the A,R,G and B components, and perform the computation on these components. In the most general form, it may be implemented like this:
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
int a0 = (argb0 >> 24) & 0xFF;
int r0 = (argb0 >> 16) & 0xFF;
int g0 = (argb0 >> 8) & 0xFF;
int b0 = (argb0 ) & 0xFF;
int a1 = (argb1 >> 24) & 0xFF;
int r1 = (argb1 >> 16) & 0xFF;
int g1 = (argb1 >> 8) & 0xFF;
int b1 = (argb1 ) & 0xFF;
int aDiff = Math.abs(a1 - a0);
int rDiff = Math.abs(r1 - r0);
int gDiff = Math.abs(g1 - g0);
int bDiff = Math.abs(b1 - b0);
int diff =
(aDiff << 24) | (rDiff << 16) | (gDiff << 8) | bDiff;
result.setRGB(x, y, diff);
由于这些是灰度图像,因此这里完成的计算有些多余:对于灰度图像,R, G和B组件始终相等。由于不透明度始终为255,因此不必在此处明确处理。因此,对于您的特定情况,将其简化为
Since these are grayscale images, the computations done here are somewhat redundant: For grayscale images, the R, G and B components are always equal. And since the opacity is always 255, it does not have to be treated explicitly here. So for your particular case, it should be sufficient to simplify this to
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
// Here the 'b' stands for 'blue' as well
// as for 'brightness' :-)
int b0 = argb0 & 0xFF;
int b1 = argb1 & 0xFF;
int bDiff = Math.abs(b1 - b0);
int diff =
(255 << 24) | (bDiff << 16) | (bDiff << 8) | bDiff;
result.setRGB(x, y, diff);
这篇关于图像减法的结果不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!