需求
实现两张图对比,找出其中不同的部分。
分析
首先将大图切片,分成许多小图片。然后进行逐个对比,并设定相似度阈值,判断是否是相同。最后整理,根据生成数组标记不同部分。如果切片足够小,便越能精确找出不同点。
本例使用1024x1024图片,切片大小为32x32。
实现
import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; public class PicTest { public final static int THRESHOLD = 90;//阈值百分比 public static void main(String[] args) throws Exception { //用于记录不同点 int[][] comparyArray = new int[32][32]; //两张图片 BufferedImage img1 = ImageIO.read(new File("G:\1.jpg")); BufferedImage img2 = ImageIO.read(new File("G:\2.jpg")); //两张图片的切片 BufferedImage img1Sub; BufferedImage img2Sub; float percent; //双循环用来取图片的切片坐标 for(int i = 0;i<32;i++){ for(int j = 0;j<32;j++){ //取相同点的坐标 img1Sub = img1.getSubimage(j*32, i*32, 32, 32); img2Sub = img2.getSubimage(j*32, i*32, 32, 32); //比较获得相似度 percent = compare(getData(img1Sub), getData(img2Sub)); if(percent>THRESHOLD){//比阈值大,则记录1表示相同 comparyArray[i][j] = 1; System.out.print(1+" "); }else{//比阈值小,则记录0表示不同 comparyArray[i][j] = 0; System.out.print(0+" "); } } System.out.println(); } } //直方图作对比返回相似度 public static float compare(int[] s, int[] t) { float result = 0F; for (int i = 0; i < 256; i++) { int abs = Math.abs(s[i] - t[i]); int max = Math.max(s[i], t[i]); result += (1 - ((float) abs / (max == 0 ? 1 : max))); } return (result / 256) * 100; } //根据图片获取直方图数据 public static int[] getData(BufferedImage img) throws Exception { BufferedImage slt = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); slt.getGraphics().drawImage(img, 0, 0, 100, 100, null); // ImageIO.write(slt,"jpeg",new File("slt.jpg")); int[] data = new int[256]; for (int x = 0; x < slt.getWidth(); x++) { for (int y = 0; y < slt.getHeight(); y++) { int rgb = slt.getRGB(x, y); Color myColor = new Color(rgb); int r = myColor.getRed(); int g = myColor.getGreen(); int b = myColor.getBlue(); data[(r + g + b) / 3]++; } } // data 就是所谓图形学当中的直方图的概念 return data; } }
效果
两张图片分别为
运行程序后,输出1和0的数组,与第二张图相比较得到
可以看出不同的地方显示为0.据此,便可以根据数组显示画框突出了。