python利用open-cv和SSIM和特征值比较两个图片的相似性
以下是关于 **SSIM(结构相似性指数)** 和 **特征匹配** 的详细解释及实际示例,帮助理解它们的区别和应用场景:
---
### **1. SSIM(结构相似性指数)**
#### **含义**:
- **SSIM** 是一种衡量两张图片在 **亮度(Luminance)**、**对比度(Contrast)** 和 **结构(Structure)** 三方面相似度的指标,值范围为 `[0, 1]`,越接近 1 表示越相似。
- **核心公式**:
\[
\text{SSIM} = \text{亮度相似度} \times \text{对比度相似度} \times \text{结构相似度}
\]
#### **适用场景**:
- 全局结构相似的图片(如内容相同但颜色不同)。
- 轻微压缩、模糊或亮度调整的图片对比。
#### **示例**:
- **场景1**:两张内容完全相同的图片,但一张被调暗。
- **SSIM 结果**:可能为 `0.95`(结构未变,但亮度差异轻微扣分)。
- **场景2**:一张猫的图片和一张狗的图片。
- **SSIM 结果**:可能为 `0.3`(结构完全不同)。
#### **局限性**:
- 对颜色变化敏感(SSIM 通常使用灰度图计算,但亮度变化仍影响结果)。
- 无法检测局部内容差异(如一张图片中多了一个小物体)。
---
### **2. 特征匹配(如ORB/SIFT算法)**
#### **含义**:
- **特征匹配** 通过检测图片中的关键点(如边缘、角点)并计算特征描述符,匹配两图中相似的关键点。相似度通常以 **匹配点数量占总关键点的比例** 表示。
- **核心步骤**:
1. 检测关键点(如 ORB 算法)。
2. 计算每个关键点的特征描述符。
3. 匹配两图中的描述符,筛选优质匹配点。
#### **适用场景**:
- 局部内容重叠的图片(如部分遮挡的物体)。
- 颜色差异大但结构相似的图片。
- 旋转、缩放或透视变换的图片。
#### **示例**:
- **场景1**:两张内容相同的图片,但一张被旋转 45 度。
- **特征匹配结果**:匹配比例可能为 `0.85`(旋转不影响关键点匹配)。
- **场景2**:一张完整建筑物的图片和另一张仅包含建筑物局部的图片。
- **特征匹配结果**:可能为 `0.6`(局部区域匹配成功)。
#### **局限性**:
- 对模糊或低纹理图片效果差(关键点检测困难)。
- 计算复杂度高,不适合实时大规模比对。
---
### **3. 综合示例**
#### **测试图片**:
- **图片A**:原始猫的图片。
- **图片B**:对图片A进行颜色反转(结构相同,颜色不同)。
- **图片C**:图片A的 80% 区域,但右下角被裁剪。
#### **对比结果**:
| 对比对 | SSIM 得分 | 特征匹配得分 |
|----------|-----------|--------------|
| A vs B | 0.25 | 0.92 |
| A vs C | 0.65 | 0.78 |
#### **分析**:
- **A vs B**:
- **SSIM 低**:颜色反转导致亮度差异显著。
- **特征匹配高**:关键点结构未变,匹配成功。
- **A vs C**:
- **SSIM 中等**:裁剪导致全局结构变化。
- **特征匹配中等**:大部分区域关键点匹配,但裁剪部分丢失。
---
### **4. 实际应用建议**
- **组合使用**:
- 先用 **SSIM** 快速筛选全局相似的图片。
- 再用 **特征匹配** 验证局部细节。
- **阈值设定**:
- SSIM > 0.8 → 高度相似。
- 特征匹配 > 0.7 → 局部内容重叠。
通过理解这两个指标的特点,可以更精准地判断图片相似性,适应颜色变化、局部遮挡等复杂场景。
代码,要安装open-cv,GUI界面可以选择某个文件夹,注意不能中文命名,否则opencv识别报错,然后把要对比的图片放到该文件夹中即可,代码如下:
import cv2
import numpy as np
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from skimage.metrics import structural_similarity as ssim
from itertools import combinations
import os
import csv# --------------------------- 核心算法部分 ---------------------------
def load_and_resize(image_path, target_size=(500, 500)):"""加载并统一调整图片尺寸"""image = cv2.imread(image_path)if image is None:raise ValueError(f"无法读取图片: {image_path}")return cv2.resize(image, target_size)def calculate_ssim(image1, image2):"""计算结构相似性指数(SSIM)"""gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)score, _ = ssim(gray1, gray2, full=True)return scoredef feature_matching(image1, image2):"""使用ORB特征点检测与匹配"""orb = cv2.ORB_create()kp1, des1 = orb.detectAndCompute(image1, None)kp2, des2 = orb.detectAndCompute(image2, None)if des1 is None or des2 is None:return 0.0bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)matches = bf.match(des1, des2)good_matches = sorted(matches, key=lambda x: x.distance)[:50]return len(good_matches) / min(len(kp1), len(kp2)) if min(len(kp1), len(kp2)) > 0 else 0.0# --------------------------- GUI界面部分 ---------------------------
class ImageComparatorApp:def __init__(self, root):self.root = rootself.root.title("图片相似度对比工具")self.image_paths = []self.results = []# 界面布局self.setup_ui()def setup_ui(self):# 文件选择区域frame_select = ttk.Frame(self.root, padding="10")frame_select.pack(fill=tk.X)self.btn_select = ttk.Button(frame_select, text="选择图片文件夹", command=self.select_folder)self.btn_select.pack(side=tk.LEFT)self.lbl_folder = ttk.Label(frame_select, text="未选择文件夹")self.lbl_folder.pack(side=tk.LEFT, padx=10)# 图片列表区域frame_list = ttk.Frame(self.root, padding="10")frame_list.pack(fill=tk.BOTH, expand=True)self.tree = ttk.Treeview(frame_list, columns=("file"), show="headings")self.tree.heading("file", text="已选图片")self.tree.pack(fill=tk.BOTH, expand=True)# 操作按钮区域frame_actions = ttk.Frame(self.root, padding="10")frame_actions.pack(fill=tk.X)self.btn_compare = ttk.Button(frame_actions, text="开始对比", command=self.start_comparison)self.btn_compare.pack(side=tk.LEFT)self.btn_export = ttk.Button(frame_actions, text="导出结果", command=self.export_results)self.btn_export.pack(side=tk.LEFT, padx=10)self.btn_export["state"] = "disabled"# 结果表格区域frame_results = ttk.Frame(self.root, padding="10")frame_results.pack(fill=tk.BOTH, expand=True)columns = ("image1", "image2", "ssim", "feature_match")self.result_tree = ttk.Treeview(frame_results, columns=columns, show="headings")self.result_tree.heading("image1", text="图片1")self.result_tree.heading("image2", text="图片2")self.result_tree.heading("ssim", text="SSIM相似度")self.result_tree.heading("feature_match", text="特征匹配度")self.result_tree.pack(fill=tk.BOTH, expand=True)def select_folder(self):folder_path = filedialog.askdirectory()if folder_path:self.lbl_folder["text"] = folder_pathself.image_paths = [os.path.join(folder_path, f)for f in os.listdir(folder_path)if f.lower().endswith(('.png', '.jpg', '.jpeg'))]self.update_image_list()def update_image_list(self):self.tree.delete(*self.tree.get_children())for path in self.image_paths:self.tree.insert("", "end", values=(os.path.basename(path),))def start_comparison(self):if len(self.image_paths) < 2:messagebox.showwarning("警告", "至少需要选择2张图片!")returnself.results.clear()self.result_tree.delete(*self.result_tree.get_children())# 遍历所有两两组合for (path1, path2) in combinations(self.image_paths, 2):try:img1 = load_and_resize(path1)img2 = load_and_resize(path2)ssim_score = calculate_ssim(img1, img2)feature_score = feature_matching(img1, img2)result = {"image1": os.path.basename(path1),"image2": os.path.basename(path2),"ssim": round(ssim_score, 2),"feature_match": round(feature_score, 2)}self.results.append(result)# 更新表格self.result_tree.insert("", "end", values=(result["image1"],result["image2"],result["ssim"],result["feature_match"]))except Exception as e:print(f"对比失败: {str(e)}")self.btn_export["state"] = "normal"messagebox.showinfo("完成", "图片对比已完成!")def export_results(self):file_path = filedialog.asksaveasfilename(defaultextension=".csv",filetypes=[("CSV文件", "*.csv")])if file_path:with open(file_path, "w", newline="", encoding="utf-8") as f:writer = csv.DictWriter(f, fieldnames=["image1", "image2", "ssim", "feature_match"])writer.writeheader()writer.writerows(self.results)messagebox.showinfo("成功", f"结果已导出到: {file_path}")if __name__ == "__main__":root = tk.Tk()app = ImageComparatorApp(root)root.geometry("800x600")root.mainloop()
相关文章:
python利用open-cv和SSIM和特征值比较两个图片的相似性
以下是关于 **SSIM(结构相似性指数)** 和 **特征匹配** 的详细解释及实际示例,帮助理解它们的区别和应用场景: --- ### **1. SSIM(结构相似性指数)** #### **含义**: - **SSIM** 是一种衡量两…...
蔚来汽车智能座舱接入通义大模型,并使用通义灵码全面提效
为加速AI应用在企业市场落地,4月9日,阿里云在北京召开AI势能大会。阿里云智能集团资深副总裁、公共云事业部总裁刘伟光发表主题演讲,大模型的社会价值正在企业市场释放,阿里云将坚定投入,打造全栈领先的技术࿰…...
QT 老版本下载地址被禁 如何下载
前提: 想用老版本的QT 5.12 系列,但是QT官方已经封禁了国内IP 访问,5.15之前的版本,而且5.14.2是最后一个离线exe版本 ; Index of /official_releases/qt 基本不可用;全部改为在线安装; 收集了一下地址&am…...
VMWare Workstation Pro17.6最新版虚拟机详细安装教程(附安装包教程)
目录 前言 一、VMWare虚拟机下载 二、VMWare虚拟机安装 三、运行虚拟机 前言 VMware 是全球领先的虚拟化技术与云计算解决方案提供商,通过软件模拟计算机硬件环境,允许用户在一台物理设备上运行多个独立的虚拟操作系统或应用。其核心技术可提升硬件…...
【数据结构】红黑树超详解 ---一篇通关红黑树原理(含源码解析+动态构建红黑树)
一.什么是红黑树 红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构。1972年出现,最初被称为平衡二叉B树。1978年更名为“红黑树”。是一种特殊的二叉查找树,红黑树的每一个节点上都有存储表示节点的颜色。每一个节点可以是…...
uni-app初学
文章目录 1. pages.json 页面路由2. 图标3. 全局 CSS4. 首页4.1 整体框架4.2 完整代码4.3 轮播图 swiper4.3.1 image 4.4 公告4.4.1 uni-icons 4.5 分类 uni-row、uni-col4.6 商品列表 uni-row、uni-col 小程序开发网址: 注册小程序账号 微信开发者工具下载 uniapp …...
PHP多维数组
在 PHP 中,多维数组是数组的数组,允许你存储和处理更复杂的数据结构。多维数组可以有任意数量的维度,但通常我们最常用的是二维数组(数组中的数组)。 首先来介绍一下一维数组, <?php//一维数组 $strAr…...
数学建模:针对汽车行驶工况构建思路的延伸应用
前言: 汽车行驶工况构建的思简单理解为将采集的大量数据进行“去除干扰、数据处理,缩减至1800S的数据”,并可达到等效替换的目的,可以使在试验室快速复现;相应的解决思路、办法可应用在 “通过能量流采集设备大量采集…...
go语言内存泄漏的常见形式
go语言内存泄漏 子字符串导致的内存泄漏 使用自动垃圾回收的语言进行编程时,通常我们无需担心内存泄漏的问题,因为运行时会定期回收未使用的内存。但是如果你以为这样就完事大吉了,哪里就大错特措了。 因为,虽然go中并未对字符串…...
当DRAM邂逅SSD:新型“DRAM+”存储技术来了!
在当今快速发展的科技领域,数据存储的需求日益增长,对存储设备的性能和可靠性提出了更高的要求。传统DRAM以其高速度著称,但其易失性限制了应用范围;而固态硬盘SSD虽然提供非易失性存储,但在速度上远不及DRAM。 为了解…...
论文精度:YOLOMG:基于视觉的无人机间检测算法——外观与像素级运动融合详解
论文地址:https://arxiv.org/pdf/2503.07115 1. 论文概述 论文标题:YOLOMG: Vision-based Drone-to-Drone Detection with Appearance and Pixel-Level Motion Fusion 作者:Hanqing Guo, Xiuxiu Lin, Shiyu Zhao 发表:未明确会议/期刊(推测为预印本或待发表) 核心贡献:…...
JS实现文件点击或者拖拽上传
B站看到了渡一大师课的切片,自己实现了一下,做下记录 效果展示 分为上传前、上传中和上传后 实现 分为两步 界面交互网络请求 源码如下 upload.html <!DOCTYPE html> <html lang"zh-CN"><head><meta charset&q…...
【KWDB 创作者计划】_ruby基础语法
以下是 Ruby 基础语法的简明总结,适合快速入门: 一、变量与常量 1. 局部变量 小写字母或下划线开头,作用域为当前代码块。 name "Alice" _age 20//局部变量附加:{{{{ 声明与命名规则 命名格式 以小写字母或下划线…...
Python Cookbook-5.15 根据姓的首字母将人名排序和分组
任务 想将一组人名写入一个地址簿,同时还希望地址簿能够根据姓的首字母进行分组,且按照字母顺序表排序。 解决方案 Python 2.4 的新 itertools.groupby 函数使得这个任务很简单: import itertools def qroupnames(name_iterable):sorted_names sort…...
2025 蓝桥杯省赛c++B组个人题解
声明 本题解为退役蒻苟所写,不保证正确性,仅供参考。 花了大概2个半小时写完,感觉比去年省赛简单,难度大概等价于 codeforces dv4.5 吧 菜鸡不熟悉树上背包,调了一个多小时 题目旁边的是 cf 预测分 所有代码均以通…...
Centos7.9 升级内核,安装RTX5880驱动
系统镜像下载 https://vault.centos.org/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso 系统安装步骤省略 开始安装显卡驱动 远程登录查看内核 [root192 ~]# uname -a Linux 192.168.119.166 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x8…...
Xdocreport实现根据模板导出word
只使用freemaker生成简单的word文档很容易,但是当word文档需要插入动态图片,带循环数据,且含有富文本时解决起来相对比较复杂,但是使用Xdocreport可以轻易解决。 Xdocreport既可以实现文档填充也可以实现文档转换,此处…...
运行一次性任务与定时任务
运行一次性任务与定时任务 文章目录 运行一次性任务与定时任务[toc]一、使用Job运行一次性任务1.创建一次性任务2.测试一次性任务3.删除Job 二、使用CronJob运行定时任务1.创建定时任务2.测试定时任务3.删除CronJob 一、使用Job运行一次性任务 1.创建一次性任务 (…...
解决VS2022中scanf报错C4996
这个的原因是因为新版的VS认为scanf不安全,要去使用scanf_s,但在C语言中就需要scanf,所以我们只要以以下步骤解决就可以了。 只要加入宏定义即可 #define _CRT_SECURE_NO_WARNINGS 因为本人已经很少写小案例了,所以就用这个办法…...
当当平台商品详情接口设计与调用指南
当当平台商品详情接口设计与调用指南 接口名称 GET /api/product/detail 图书商品核心信息查询接口 请求参数说明 参数名称 类型 是否必填 说明 isbn string 是 国际标准书号(支持13位/10位) product_id string 否 平台内部商品编号(与…...
sql server分析表大小
使用自动存储过程查询 EXEC sp_spaceused YourTableName; rows:表中的行数。reserved:表占用的总空间(包括数据和索引)。data:表数据占用的空间。index_size:索引占用的空间。unused:未使用的空…...
《AI大模型应知应会100篇》第13篇:大模型评测标准:如何判断一个模型的优劣
第13篇:大模型评测标准:如何判断一个模型的优劣 摘要 近年来,大语言模型(LLMs)在自然语言处理、代码生成、多模态任务等领域取得了显著进展。然而,随着模型数量和规模的增长,如何科学评估这些模…...
Linux基础9
一、日志管理 > 日志配置文件: > > /var/log/messages #内核的消息以及各种服务的公共信息 > > /var/log/dmesg #系统启动过程信息 > > /var/log/cron #cron计划任务相关信息 > > /var…...
hyper-v server服务器部署远程访问(我目前环境:hyper-v服务器+路由器+公网ip)
Hyper-v server部署(裸金属方式) 系统镜像下载安装# 下载地址:17763.737.190906-2324.rs5_release_svc_refresh_SERVERHYPERCORE_OEM_x64FRE_zh-cn_1.iso 安装的过程很简单,和安装Windows操作系统没啥区别,这里就不记录了。 安装过程可参考:安装Hyper-v Server 2016 部…...
【区块链安全 | 第三十七篇】合约审计之获取私有数据(一)
文章目录 私有数据访问私有数据实例存储槽Solidity 中的数据存储方式1. storage(持久化存储)定长数组变长数组2. memory(临时内存)3. calldata可见性关键字私有数据存储风险安全措施私有数据 私有数据(Private Data)通常指的是只对特定主体可见或可访问的数据,在区块链…...
项目管理(高软56)
系列文章目录 项目管理 文章目录 系列文章目录前言一、进度管理二、配置管理三、质量四、风险管理五、真题总结 前言 本节主要讲项目管理知识,这些知识听的有点意思啊。对于技术人想创业,单干的都很有必要听听。 一、进度管理 二、配置管理 三、质量 四…...
程序化广告行业(79/89):技术革新与行业发展脉络梳理
程序化广告行业(79/89):技术革新与行业发展脉络梳理 大家好!一直以来,我都热衷于在技术领域不断探索,也深知知识共享对于进步的重要性。写这篇博客,就是希望能和大家一起深入研究程序化广告行业…...
零基础上手Python数据分析 (13):DataFrame 数据合并与连接 - 整合多源数据,构建完整分析视图
写在前面 —— 告别 VLOOKUP 烦恼,掌握 Pandas 合并连接利器,轻松整合分散数据 在前面的博客中,我们学习了如何读取数据、清洗数据、选取数据。 现在,我们已经能够处理单个 DataFrame 中的数据了。 然而,在实际的数据分析项目中,数据往往不是存储在一个单独的文件或表格…...
解决OBS里的鼠标太小|OBS鼠标尺寸问题
在进行OBS录制时,不少用户可能会被鼠标显示问题所困扰。比如,录制时鼠标在画面中尺寸过大,影响视觉效果;或是出现两个鼠标指针,显得杂乱无章。其实,借助一款名为Custom cursor的工具,这些问题便…...
OpenCV边缘检测方法详解
文章目录 引言一、边缘检测基础概念边缘类型 二、OpenCV中的边缘检测方法1. Sobel算子2. Scharr算子3. Laplacian算子4. Canny边缘检测 三、性能比较与选择建议四、总结 引言 边缘检测是计算机视觉和图像处理中的基础技术,它能有效识别图像中物体的边界,…...
