用java大图中寻找小图位置

本文介绍了一种快速在大图中定位小图的方法,并通过选取特定像素点进行匹配来提高搜索效率。同时,利用汉明距离计算图像相似度,确保识别准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先说下思路:
因为是大图中寻找小图,所以小图必须是大图的一部分,那么对应的他们具有相同的像素点,所以为了一遍就可以搜出来,从小图中抽取若干个像素点(本次DEMO只选区了5个),从大图中找到像素与第一个点满足的,然后直接进行对比第二个点。。。到N个。都符合,说明就找到了,然后为了进行验证,对图片进行了相似度运算。
看下结果,开始还想做优化,但是看了下用的时间82毫秒,最后加上验证才1秒,貌似挺快的。就算了
这里写图片描述
话不多说,上代码:
SearchPixelPosition核心类

public class SearchPixelPosition {
	//需要找的图片宽度
	private int targetWidth;
	//需要找的图片高度
	private int targetHeight;

	/**
	 * 对大图进行所有像素点寻找,知道满足5个点,返回之后到的坐标值
	 * @param path
	 * @param tagert
	 * @return
	 */
	public ResultBean getAllRGB(String path, String tagert) {
		// int[] rgb = new int[3];
		File file = new File(path);
		BufferedImage bi = null;
		try {
			bi = ImageIO.read(file);
		} catch (Exception e) {
			e.printStackTrace();
		}

		int width = bi.getWidth();
		int height = bi.getHeight();
		int minx = bi.getMinX();
		int miny = bi.getMinY();
		System.out.println("width=" + width + ",height=" + height + ".");
		System.out.println("minx=" + minx + ",miniy=" + miny + ".");
		ArrayList<PositionBean> setTarget5RGB = setTarget5RGB(tagert);

		// System.out.println(setTarget5RGB.get(0).x+" "+setTarget5RGB.get(0).y+"
		// "+setTarget5RGB.get(0).pxrgb);
		// System.out.println(setTarget5RGB.get(1).x+" "+setTarget5RGB.get(1).y+"
		// "+setTarget5RGB.get(1).pxrgb);
		// System.out.println(setTarget5RGB.get(2).x+" "+setTarget5RGB.get(2).y+"
		// "+setTarget5RGB.get(2).pxrgb);
		// System.out.println(setTarget5RGB.get(3).x+" "+setTarget5RGB.get(3).y+"
		// "+setTarget5RGB.get(3).pxrgb);
		// System.out.println(setTarget5RGB.get(4).x+" "+setTarget5RGB.get(4).y+"
		// "+setTarget5RGB.get(4).pxrgb);

		long start = System.currentTimeMillis();
		for (int i = minx; i < width; i++) {
			for (int j = miny; j < height; j++) {
				int pixel = bi.getRGB(i, j);
				// rgb[0] = (pixel & 0xff0000) >> 16;
				// rgb[1] = (pixel & 0xff00) >> 8;
				// rgb[2] = (pixel & 0xff);
				
				//依次对比5个点。
				if (setTarget5RGB != null) {
					PositionBean p1 = setTarget5RGB.get(0);
					if (pixel == p1.pxrgb) {
						int other = 0;
						PositionBean p2 = setTarget5RGB.get(1);
						int pixel2 = bi.getRGB(i + (p2.x - p1.x), j);
						if (pixel2 == p2.pxrgb) {
							other++;
							PositionBean p3 = setTarget5RGB.get(2);
							int pixel3 = bi.getRGB(i + (p3.x - p1.x), j + (p3.y - p1.y));
							if (pixel3 == p3.pxrgb) {
								other++;
								PositionBean p4 = setTarget5RGB.get(3);
								int pixel4 = bi.getRGB(i, j + (p4.y - p1.y));
								if (pixel4 == p4.pxrgb) {
									other++;
									PositionBean p5 = setTarget5RGB.get(4);
									int pixel5 = bi.getRGB(i + (p5.x - p1.x), j + (p5.y - p1.y));
									if (pixel5 == p5.pxrgb) {
										other++;
									}
								}
							}
						}
						if (other == 4) {
							long end = System.currentTimeMillis();
							System.out.println("总耗时:" + (end - start));
							System.out.println("找到了===》》》》横坐标" + i + "纵坐标" + j);
							ResultBean resultBean = new ResultBean();
							resultBean.width = targetWidth;
							resultBean.height = targetHeight;
							resultBean.x = i - p1.x;
							resultBean.y = j - p1.y;
							return resultBean;
						}
					}
				}
			}
		}
		long end = System.currentTimeMillis();
		System.out.println("搜索坐标耗时:" + (end - start));
		return null;
	}

