Similar image search using an image

…衆ロ難τιáo~ 提交于 2019-12-04 07:43:02

I've made a tool named Images similarities searcher for this purpose as free software available at http://sourceforge.net/projects/imgndxr/

It use two libraries:

The LIRE (Lucene Image REtrieval) library provides a simple way to retrieve images and photos based on their color and texture characteristics. LIRE creates a Lucene index of image features for content based image retrieval (CBIR). Several different low level features are available, such as MPEG-7 ScalableColor, ColorLayout, and EdgeHistogram, Auto Color Correlogram, PHOG, CEDD, JCD, FCTH, and many more. Furthermore simple and extended methods for searching the index and result browsing are provided by LIRE. LIRE scales well up to millions of images with hash based approximate indexing. The LIRE library and the LIRE Demo application as well as all the source are available under the Gnu GPL license.

Apache LuceneTM is a high-performance, full-featured text search engine library written entirely in Java. It is a technology suitable for nearly any application that requires full-text search, especially cross-platform.

Apache Lucene is an open source project available for free download. Please use the links on the right to access Lucene.

It depends on your use case. Are the images generic, or are they taken under similar lighting conditions and perspectives?


The approaches can be classified according to the complexity of the model. Essentially, we can distinguish direct vs feature-based approaches.

Direct (or intensity-based) methods attempt to (iteratively) estimate the similarity by minimizing an error function based on the intensity difference in the area of overlap. Each image must represent exactly the same scene with same scale, angle of view, etc. in order to overlap them. Similarity measurement can be achieved by computing the sum square difference (SSD) or ZSSD, the correlation coefficient (CC), the mutual information (MI) and the correlation ratio (RC).

Direct approaches can be useful e.g. to check just how well a new video compressing algorithms works. Take a look at the article below:

http://docs.opencv.org/trunk/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.html


On the other hand we can talk about feature-based approches. They try to establish correspondences between points, lines or other geometrical entities for estimating the camera parameters. They can be useful when the structural units of an image (pixels) does not contain sufficient information about its content. Hence, feature-based approaches try to represent image content in terms of mathematical features (n-dimensional vectors), and then use classifiers to compare these features in order to get a measure regarding their similarities.

I got satisfactory results by resizing images to an 8x8 thumbnail and then taking the Mean Square Error of the 8-bit RGB color differences between the corresponding pixel in each image.

Step 1. Create thumbnails:

        BufferedImage img = ImageIO.read(src);
        Image thumbnail = img.getScaledInstance(8, 8, Image.SCALE_AREA_AVERAGING);

Check https://community.oracle.com/docs/DOC-983611 to understand why I chose the slower SCALE_AREA_AVERAGING over newer, faster methods.

Step 2. Convert Image thumbnails to BufferedImage by using the toBufferedImage method from Java converting Image to BufferedImage. Place the result into a List<BufferedImage>.

Step 3. Calculate the Mean Squared Error

This method takes two thumbnail-sized images of identical size and returns the difference. Zero means the images are very very similar:

public static double compare(BufferedImage img1, BufferedImage img2) {
    int width1 = img1.getWidth();
    int width2 = img2.getWidth();
    int height1 = img1.getHeight();
    int height2 = img2.getHeight();
    if ((width1 != width2) || (height1 != height2)) {
        throw new IllegalArgumentException("Error: Images dimensions mismatch");
    }

    int diff2 = 0;

    for (int i = 0; i < height1; i++) {
        for (int j = 0; j < width1; j++) {
            int rgb1 = img1.getRGB(j, i);
            int rgb2 = img2.getRGB(j, i);
            int r1 = (rgb1 >> 16) & 0xff;
            int g1 = (rgb1 >> 8) & 0xff;
            int b1 = (rgb1) & 0xff;
            int r2 = (rgb2 >> 16) & 0xff;
            int g2 = (rgb2 >> 8) & 0xff;
            int b2 = (rgb2) & 0xff;

            diff2 += Math.pow(r1 - r2, 2) + Math.pow(g1 - g2, 2) + Math.pow(b1 - b2, 2); 
        }
    }
    return diff2 * 1.0 / (height1*width1);
}

Step 4. Implement Search

This works by simply finding the image with the smallest difference. Depending on your use-case you may also want to set a threshold above which no image is returned. In my application the best match is always shown to the user so the user can decide if it is the correct image or not, so a hard-coded threshold is not necessary.

public BufferedImage findImage(List<BufferedImage> haystack, BufferedImage needle) {

    double lastDiff = Double.MAX_VALUE;
    BufferedImage winner = null;

    for(BufferedImage candidate: haystack) {
        double diff = compare(candidate, needle);
        if(diff < lastDiff) {
            lastDiff = diff;
            winner = candidate;
        }
    }
    return winner;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!