1. 介绍
余弦相似度(Cosine Similarity),又称为余弦相似性,是通过计算两个向量的夹角余弦值来评估他们的相似度。余弦相似度仅仅与向量的指向方向相关,与向量的长度无关,它将向量根据坐标值绘制到向量空间中,如最常见的二维空间。因此,万物皆向量,我们可以使用余弦相似度来进行相似图片查找、相似文件搜索等工作。
两个向量间的余弦值可以通过使用欧几里得点积公式求出:
给定两个属性向量,A 和 B,其余弦相似性 θ 由点积和向量长度给出,如下所示:

原理
余弦相似度将向量根据坐标值,绘制到向量空间中,如最常见的二维空间。
- 当两个向量的夹角为0°,即余弦值为1,则两个向量有相同的指向,相当于相似度最高(其他任何角度的余弦值都不大于1)。
- 当两个向量的夹角为90°,即余弦值为0,则两个向量垂直。
- 当两个向量的夹角为180°,即余弦值为-1,则两个向量指向完全相反的方向,相当于完全不是同类。
余弦相似度而非算法,求出余弦相似度后,到底阈值如何界定(值大于多少认为是样本的相似同类),往往需要依次用不同的阈值数值对全部数据集进行测试,挑选效果最好的数值作为阈值。
余弦相似度通常用于正空间。余弦值的范围在-1到1之间,因为包含负值,有时不便于使用。改进方法有:
- 将余弦相似度用于正空间,对于各个维度均为正的向量,可以保证余弦相似度非负(该空间的夹角被限定在 0-90,或者根据公式,内积恒为正),所以可以转为 [0, 1] 上的有界相似性。
- 用1减余弦相似度,此时结果范围为 [0, 2],且值越小表示越接近(类似欧氏距离)。
2. 实验一:查找相似图像
2.1.1 魔法
- 图像加载和预处理: 读取目标图像。预处理图像,例如转换为灰度图像、调整大小等。
- 特征提取: 选择图像特征,这里通常使用直方图,对每张图像计算所选特征,得到特征向量。
- 相似度计算: 使用余弦相似度计算两个特征向量之间的相似性。相似度的计算通常在 [0, 1] 范围,越接近1表示越相似。
- 排序和筛选: 对相似图像按照相似度降序排序。根据需求,可以选择保留相似度高于某个阈值的图像。
- 结果展示: 展示相似度高的图像作为结果。可以通过图形界面、命令行输出或其他方式呈现结果。
2.1.2 实验
第一步:图像加载和预处理
读取目标图像。预处理图像,例如转换为灰度图像、调整大小等。
"""
以图搜图:余弦相似度(Cosine Similarity)查找相似图像的原理与实现
实验环境:Win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | Matplotlib 3.7.1
实验时间:2023-11-30
实例名称:imgCosineSimilarity_v1.0_show.py
"""
import os
import cv2
import matplotlib.pyplot as plt
# 目标图像素材库文件夹路径
database_dir = '../../P0_Doc/img_data/'
# 读取查询图像和数据库中的图像
img1_path = database_dir + 'car-101.jpg'
img2_path = database_dir + 'car-102.jpg'
img3_path = database_dir + 'car-103.jpg'
img4_path = database_dir + 'car-106.jpg'
img5_path = database_dir + 'car-109.jpg'
# 读取图像
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
img3 = cv2.imread(img3_path)
img4 = cv2.imread(img4_path)
img5 = cv2.imread(img5_path)
# 将图像转换为灰度图像
img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
img3_gray = cv2.cvtColor(img3, cv2.COLOR_BGR2GRAY)
img4_gray = cv2.cvtColor(img4, cv2.COLOR_BGR2GRAY)
img5_gray = cv2.cvtColor(img5, cv2.COLOR_BGR2GRAY)
# 绘制子图
plt.figure(figsize=(12, 4))
# 绘制灰度图像
plt.subplot(1, 5, 1)
plt.imshow(img1_gray, cmap='gray')
plt.title(os.path.basename(img1_path))
plt.subplot(1, 5, 2)
plt.imshow(img2_gray, cmap='gray')
plt.title(os.path.basename(img2_path))
plt.subplot(1, 5, 3)
plt.imshow(img3_gray, cmap='gray')
plt.title(os.path.basename(img3_path))
plt.subplot(1, 5, 4)
plt.imshow(img4_gray, cmap='gray')
plt.title(os.path.basename(img4_path))
plt.subplot(1, 5, 5)
plt.imshow(img5_gray, cmap='gray')
plt.title(os.path.basename(img5_path))
plt.tight_layout()
# 显示灰度图像
plt.show()
灰度图像:

第二步:特征提取
选择图像特征,这里通常使用直方图,对每张图像计算所选特征,得到特征向量。
# 计算图像的直方图
img1_hist = cv2.calcHist([img1_gray], [0], None, [256], [0, 256])
img2_hist = cv2.calcHist([img2_gray], [0], None, [256], [0, 256])
img3_hist = cv2.calcHist([img3_gray], [0], None, [256], [0, 256])
img4_hist = cv2.calcHist([img4_gray], [0], None, [256], [0, 256])
img5_hist = cv2.calcHist([img5_gray], [0], None, [256], [0, 256])
# 获取图像的特征向量
vector1 = img1_hist.flatten()
vector2 = img2_hist.flatten()
vector3 = img3_hist.flatten()
vector4 = img4_hist.flatten()
vector5 = img5_hist.flatten()
# 使用垂直线(stem lines)绘制向量
plt.figure(figsize=(8, 4))
# 绘制向量1
plt.subplot(1, 5, 1)
plt.stem(vector1)
plt.title('Vector 1')
# 绘制向量2
plt.subplot(1, 5, 2)
plt.stem(vector2)
plt.title('Vector 2')
# 绘制向量3
plt.subplot(1, 5, 3)
plt.stem(vector3)
plt.title('Vector 3')
# 绘制向量4
plt.subplot(1, 5, 4)
plt.stem(vector4)
plt.title('Vector 4')
# 绘制向量5
plt.subplot(1, 5, 5)
plt.stem(vector5)
plt.title('Vector 5')
# 图像向量可视化
plt.tight_layout()
plt.show()
图像特征向量可视化,横向对比:

使用散点图绘制特征向量:
# 使用散点图绘制向量
plt.figure(figsize=(8, 4))
# 绘制散点图
plt.scatter(range(len(vector1)), vector1, label='Vector 1', marker='o', s=10)
plt.scatter(range(len(vector2)), vector2, label='Vector 2', marker='x', s=10)
plt.scatter(range(len(vector3)), vector3, label='Vector 3', marker='o', s=10)
plt.scatter(range(len(vector4)), vector4, label='Vector 4', marker='o', s=10)
plt.scatter(range(len(vector5)), vector5, label='Vector 5', marker='o', s=10)
plt.title('Scatter Plot of Vectors')
plt.xlabel('Index')
plt.ylabel('Value')
# 添加图例
plt.legend()
# 图像向量可视化
plt.show()
图像特征向量散点图可视化:

通过可视化纵向对比测试图像的特征向量,不难发现,图像1与图像2的特征向量完全重合,即完全相似。
第三步:相似度计算
使用余弦相似度计算两个特征向量之间的相似性。相似度的计算通常在 [0, 1] 范围,越接近1表示越相似。
# 归一化直方图:将特征表示成一维向量
vector1 = img1_hist.flatten()
vector2 = img2_hist.flatten()
# 计算向量 vector1 和 vector2 的点积,即对应元素相乘后相加得到的标量值
dot_product = np.dot(vector1, vector2)
# 计算向量 vector1 的 L2 范数,即向量各元素平方和的平方根
norm_vector1 = np.linalg.norm(vector1)
# 计算向量 vector2 的 L2 范数
nor


1万+

被折叠的 条评论
为什么被折叠?