	/**
	 * 分别取小图的四个角落和中心点的像素,作为搜图依据
	 * 
	 * @param src
	 * @return
	 * @throws Exception
	 */
	private ArrayList<PositionBean> get5PointForTager(String src) throws Exception {
		ArrayList<PositionBean> searchXYList = new ArrayList<>();
		File file = new File(src);
		BufferedImage bi = null;
		try {
			bi = ImageIO.read(file);
		} catch (Exception e) {
			e.printStackTrace();
		}
		int width = bi.getWidth();
		int height = bi.getHeight();
		targetWidth = width;
		targetHeight = height;

		if (width >= 10 && height >= 10) {
			int px1 = (int) (width * 0.25);
			int py1 = (int) (height * 0.25);
			int px2 = (int) (width * 0.75);
			int py2 = (int) (height * 0.25);
			int px3 = (int) (width * 0.5);
			int py3 = (int) (height * 0.5);
			int px4 = (int) (width * 0.25);
			int py4 = (int) (height * 0.75);
			int px5 = (int) (width * 0.75);
			int py5 = (int) (height * 0.75);
			searchXYList.add(new PositionBean(px1, py1));
			searchXYList.add(new PositionBean(px2, py2));
			searchXYList.add(new PositionBean(px3, py3));
			searchXYList.add(new PositionBean(px4, py4));
			searchXYList.add(new PositionBean(px5, py5));
		} else {
			throw new Exception("不支持10px以内的搜索");
		}

		return searchXYList;
	}

