基于Java实现图片相似度对比的示例代码

 更新时间:2022年07月25日 10:47:36   作者:日拱一車  
很多时候我们需要将两个图片进行对比,确定两个图片的相似度。本文将利用Java和OpenCV库实现图片相似度对比,感兴趣的可以动手尝试一下

前言

很多时候我们需要将两个图片进行对比,确定两个图片的相似度。一般常用的就是openCv库,这里就是使用openCv进行图片相似度对比。

依赖

<dependency>
          <groupId>org.bytedeco</groupId>
          <artifactId>javacv</artifactId>
          <version>1.3.3</version>
      </dependency>
<dependency>
          <groupId>org.bytedeco</groupId>
          <artifactId>javacv-platform</artifactId>
          <version>1.3.3</version>
</dependency>

基本算法

基本算法

1、判断高度是否一致,如果不一致,需要截取到高度一致

2、截取算法

a、因为图片有通用的顶部bar和底部bar,需要先找到底部bar。

b、截取长图片的部分,然后和底部bar拼接,就完成了图片截取。

c、这里设置一个默认的宽度,然后对比,找到相同部分,就是底部bar。

相关代码

package com.test.image;
 
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.opencv_core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_imgcodecs.imread;
import static org.bytedeco.javacpp.opencv_imgcodecs.imwrite;
import static org.bytedeco.javacpp.opencv_imgproc.*;
import static org.bytedeco.javacpp.opencv_imgproc.THRESH_BINARY;
 
public class ImageService {
    private static Logger Log = LoggerFactory.getLogger(ImageService.class);
 
 
    public static void compareImage( String targetImageUrl, String baseImageUrl ){
 
 
        /**
         * 读取图片到数组
         */
        opencv_core.Mat targetImage = imread(targetImageUrl);
        opencv_core.Mat baseImage = imread(baseImageUrl);
        Log.info("read image success");
 
 
        /**
         * 首先对比的两个图片宽度要一致,否则不能对比
         */
        if(targetImage.size().width()==baseImage.size().width()){
 
 
            /**
             * 基本算法
             * 1、判断高度是否一致,如果不一致,需要截取到高度一致
             * 2、截取算法
             *    a、因为图片有通用的顶部bar和底部bar,需要先找到底部bar。
             *    b、截取长图片的部分,然后和底部bar拼接,就完成了图片截取。
             *    c、这里设置一个默认的宽度,然后对比,找到相同部分,就是底部bar。
             */
 
            if(targetImage.size().height()!=baseImage.size().height()){
 
                if(targetImage.size().height()>baseImage.size().height()){
                    targetImage = dealLongImage(targetImage.clone(),baseImage.clone());
                } else {
                    baseImage = dealLongImage(baseImage.clone(),targetImage.clone());
                }
            }
 
            /**
             * 进行图片差异对比
             */
            Mat imageDiff = compareImage(targetImage,baseImage);
 
            double nonZeroPercent = 100 * (double) countNonZero(imageDiff) / (imageDiff.size().height() * imageDiff.size().width());
 
            /**
             * 展示图片,将标准图,对比图,差异图,拼接成一张大图。
             * 其中差异图会用绿色标出差异的部分。
             */
            set3ImageTo1("", targetImage, baseImage, showDiff(imageDiff, baseImage), "xxxx.jpg" );
 
 
            imageDiff.release();
            baseImage.release();
            targetImage.release();
 
        } else {
 
        }
    }
 
 
    /**
     * 2、截取算法
     *    a、因为图片有通用的顶部bar和底部bar,需要先找到底部bar。
     *    b、截取长图片的部分,然后和底部bar拼接,就完成了图片截取。
     *    c、这里设置一个默认的宽度,然后对比,找到相同部分,就是底部bar。
     * @return bar的高度
     */
    public static int interceptBarHeight( Mat longImage, Mat shortImage ){
 
        /**
         * 设置的默认高度。
         */
        int imageSearchMaxHeight = 400;
        Mat subImageLong = new Mat(longImage, new Rect(0, longImage.size().height() - imageSearchMaxHeight, longImage.size().width(), imageSearchMaxHeight));
        Mat subImageShort = new Mat(shortImage, new Rect(0, shortImage.size().height() - imageSearchMaxHeight, shortImage.size().width(), imageSearchMaxHeight));
 
        opencv_core.Mat imageDiff = compareImage(subImageLong,subImageShort);
 
        for (int row = imageDiff.size().height() - 1; row > -1; row--) {
            for (int col = 0; col < imageDiff.size().width(); col++) {
                BytePointer bytePointer = imageDiff.ptr(row, col);
                if (bytePointer.get(0) != 0) {
                    imageDiff.release();
                    return imageSearchMaxHeight-row;
                }
            }
        }
        return imageSearchMaxHeight;
    }
 
