Java使用OpenCV计算两张图片相似度

业务:找出两个表的重复的图片。

图片在表里存的是二进制值,存在大量由于一些特殊情况例如扫描有差异,导致图片存的二进制值不同,但图片其实是一样来的。

所以找出两个表重复相同的图片,不可能只是单纯的比较二进制值相等。

方法:针对这种情况,使用OpenCV直方图算法可以比较两张图片的相似度,测试发现完全相同的图片相似度等于1(表里存的二进制值不相等)

实操:Java引入使用opencv步骤详解

1.引入opencv依赖

<!-- https://mvnrepository.com/artifact/org.openimaj/core -->
<dependency><groupId>org.openpnp</groupId><artifactId>opencv</artifactId><version>4.5.5-1</version>
</dependency>

2.代码Demo

opencv提供了均方差算法(MSE)、结构相似性指数算法(SSIM)、峰值信噪比算法(PSNR)、直方图算法(SSIM-WH),其中使用直方图算法来比较图片相似效果最好。

    public static void main(String[] args) {// 加载OpenCV库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 读取两张图像。准备比对的图片Mat image1 = Imgcodecs.imread("D:\\work\\testdata\\psc_1716260008343.jpg");Mat image2 = Imgcodecs.imread("D:\\work\\testdata\\psc_1716260008345.jpg");// 将图片处理成一样大Imgproc.resize(image1, image1, image2.size());Imgproc.resize(image2, image2, image1.size());// 计算均方差(MSE)double mse = calculateMSE(image1, image2);System.out.println("均方差(MSE): " + mse);// 计算结构相似性指数(SSIM)double ssim = calculateSSIM(image1, image2);System.out.println("结构相似性指数(SSIM): " + ssim);// 计算峰值信噪比(PSNR)double psnr = calculatePSNR(image1, image2);System.out.println("峰值信噪比(PSNR): " + psnr);// 计算直方图final double similarity = calculateHistogram(image1, image2);System.out.println("图片相似度(直方图): " + similarity);// 计算归一化交叉相关(NCC)
//        double ncc = calculateNCC(image1, image2);
//        System.out.println("归一化交叉相关(NCC): " + ncc);}// 计算均方差(MSE)private static double calculateHistogram(Mat image1, Mat image2) {// 计算直方图Mat hist1 = calculateHistogram(image1);Mat hist2 = calculateHistogram(image2);// 计算相似度final double similarity = Imgproc.compareHist(hist1, hist2, Imgproc.CV_COMP_CORREL);// 手动释放内存
//        if (hist1 != null) {
//            hist1.release();
//        }
//        if (hist2 != null) {
//            hist2.release();
//        }return similarity;}// 计算均方差(MSE)private static double calculateMSE(Mat image1, Mat image2) {Mat diff = new Mat();Core.absdiff(image1, image2, diff);Mat squaredDiff = new Mat();Core.multiply(diff, diff, squaredDiff);Scalar mseScalar = Core.mean(squaredDiff);return mseScalar.val[0];}// 计算结构相似性指数(SSIM)private static double calculateSSIM(Mat image1, Mat image2) {Mat image1Gray = new Mat();Mat image2Gray = new Mat();Imgproc.cvtColor(image1, image1Gray, Imgproc.COLOR_BGR2GRAY);Imgproc.cvtColor(image2, image2Gray, Imgproc.COLOR_BGR2GRAY);MatOfFloat ssimMat = new MatOfFloat();Imgproc.matchTemplate(image1Gray, image2Gray, ssimMat, Imgproc.CV_COMP_CORREL);Scalar ssimScalar = Core.mean(ssimMat);return ssimScalar.val[0];}// 计算峰值信噪比(PSNR)private static double calculatePSNR(Mat image1, Mat image2) {Mat diff = new Mat();Core.absdiff(image1, image2, diff);Mat squaredDiff = new Mat();Core.multiply(diff, diff, squaredDiff);Scalar mseScalar = Core.mean(squaredDiff);double mse = mseScalar.val[0];double psnr = 10.0 * Math.log10(255.0 * 255.0 / mse);return psnr;}// 计算归一化交叉相关(NCC)
//    private static double calculateNCC(Mat image1, Mat image2) {
//        Mat image1Gray = new Mat();
//        Mat image2Gray = new Mat();
//        Imgproc.cvtColor(image1, image1Gray, Imgproc.COLOR_BGR2GRAY);
//        Imgproc.cvtColor(image2, image2Gray, Imgproc.COLOR_BGR2GRAY);
//        MatOfInt histSize = new MatOfInt(256);
//        MatOfFloat ranges = new MatOfFloat(0, 256);
//        Mat hist1 = new Mat();
//        Mat hist2 = new Mat();
//
//        Core.normalize(hist1, hist1, 0, 1, Core.NORM_MINMAX);
//        Core.normalize(hist2, hist2, 0, 1, Core.NORM_MINMAX);
//        double ncc = Core.compareHist(hist1, hist2, Imgproc.CV_COMP_CORREL);
//        return ncc;
//    }private static Mat calculateHistogram(Mat image) {Mat hist = new Mat();// 设置直方图参数MatOfInt histSize = new MatOfInt(256);MatOfFloat ranges = new MatOfFloat(0, 256);MatOfInt channels = new MatOfInt(0);List<Mat> images = new ArrayList<>();images.add(image);// 计算直方图Imgproc.calcHist(images, channels, new Mat(), hist, histSize, ranges);return hist;}

3.运行遇到的报错问题以及解决方法

Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java455 in java.library.path

报错原因:

在JDK bin 目录下找不到 opencv_java455.dll 文件

解决方法:

官网下载地址:Releases - OpenCV

找到对应的版本下载opencv(如果下载不起很慢,可以复制链接用迅雷下载)

双击打开安装包选择安装提取目录

等待解压

在目录找到dll文件

然后复制到jdk bin目录中

再重新运行程序即可解决

4.运行

均方差算法(MSE):

计算两幅图片每个像素之间的差异,并计算它们的平均值。MSE值越小,表示两幅图片越相似。

结构相似性指数(SSIM):

通过比较两幅图片的亮度、对比度和结构信息来评估它们的相似性。值越大,越相似。

峰值信噪比(PSNR):

通过计算两幅图片的MSE值,并将其转换为对数尺度,来评估它们的相似性。PSNR值越大,表示两幅图片越相似。

图片相似度(直方图):

通过将SSIM指数和直方图相似性组合起来,来评估两幅图片的相似性。返回的相似性度量值越接近1,表示两幅图像越相似。

5.结合业务实现代码片段

注:务必手动释放Mat内存,亲测不写手动释放内存,随着循环量越多,创建Mat越多,就会导致内存崩溃泄露(按理说Java有回收机制,但我经过测试发现并没有触发回收内存,即使是没用的Mat)

byte[] ecf2Image = bsImage.getImage();
byte[] upsImage = upsPage.getScanPage();
// 1.先直接对比ecf2和ups图片的二进制值
if (Arrays.equals(ecf2Image, upsImage)) {// 二进制值相等则给ecf2图片状态更新为重复的updateAndRecord(shipmentNo, filename, upsPage, 1);// 然后跳出scanPageList的循环,已经确认为重复就不用再去匹配break;
}// 2.byte值不等,再用OpenCV来比较
// 将图片二进制数据转换为Mat对象
Mat image1 = Imgcodecs.imdecode(new MatOfByte(ecf2Image), Imgcodecs.IMREAD_COLOR);
Mat image2 = Imgcodecs.imdecode(new MatOfByte(upsImage), Imgcodecs.IMREAD_COLOR);
try {// 将图片处理成一样大Imgproc.resize(image1, image1, image2.size());Imgproc.resize(image2, image2, image1.size());// 计算直方图final double similarity = calculateHistogram(image1, image2);if (similarity == 1) {// 更新状态为重复的updateAndRecord(shipmentNo, filename, upsPage, 2);break;}
} catch (Exception e) {e.printStackTrace();
} finally {// 手动释放内存if (image1 != null) {image1.release();}if (image2 != null) {image2.release();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/23976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

flask招聘数据分析及展示平台-计算机毕业设计源码39292

目 录 摘要 1 绪论 1.1研究意义 1.2国内外研究进展 1.3flask框架介绍 2 1.4论文结构与章节安排 3 2 招聘数据分析及展示平台分析 4 2.1 可行性分析 4 2.2 系统流程分析 4 2.2.1数据增加流程 5 2.3.2数据修改流程 5 2.3.3数据删除流程 5 2.3 系统功能分析 5 2.3.1 功能性分…

亚马逊新品如何快速吸引流量?自养号测评助卖家一臂之力

在亚马逊平台上每天都会有大量的新品推出&#xff0c;而这些新品中有部分可能并没有什么流量和订单&#xff0c;有些可能上架后立马就能获得流量了&#xff0c;那么亚马逊上新品一般几天出单&#xff1f; 一、亚马逊上新品一般几天出单&#xff1f; 亚马逊上新品出单的时间因…

人工智能时代,想转型AI产品经理?这篇文章你不应该错过

前言 在这个日新月异的智能时代&#xff0c;人工智能&#xff08;AI&#xff09;已经从未来概念转变为推动各行各业发展的核心驱动力。作为连接技术与市场的桥梁&#xff0c;AI产品经理的角色愈发关键&#xff0c;他们不仅是技术的翻译者&#xff0c;更是创新的推动者。如果你…

Mintegral解析休闲游戏如何靠创意素材吸引玩家

核心玩法简单清晰、容易让人无限上头的休闲游戏&#xff0c;玩法机制一般比较明确、简单&#xff0c;如果要在短时间内吸引玩家注意&#xff0c;除了完整展示游戏流程以外&#xff0c;开发者需要在素材中设置更多亮点性的内容&#xff0c;如吸睛的剧情、爆炸性的视听效果等元素…

组件的注册和引用

在Vue中&#xff0c;开发者可以将页面中独立的、可重用的部分封装成组件&#xff0c;对组件的结构&#xff0c;样式和行为进行设置。组件是 Vue 的基本结构单元&#xff0c;组件之间可以相互引用。 一.注册组件 当在Vue项目中定义了一个新的组件后&#xff0c;要想在其他组件中…

Vue3_对接腾讯云COS_大文件分片上传和下载

目录 一、腾讯云后台配置 二、安装SDK 1.script 引入方式 2.webpack 引入方式 三、文件上传 1.new COS 实例 2.上传文件 四、文件下载 腾讯云官方文档&#xff1a; 腾讯云官方文档https://cloud.tencent.com/document/product/436/11459 一、腾讯云后台配置 1.登录 对…

[职场] 为什么不能加薪? #学习方法#知识分享#微信

为什么不能加薪&#xff1f; 不能加薪的根本原因&#xff0c;终于被我找到了&#xff01; 朋友们&#xff01;职场这个地方是个很神奇的世界&#xff0c;有些规则并不是你想象的那样。我们都希望能在这个世界里施展自己的才华&#xff0c;获得升职加薪的荣耀。然而&#xff0c…

seerfar丨OZON运营工具,OZON选品插件

随着全球电商市场的蓬勃发展&#xff0c;OZON作为俄罗斯及东欧地区的重要电商平台&#xff0c;吸引了众多中国商家的目光。然而&#xff0c;如何在OZON平台上脱颖而出&#xff0c;实现高效的商品运营&#xff0c;成为了众多商家亟待解决的问题。在这样的背景下&#xff0c;seer…

tailwindcss的@apply使用

tailwindcss的apply是把在html写的tailwindcss可以挪到style里面 简化页面的可读性 没写之前的 <section class"block-risk absolute flex flex-col items-center p-4 text-center left-0 text-white;" :style"{ top, left: 60px }"> </section…

被拖欠6000万,代工大厂倒闭了····

6月7日消息&#xff0c;据综合媒体报道&#xff0c;电子烟代工大厂佳斯特电子&#xff08;东莞&#xff09;发布公告&#xff0c;将自6月3日起停止一切经营活动&#xff0c;开始自行清算工作。根据佳斯特电子科技&#xff08;东莞&#xff09;有限公司的通告&#xff0c;由于公…

TypeScript环境安装与VScode编辑器的使用

说明大背景环境&#xff0c;我用的是window10系统。 1.安装node.js 。 去官网下载安装包。 虽然我去的是官网&#xff0c;但是不知为何下载了个不知名的东西&#xff0c;后来又找了个链接才下载正确了。 实际上就是一个.msi的文件。我用的版本&#xff1a;node-v18.19.0-x6…

最大矩形问题

柱状图中最大的矩形 题目 分析 矩形的面积等于宽乘以高&#xff0c;因此只要能确定每个矩形的宽和高&#xff0c;就能计算它的面积。如果直方图中一个矩形从下标为 i 的柱子开始&#xff0c;到下标为 j 的柱子结束&#xff0c;那么这两根柱子之间的矩形&#xff08;含两端的柱…

能把试卷上的字消除的软件有哪些?推荐三款好用的

能把试卷上的字消除的软件有哪些&#xff1f;在数字化时代&#xff0c;我们越来越依赖科技手段来解决生活中的各种问题。其中&#xff0c;试卷上的字消除问题&#xff0c;就是一个备受关注的痛点。幸运的是&#xff0c;现在市面上已经出现了多款能够轻松消除试卷上字迹的软件&a…

力扣hot100:295. 数据流的中位数(两个优先队列维护中位数)

LeetCode&#xff1a;295. 数据流的中位数 这个题目最快的解法应该是维护中位数&#xff0c;每插入一个数都能快速得到一个中位数。 根据数据范围&#xff0c;我们应当实现一个 O ( n l o g n ) O(nlogn) O(nlogn)的算法。 1、超时—插入排序 使用数组存储&#xff0c;维持数…

【WEB自动化面试02--学习过程的问题及解决】

day01 1、报错获取不到浏览器二进制文件&#xff1a;需要指定浏览器路径及驱动路径。 第一次使用谷歌浏览器驱动&#xff0c;找不到二进制文件报错&#xff1a; selenium.common.exceptions.WebDriverException: Message: unknown error: cannot find Chrome binary Stacktra…

短视频矩阵源码----如何做正规开发规则分享:

一、什么是SaaS化服务技术开发&#xff1f; &#xff08;短视频矩阵系统是源头开发的应该分为3个端口---- 总后台控制端、总代理端口&#xff0c;总商户后台&#xff09; SaaS是软件即服务&#xff08;Software as a Service&#xff09;的缩写。它是一种通过互联网提供软件应…

Vue2(0基础入门)

环境准备 安装脚手架 vuecli: npm install -g vue/clivite: npm init vuelatest-g 全局安装&#xff0c;任意目录都可以使用vue脚本 进入目录创建项目&#xff1a; 在目录的终端输入&#xff1a;vue ui安装devtool(这个网页是安装好了自动跳转的) 运行项目&#xff1a; …

代码随想录第27天|贪心算法part1

455.分发饼干 先给孩子和饼干排序&#xff0c;每次选取一个最大的饼干给一个最大胃口的孩子&#xff0c;直到饼干分完或者遍历完孩子 class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(), g.end());sort(…

Vue3【三】 使用TS自己编写APP组件

Vue3【三】 使用TS自己编写APP组件 运行截图 目录结构 注意目录层级 文件源码 APP.vue <template><div class"app"><h1>你好世界!</h1></div> </template><script lang"ts"> export default {name:App //组…

JavaScript的核心语法

JavaScript JavaScript&#xff1a;JavaScript的组成&#xff1a;核心语法&#xff1a;Hello&#xff1a;变量&#xff1a;JS的基本数据类型&#xff1a;特殊点&#xff1a; 数组&#xff1a;流程控制语句&#xff1a;函数&#xff1a;函数的重载&#xff1a;函数的递归:预定义…