	/**
	 * 设置5个点的像素值 和对应的坐标
	 * @param src
	 * @return
	 */
	private ArrayList<PositionBean> setTarget5RGB(String src) {
		File file = new File(src);
		BufferedImage bi = null;
		try {
			bi = ImageIO.read(file);
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			ArrayList<PositionBean> get5PointForTager = get5PointForTager(src);
			for (int i = 0; i < get5PointForTager.size(); i++) {
				PositionBean positionBean = get5PointForTager.get(i);
				positionBean.pxrgb = bi.getRGB(positionBean.x, positionBean.y);
			}
			return get5PointForTager;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

}

看下调用

public class MainInTest {
	public static void main(String[] args) {
		String src = "/Users/mac_py/Desktop/cocl.png";
		String dest = "/Users/mac_py/Desktop/cocl-n-y.png";
		String target = "/Users/mac_py/Desktop/cocl-n.png";
		long start = System.currentTimeMillis();
		try {
			// ScalImage.zoomImage(src, dest,320,180);
			// SnippingImage.saveImageWithSize(568,850,240,106,src,"/Users/mac_py/Desktop/cocl-n.png");
			// SnippingImage.saveImageWithSize(71,106,30,13,src,"/Users/mac_py/Desktop/cocl-n-s-y.png");
			// ScalImage.zoomImage(src, dest,30,13);
			// SearchPixelPosition.getAllRGB(src);
			SearchPixelPosition searchPixelPosition = new SearchPixelPosition();
			ResultBean result = searchPixelPosition.getAllRGB(src, target);
			if (result != null) {
				SnippingImage.saveImageWithSize(result.x, result.y, result.width, result.height, src,
						"/Users/mac_py/Desktop/cocl-ai.png");
				ImagePHash p = new ImagePHash();
				System.out.println("进行相似度计算");
				String image1 = p.getHash(new FileInputStream(new File(target)));
				String image2 = p.getHash(new FileInputStream(new File("/Users/mac_py/Desktop/cocl-ai.png")));
				System.out.println("相似度为" + (p.distance(image1, image2)==0?"相似度100%":"不相似"));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		long end = System.currentTimeMillis();
		System.out.println("总共耗时:" + (end - start));
	}
}

相似度计算核心类 ImagePHash

/* 
 * 汉明距离越大表明图片差异越大,如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。
 */
public class ImagePHash {
    private int size = 32;
    private int smallerSize = 8;

    public ImagePHash() {
        initCoefficients();
    }

    public ImagePHash(int size, int smallerSize) {
        this.size = size;
        this.smallerSize = smallerSize;

        initCoefficients();
    }

    public int distance(String s1, String s2) {
        int counter = 0;
        for (int k = 0; k < s1.length(); k++) {
            if (s1.charAt(k) != s2.charAt(k)) {
                counter++;
            }
        }
        return counter;
    }

    /**
     * 返回图片二进制流的字符串
     * @param is 输入流
     * @return
     * @throws Exception
     */
    public String getHash(InputStream is) throws Exception {
        BufferedImage img = ImageIO.read(is);

        /*
         * 简化图片尺寸
         */
        img = resize(img, size, size);

        /*
         *  减少图片颜色
         */
        img = grayscale(img);

        double[][] vals = new double[size][size];

        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                vals[x][y] = getBlue(img, x, y);
            }
        }

        /*
         * 计算DTC 采用32*32尺寸
         */
        long start = System.currentTimeMillis();
        double[][] dctVals = applyDCT(vals);
        System.out.println("DCT: " + (System.currentTimeMillis() - start));

    
        /*
         * 计算平均值DTC
         */
        double total = 0;

        for (int x = 0; x < smallerSize; x++) {
            for (int y = 0; y < smallerSize; y++) {
                total += dctVals[x][y];
            }
        }
        total -= dctVals[0][0];

        double avg = total / (double) ((smallerSize * smallerSize) - 1);

        /*
         * 计算hash值
         */
        String hash = "";

        for (int x = 0; x < smallerSize; x++) {
            for (int y = 0; y < smallerSize; y++) {
                if (x != 0 && y != 0) {
                    hash += (dctVals[x][y] > avg ? "1" : "0");
                }
            }
        }

        return hash;
    }

    private BufferedImage resize(BufferedImage image, int width, int height) {
        BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(image, 0, 0, width, height, null);
        g.dispose();
        return resizedImage;
    }

    private ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

    private BufferedImage grayscale(BufferedImage img) {
        colorConvert.filter(img, img);
        return img;
    }

    private static int getBlue(BufferedImage img, int x, int y) {
        return (img.getRGB(x, y)) & 0xff;
    }


    private double[] c;

    private void initCoefficients() {
        c = new double[size];

        for (int i = 1; i < size; i++) {
            c[i] = 1;
        }
        c[0] = 1 / Math.sqrt(2.0);
    }

    private double[][] applyDCT(double[][] f) {
        int N = size;

        double[][] F = new double[N][N];
        for (int u = 0; u < N; u++) {
            for (int v = 0; v < N; v++) {
                double sum = 0.0;
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < N; j++) {
                        sum += Math.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI)
                                * Math.cos(((2 * j + 1) / (2.0 * N)) * v * Math.PI) * (f[i][j]);
                    }
                }
                sum *= ((c[u] * c[v]) / 4.0);
                F[u][v] = sum;
            }
        }
        return F;
    }

    public static void main(String[] args) {
        ImagePHash p = new ImagePHash();
        String image1;
        String image2;
        try {
                image1 = p.getHash(new FileInputStream(new File("/Users/mac_py/Desktop/cocl-n-sc.png")));
                image2 = p.getHash(new FileInputStream(new File("/Users/mac_py/Desktop/cocl-n-s-y.png")));
                System.out.println("得分为 " + p.distance(image1, image2));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

如果有问题欢迎留言!对你有帮助记得点个赞!
最后附上git地址:获取源码
相似汉明原理参考:点击跳转

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值