    /**
     * 这里将两张图片作为参数传入,
     * 获取到共同的底部之后。对长图进行截取,
     * 然后将顶部和底部拼接在一起就ok了。
     * @param longImage
     * @param shortImage
     * @return
     */
    public static opencv_core.Mat dealLongImage( Mat longImage, Mat shortImage ){
 
        int diffHeight = longImage.size().height()-shortImage.size().height();
        int barHeight = interceptBarHeight(longImage,shortImage);
 
        opencv_core.Mat dealedLongImage = new Mat(longImage,new Rect(0,0,longImage.size().width(),shortImage.size().height()-barHeight) );
 
        opencv_core.Mat imageBar = new Mat(longImage,new Rect(0,longImage.size().height()-barHeight,longImage.size().width(),barHeight) );
 
        opencv_core.Mat dealedLongImageNew = dealedLongImage.clone();
 
        /**
         * 将头部和底部bar拼接在一起。
         */
        vconcat(dealedLongImage, imageBar, dealedLongImageNew);
        imageBar.release();
        dealedLongImage.release();
        return dealedLongImageNew;
    }
 
 
    public static opencv_core.Mat compareImage( opencv_core.Mat targetImage, opencv_core.Mat baseImage ){
 
        opencv_core.Mat targetImageClone = targetImage.clone();
        opencv_core.Mat baseImageColne = baseImage.clone();
        opencv_core.Mat imgDiff1 = targetImage.clone();
        opencv_core.Mat imgDiff = targetImage.clone();
 
        /**
         * 首先将图片转成灰度图,
         */
        cvtColor(targetImage, targetImageClone, COLOR_BGR2GRAY);
        cvtColor(baseImage, baseImageColne, COLOR_BGR2GRAY);
 
        /**
         * 两个矩阵相减,获得差异图。
         */
        subtract(targetImageClone, baseImageColne, imgDiff1);
        subtract(baseImageColne, targetImageClone, imgDiff);
 
        /**
         * 按比重进行叠加。
         */
        addWeighted(imgDiff, 1, imgDiff1, 1, 0, imgDiff);
 
        /**
         * 图片二值化,大于24的为1,小于24的为0
         */
        threshold(imgDiff, imgDiff, 24, 255, THRESH_BINARY);
        erode(imgDiff, imgDiff, new opencv_core.Mat());
        dilate(imgDiff, imgDiff, new opencv_core.Mat());
        return imgDiff;
    }
 
 
    private static void set3ImageTo1(String logTag, Mat imageSrc, Mat imageBaseSrc, Mat imageDest, String mergePicResult ) {
 
        if (imageSrc.size().width() == imageDest.size().width() && imageBaseSrc.size().height() == imageDest.size().height()) {
            Mat img = imageSrc.clone();
            Mat imgBase = imageBaseSrc.clone();
            Mat imgDest = imageDest.clone();
            Mat imgLine = new Mat(imgBase.size().height(), 1, CV_8UC3, new Scalar(0, 0, 0, 255));
            Mat largeImg2 = new Mat();
            Mat largeImg3 = new Mat();
            Mat largeImg4 = new Mat();
            Mat largeImg5 = new Mat();
            /**
             * 横向拼接。
             */
            hconcat(img, imgLine, largeImg2);
            hconcat(largeImg2, imgBase, largeImg3);
            hconcat(largeImg3, imgLine, largeImg4);
            hconcat(largeImg4, imgDest, largeImg5);
 
            imwrite( mergePicResult, largeImg5);
 
            img.release();
            imgBase.release();
            imgDest.release();
            imgLine.release();
            largeImg2.release();
            largeImg3.release();
            largeImg4.release();
            largeImg5.release();
        } else {
            Log.info(logTag+" pictures merge failed");
            imwrite( mergePicResult, imageDest);
        }
 
    }
 
 
    private static Mat showDiff(Mat imgDiff, Mat imgBase) {
 
        MatVector rgbFrame = new MatVector();
        Mat imgDest = imgBase.clone();
        split(imgBase, rgbFrame);
        subtract(rgbFrame.get(2), imgDiff, rgbFrame.get(2));
        subtract(rgbFrame.get(0), imgDiff, rgbFrame.get(0));
        addWeighted(rgbFrame.get(1), 1, imgDiff, 1, 0, rgbFrame.get(1));
        merge(rgbFrame, imgDest);
        return imgDest;
    }
 
 
    public static void main( String[] args ){
 
        String targetImageUrl = "2022-03-15-11-37-35-2ouA9yi9gjsGWHDAoaZTaNe4awr0xSlohFq0gF0m.png";
        String baseImageUrl = "2022-03-15-11-37-38-njH2kVzd3boX1i8q8bLCfnnIj8xTLyHhHufgs9rp.png";
 
        compareImage(targetImageUrl,baseImageUrl);
    }
 
}

