用java大图中寻找小图位置

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SummerCloudXT/article/details/82628941

先说下思路:
因为是大图中寻找小图,所以小图必须是大图的一部分,那么对应的他们具有相同的像素点,所以为了一遍就可以搜出来,从小图中抽取若干个像素点(本次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地址:获取源码
相似汉明原理参考:点击跳转

猜你喜欢

转载自blog.csdn.net/SummerCloudXT/article/details/82628941