在JAVA中,我试图以编程方式判断屏幕上显示的图像是否相等(即使它们具有不同的color spaces,也是相同的图像。是否有一段代码在呈现时会返回一个布尔值2图象?
我的一个例子是RGB PNG,我转换为灰度PNG。两个图像看起来都一样,我想以编程方式证明这一点。另一个例子是两个图像,它们在屏幕上显示完全相同的颜色像素,但用于100%透明像素的颜色已经改变。
答案 0 :(得分:4)
对于灰度图像,我使用均方误差作为衡量两幅图像之前的差异的方法。只需将每个图像中的相应像素插入公式即可。
这不仅可以告诉你它们是否完全相同,而且它可以告诉你两个图像的不同之处,尽管它们是相当粗糙的。
https://en.wikipedia.org/wiki/Mean_squared_error
修改强>
注意:这是C#代码而不是Java(道歉,但这是我最初写的),但它应该很容易转移。
//Calculates the MSE between two images
private double MSE(Bitmap original, Bitmap enhanced)
{
Size imgSize = original.Size;
double total = 0;
for (int y = 0; y < imgSize.Height; y++)
{
for (int x = 0; x < imgSize.Width; x++)
{
total += System.Math.Pow(original.GetPixel(x, y).R - enhanced.GetPixel(x, y).R, 2);
}
}
return (total / (imgSize.Width * imgSize.Height));
}
答案 1 :(得分:4)
我查看了所有解决方案,并确定他们可以告诉您图像对于某些类型的图像有多么不同或不同,但不是全部。这是我提出的解决方案......
package image.utils;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility methods used to interact with images.
*/
public class ImageUtils {
private final static Logger logger = LoggerFactory.getLogger(ImageUtils.class);
private static final boolean equals(final int[] data1, final int[] data2) {
final int length = data1.length;
if (length != data2.length) {
logger.debug("File lengths are different.");
return false;
}
for(int i = 0; i < length; i++) {
if(data1[i] != data2[i]) {
//If the alpha is 0 for both that means that the pixels are 100%
//transparent and the color does not matter. Return false if
//only 1 is 100% transparent.
if((((data1[i] >> 24) & 0xff) == 0) && (((data2[i] >> 24) & 0xff) == 0)) {
logger.debug("Both pixles at spot {} are different but 100% transparent.", Integer.valueOf(i));
} else {
logger.debug("The pixel {} is different.", Integer.valueOf(i));
return false;
}
}
}
logger.debug("Both groups of pixels are the same.");
return true;
}
private static final int[] getPixels(final BufferedImage img, final File file) {
final int width = img.getWidth();
final int height = img.getHeight();
int[] pixelData = new int[width * height];
final Image pixelImg;
if (img.getColorModel().getColorSpace() == ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
pixelImg = img;
} else {
pixelImg = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(img, null);
}
final PixelGrabber pg = new PixelGrabber(pixelImg, 0, 0, width, height, pixelData, 0, width);
try {
if(!pg.grabPixels()) {
throw new RuntimeException();
}
} catch (final InterruptedException ie) {
throw new RuntimeException(file.getPath(), ie);
}
return pixelData;
}
/**
* Gets the {@link BufferedImage} from the passed in {@link File}.
*
* @param file The <code>File</code> to use.
* @return The resulting <code>BufferedImage</code>
*/
@SuppressWarnings("unused")
final static BufferedImage getBufferedImage(final File file) {
Image image;
try (final FileInputStream inputStream = new FileInputStream(file)) {
// ImageIO.read(file) is broken for some images so I went this
// route
image = Toolkit.getDefaultToolkit().createImage(file.getCanonicalPath());
//forces the image to be rendered
new ImageIcon(image);
} catch(final Exception e2) {
throw new RuntimeException(file.getPath(), e2);
}
final BufferedImage converted = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = converted.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return converted;
}
/**
* Compares file1 to file2 to see if they are the same based on a visual
* pixel by pixel comparison. This has issues with marking images different
* when they are not. Works perfectly for all images.
*
* @param file1 First file to compare
* @param file2 Second image to compare
* @return <code>true</code> if they are equal, otherwise
* <code>false</code>.
*/
private final static boolean visuallyCompareJava(final File file1, final File file2) {
return equals(getPixels(getBufferedImage(file1), file1), getPixels(getBufferedImage(file2), file2));
}
/**
* Compares file1 to file2 to see if they are the same based on a visual
* pixel by pixel comparison. This has issues with marking images different
* when they are not. Works perfectly for all images.
*
* @param file1 Image 1 to compare
* @param file2 Image 2 to compare
* @return <code>true</code> if both images are visually the same.
*/
public final static boolean visuallyCompare(final File file1, final File file2) {
logger.debug("Start comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath());
if(file1 == file2) {
return true;
}
boolean answer = visuallyCompareJava(file1, file2);
if(!answer) {
logger.info("The files \"{}\" and \"{}\" are not pixel by pixel the same image. Manual comparison required.", file1.getPath(), file2.getPath());
}
logger.debug("Finish comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath());
return answer;
}
/**
* @param file The image to check
* @return <code>true</code> if the image contains one or more pixels with
* some percentage of transparency (Alpha)
*/
public final static boolean containsAlphaTransparency(final File file) {
logger.debug("Start Alpha pixel check for {}.", file.getPath());
boolean answer = false;
for(final int pixel : getPixels(getBufferedImage(file), file)) {
//If the alpha is 0 for both that means that the pixels are 100%
//transparent and the color does not matter. Return false if
//only 1 is 100% transparent.
if(((pixel >> 24) & 0xff) != 255) {
logger.debug("The image contains Aplha Transparency.");
return true;
}
}
logger.debug("The image does not contain Aplha Transparency.");
logger.debug("End Alpha pixel check for {}.", file.getPath());
return answer;
}
}
答案 2 :(得分:1)
如果您的意思完全相同,请比较每个像素。
如果你的意思是比较RGB图像和灰度图像,你需要先将RGB转换为灰度,为此,你需要知道你之前是如何做RGB-&gt; Greyscale,有不同的做法这可以得到不同的结果。
编辑,如果它在RGB-&gt; Greyscale中使用的方法是线性的,你可以通过比较3个像素来计算公式grey = a*R + b*G + c*B
中的a,b,c。
答案 3 :(得分:0)
我尝试的最简单方法之一是获取两个图像的像素数组,并将它们与Arrays.equals方法进行比较。 代码示例:
package image_processing;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.imageio.ImageIO;
public class CheckPixels {
public static void main(String args[]) throws IOException {
File pic1 = new File("D:\\ani\\img1.png");
File pic2 = new File("D:\\ani\\img2.png");
if (Arrays.equals(returnPixelVal(pic1), returnPixelVal(pic2))) {
System.out.println("Match");
} else {
System.out.println("No match");
}
}
public static byte[] returnPixelVal(File in) {
BufferedImage img = null;
File f = null;
byte[] pixels = null;
// read image
try {
f = in;
img = ImageIO.read(f);
pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
} catch (IOException e) {
System.out.println(e);
}
return pixels;
}
}
答案 4 :(得分:-1)