到此这篇关于基于Java实现图片相似度对比的示例代码的文章就介绍到这了,更多相关Java图片相似度对比内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 将15位身份证补全为18位身份证的算法示例详解

    将15位身份证补全为18位身份证的算法示例详解

    这篇文章主要给大家介绍了关于将15位身份证补全为18位身份证算法的相关资料,文中通过示例代码给大家介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
    2017-06-06
  • mybatis中几种typeHandler的定义使用详解

    mybatis中几种typeHandler的定义使用详解

    本文主要介绍了mybatis中几种typeHandler的定义使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Java线性表的顺序表示及实现

    Java线性表的顺序表示及实现

    这篇文章主要介绍了Java线性表的顺序表示及实现,顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中
    2022-07-07
  • 时间中间键的整理

    时间中间键的整理

    这篇文章主要介绍了时间中间键的整理的相关资料,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,需要的朋友可以参考下
    2017-10-10
  • Java数组与字符串深入探索使用方法

    Java数组与字符串深入探索使用方法

    在今天的文章中,我将为你详细讲述Java学习中重要的一节 [ 数组与字符串 ] ,带你深入了解Java语言中数组的声明、创建和初始化方法,字符串的定义以及常用到的操作方法
    2022-07-07
  • Java设计模式之建造者模式的示例详解

    Java设计模式之建造者模式的示例详解

    建造者模式,是一种对象构建模式 它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象。本文将通过示例讲解建造者模式,需要的可以参考一下
    2022-10-10
  • Java Netty HTTP服务实现过程解析

    Java Netty HTTP服务实现过程解析

    这篇文章主要介绍了Java Netty HTTP服务实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • mvn中dependencyManagement的使用详解

    mvn中dependencyManagement的使用详解

    这篇文章主要介绍了mvn中dependencyManagement的使用,子项目中只是声明使用此依赖即可,可不用指定版本(将使用父pom同一指定的版本),若指定了版本,将以子项目的版本号为主,需要的朋友可以参考下
    2022-08-08
  • JAVA 笔记 ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别

    JAVA 笔记 ClassLoader.getResourceAsStream() 与 Class.getResourc

    这篇文章主要介绍了JAVA 笔记 ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • Spring Boot 捕捉全局异常 统一返回值的问题

    Spring Boot 捕捉全局异常 统一返回值的问题

    这篇文章主要介绍了Spring Boot 捕捉全局异常 统一返回值,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06

最新评论