使用java程序查找两张相似图片的不同

任务介绍

在B站看up主立体視界直播,他通过平行眼查找两幅相似图片的不同之处。我也想挑战一下,但以失败告终,之后想通过代码来实现这一任务。我当时挑战的任务是查找下图中不同处。
使用java程序查找两张相似图片的不同_第1张图片

程序算法

在程序解决前需要先将图片进行编辑,保证后续工作可以顺利进行。编辑后的图片如下图所示。

解决上述任务的程序如下

package different_picture;

import javax.imageio.ImageIO;//提供了一组静态方法进行最简单的图像I/O(读图片和写图片)操作
import java.awt.image.BufferedImage;//该接口描述了对 BufferedImage对象执行的单输入/单输出操作。
import java.io.File;//文件和目录路径名的抽象表示,这个类提供了一个抽象的,独立于系统的层次化路径名的视图。


public class see {
	public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
		RecognizeFace rf=new RecognizeFace();//建立对象rf
		rf.face();//调用face方法
    } 
}


class RecognizeFace{
	public void face() throws Exception {
		/*
		 * 待处理的图片
		 */
		int[] rgb1 = new int[3];
		int[] rgb2 = new int[3];
		File files = new File("C:\\Users\\Dell\\Pictures\\QQ图片20210510101445.png");

		BufferedImage bImage = null;// bufferedImage是按照图像的方式访问图像,比如包含了颜色,光栅等
		bImage = ImageIO.read(files);

		int width = bImage.getWidth();// 图片宽度
		int height = bImage.getHeight();// 图片高度
		int minx = bImage.getMinTileX();// 图片最小x坐标

		int miny = bImage.getMinTileY();// 图片最小y坐标
		System.out.println("width" + width + ",height" + height + ",minx" + minx + ",miny" + miny);
		System.out.println("正在处理..." + files.getName());

		int flag = 0;// 标志位
		/*
		 * 遍历像素点
		 */
		for (int i = minx; i < width - 835; i++) {
			for (int j = miny; j < height; j++) {
				int pixel = bImage.getRGB(i, j);// i,j表示要开始截的坐标
				int pixel1 = bImage.getRGB(i + 835, j);
				rgb1[0] = (pixel & 0xff0000) >> 16;
				rgb1[1] = (pixel & 0xff00) >> 8;
				rgb1[2] = (pixel & 0xff);
				rgb2[0] = (pixel1 & 0xff0000) >> 16;
				rgb2[1] = (pixel1 & 0xff00) >> 8;
				rgb2[2] = (pixel1 & 0xff);
				if (Math.abs(rgb1[0] - rgb2[0]) <= 80 && Math.abs(rgb1[1] - rgb2[1]) <= 80
						&& Math.abs(rgb1[2] - rgb2[2]) <= 80) {
					// 颜色相同,不做处理
				} else {
					flag = 1;
					System.out.println("左" + rgb1[0] + " " + rgb1[1] + " " + rgb1[2] + " " + i + " " + j + "右" + rgb2[0]
							+ " " + rgb2[1] + " " + rgb2[2] + " " + (i + 835) + " " + j);
				}

			}

		}
		if (flag == 0)
			System.out.println("无不同");
	}
}

算法的思路是先读取图片的基本信息,如高度宽度等。然后根据偏移量来对比左右两点的RGB值,根据差异来判断是否不同。
根据程序得到的结果如图所示。
使用java程序查找两张相似图片的不同_第2张图片
在原图片的右下部分有一处不同,左边的图片是黄点,右边的图片是白点。

详细经历

起因

在5月9日晚看到up主立体視界直播,导致自己也想挑战他所完成的任务。我通过截图获得了上面说的任务图片,然后利用平行眼进行查找。我看了40分钟也没找到不同之处,于是我放弃,打算明天再找。

通过代码解决

我认为通过自己的眼睛几乎不可能找到,我要通过程序来完成这项任务。我想到了两种方法,一是通过对比左右图片的RGB值来查找不同,二是通过安卓显示的透明度来查找不同。
第一种方法好理解,我来介绍一下第二种方法。第二种方法的思路是先正常显示左边的图片,然后对右边的图片进行进准裁切,之后让左右这两幅图片都绘制在同一位置,然后通过降低右图的显示透明度来找到差异点。因为如果左边的图片某处每有点,右边图片的那一处有点,则该点的显示会比其他点更透明,从而找到不同处。
我对比了两个方法的困难处,第一个方法的难点是找到偏移量,第二个方法的难点是找到合适的裁剪位置和合适的透明度,并且还得自己用眼睛去找。我认为第一种方法更简单,所以我用第一种方法。

遇到的难题

1.查找偏移量

我第一反应是“偏移量=图片的宽度/2”,但我仔细想想认为不对,因为图片裁切并不是绝对正好,故这样得到的偏移量不可能正确。我想到了另一个方法,就是通过计算左右图片中最左边的点的x坐标差,从而得到偏移量。我先利用两层循环来遍历图片中所有像素点的RGB值,然后我看控制台打印的数据,找到了最左边的点。最左边的点是一个白点,RGB值为255 255 255。我记下了他的纵坐标,然后查找同一纵坐标上的白点,根据查找结果我得到了偏移量=1380。
之后我利用偏移量进行对比左右图片的左右像素值,但结果却十分古怪。我查看图片的宽度,图片的宽度也就1666,偏移量应该在830附近,我意识到我偏移量计算错误。
我思考后的得到原因,图片中每一个彩色点都占多个像素点,使用应该扩大纵坐标的范围。之后我将程序中的纵坐标=403改成了390<纵坐标<410。最终我得到了偏移量=835。自此,第一部分工作完成。

2.对比RGB值

我使用数组rgb[3]来存放像素点的RGB值,然后对比左点(i,j)和右点(i+835,j)的像素值,如果不同就打印出他们的相关信息。
但打印结果太多,控制台都不能完整显示。我意识到又出问题了。我观察显示出的结果,发现大部分结果的RGB值都相差不大。我通过网站RGB颜色对照表 - 96微信编辑器查看两点的RGB值对于的颜色,发现图片中的点的颜色通过肉眼看没有什么区别。我通过一系列实验,发现两种颜色的RGB值的差<40时几乎没有差别,故我将两点的RGB值改为RGB值的差<40。但是即使是这样,也任然有很多数据被显示出来,这导致我不得不继续思考。
我想到如果左边有彩色点,右边没有对应的彩色点这样就导致右。我正因为成功的时候,却发现了一个残酷的事实。程序发现的点对应的坐标都不在圆内,而在图片的边缘部分,那些点都是因为编辑图不彻底而残留的无效点。我用黑色画笔涂掉这些点后,我继续思考。
按照程序的结果,除了这些无效点,其他的点都相同,那岂不是我之前花了40分钟只是在找一幅不存在差异的图?我为了验证我的判断,我用黑色画笔涂掉了一个红点,继续让程序进行分析,程序只发现了这一个不同处,看来我判断是对的,左右图都相同。
我以为这次游戏结束了,但我脑子中又蹦出一个想法,如果是两点之间的颜色不同呢?程序并不能处理这种情况,而且图片应该是有不同的。
我以此作为依据,又改了程序,我发现RGB值的差=80时有细微差别,故我将两点的RGB值改为RGB值的差<80。通过这次的判断,数据少了很多,发现了三处不同,一处是因为编辑图片导致点的形状不一样,第二处是自己涂掉的红点,第三处是两点的颜色不同,左点是黄色,右点是白色。
自此,任务圆满完成。

你可能感兴趣的:(java.awt.image类,java,计算机视觉,算法)