两幅图中相同区域的相似度比较
- 1.OpenCV和Python实现的两幅图相似度衡量方法
- 1. 均方误差(MSE)
- 2. 结构相似性指数(SSIM)
- 图像协方差能显示结构特征的原因
- 3. 直方图相似度
- 4. 特征点匹配
- 5. 相关系数(Pearson Correlation)
- **方法对比与适用场景**
- 2.纹理特征比较的方法
- 基于统计的方法
- 基于频谱的方法
- 灰度共生矩阵(GLCM)
- 局部二值模式(LBP)
- 小波变换
- 基于结构的方法
- 基于模型的方法
以下是基于OpenCV和Python实现的两幅图相似度衡量方法,涵盖像素级、结构特征和局部特征等多种方式:
1.OpenCV和Python实现的两幅图相似度衡量方法
1. 均方误差(MSE)
原理:计算两图对应像素差的平方均值,值越小越相似。
import cv2
import numpy as np
def mse(img1, img2):
# 确保图像尺寸相同
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))
# 转换为灰度图(若非必需可跳过)
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 计算MSE
err = np.sum((img1.astype("float") - img2.astype("float")) ** 2)
err /= float(img1.shape[0] * img1.shape[1])
return err
# 使用示例
img1 = cv2.imread("image1.jpg")
img2 = cv2.imread("image2.jpg")
print("MSE:", mse(img1, img2))
2. 结构相似性指数(SSIM)
SSIM(结构相似性指数,Structural Similarity Index Measure) 是一种用于衡量两幅图像相似度的指标。它不仅考虑了图像的亮度、对比度,还考虑了结构信息,因此在图像质量评估中表现优异。
SSIM 原理
SSIM 通过以下三个方面的比较来计算两幅图像的相似度:
-
亮度(Luminance):
- 比较两幅图像的平均亮度。
- 公式:
-
对比度(Contrast):
- 比较两幅图像的对比度。
- 公式:
-
结构(Structure):
- 比较两幅图像的结构信息。
- 公式:
在图像处理中,协方差能够显示图像的结构特征,这与协方差的定义和性质密切相关,同时协方差和方差也有着特定的区别与联系,以下是具体说明:
图像协方差能显示结构特征的原因
- 反映像素间的相关性:图像可以看作是一个二维的像素矩阵,协方差用于衡量两个随机变量之间的线性关系强度和方向。在图像中,每个像素的灰度值或颜色值可视为一个随机变量。计算图像中不同位置像素之间的协方差,能够反映出这些像素之间的相关性。如果两个像素位置的协方差较大,说明这两个位置的像素值变化趋势较为一致,可能存在某种结构特征,比如它们可能属于图像中的同一条边缘、同一区域等;反之,如果协方差较小或为零,说明这两个像素之间的相关性较弱,它们在图像结构上可能没有直接的关联。
- 体现图像的统计特性:通过计算图像中不同区域或不同方向上像素的协方差,可以得到关于图像统计特性的信息。例如,在水平方向和垂直方向上计算协方差,能够了解图像在这两个方向上的变化规律。如果水平方向上的协方差呈现出一定的周期性或规律性,可能表示图像中存在水平方向的条纹或纹理等结构特征;垂直方向同理。这些统计特性能够帮助我们提取和分析图像的结构信息。
最终的 SSIM 值是这三个分量的乘积:
Python 实现
可以使用 scikit-image
库中的 structural_similarity
函数来计算 SSIM。
安装依赖
pip install scikit-image
代码示例
from skimage.metrics import structural_similarity as ssim
import cv2
import numpy as np
# 读取图像
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
# 调整图像大小(确保两幅图像尺寸相同)
image2 = cv2.resize(image2, (image1.shape[1], image1.shape[0]))
# 计算 SSIM
ssim_value, ssim_map = ssim(image1, image2, full=True)
# 打印 SSIM 值
print(f"SSIM: {ssim_value}")
# 可视化 SSIM 图
ssim_map_normalized = (ssim_map * 255).astype(np.uint8)
cv2.imshow('SSIM Map', ssim_map_normalized)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明
- 图像读取:
- 使用 OpenCV 读取图像,并将其转换为灰度图像。
- 图像调整:
- 确保两幅图像的尺寸相同。
- 计算 SSIM:
- 使用
structural_similarity
函数计算 SSIM 值和 SSIM 图。
- 使用
- 结果可视化:
- 将 SSIM 图归一化并显示。
参数说明
full=True
:返回 SSIM 值和 SSIM 图。data_range
:图像数据的范围(例如,8 位图像的data_range=255
)。win_size
:滑动窗口的大小(默认值为 7)。
应用场景
- 图像质量评估:比较原始图像和压缩/处理后的图像。
- 图像配准:评估两幅图像的相似度。
- 目标检测:检测图像中的变化区域。
通过以上方法,可以轻松计算两幅图像的 SSIM 值,并可视化相似度图。SSIM数值越接近1越相似
3. 直方图相似度
原理:通过颜色分布(如直方图)的相似性衡量全局特征。
def hist_compare(img1, img2, method=cv2.HISTCMP_CORREL):
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))
# 计算HSV直方图
hsv1 = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
hsv2 = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
hist1 = cv2.calcHist([hsv1], [0, 1], None, [50, 60], [0, 180, 0, 256])
hist2 = cv2.calcHist([hsv2], [0, 1], None, [50, 60], [0, 180, 0, 256])
# 归一化
cv2.normalize(hist1, hist1, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
cv2.normalize(hist2, hist2, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX)
# 比较直方图
similarity = cv2.compareHist(hist1, hist2, method)
return similarity
# 可选方法:HISTCMP_CORREL(相关度), HISTCMP_CHISQR(卡方), HISTCMP_BHATTACHARYYA(巴氏距离)
print("Histogram Correlation:", hist_compare(img1, img2))
4. 特征点匹配
原理:提取局部特征点(如SIFT、ORB),通过匹配点数量衡量相似性。
def feature_match(img1, img2):
# 初始化ORB检测器
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
# 暴力匹配
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
# 根据距离筛选优质匹配
good = [m for m in matches if m.distance < 50]
return len(good)
print("Feature Matches:", feature_match(img1, img2))
5. 相关系数(Pearson Correlation)
原理:计算两图像素值的线性相关程度,范围[-1, 1]。
def correlation(img1, img2):
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY).flatten()
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY).flatten()
# 使用numpy计算相关系数
return np.corrcoef(gray1, gray2)[0, 1]
print("Correlation Coefficient:", correlation(img1, img2))
方法对比与适用场景
方法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
MSE | 计算简单快速 | 对亮度敏感,无法反映结构 | 像素级对齐的图像 |
SSIM | 符合人类视觉感知 | 计算复杂度较高 | 需要结构相似性的场景 |
直方图 | 对平移旋转不敏感 | 忽略空间分布信息 | 颜色分布相似性比较 |
特征点匹配 | 对旋转缩放鲁棒 | 依赖特征点数量和质量 | 存在局部相似结构的图像 |
相关系数 | 反映线性相关性 | 对非线性变化敏感 | 光照变化较小的图像 |
注意事项:
- 确保图像尺寸一致或进行适当缩放。
- 对于彩色图像,需统一颜色空间(如RGB转灰度或HSV)。
- 特征点方法需安装
opencv-contrib-python
以支持SIFT/SURF。
2.纹理特征比较的方法
通过纹理特征比较两幅图中相同区域的相似度,主要有基于统计方法、频谱方法、结构方法和模型方法等,以下是具体介绍:
基于统计的方法
- 灰度共生矩阵
- 原理:计算图像中具有特定空间关系的像素对的灰度统计信息,得到灰度共生矩阵。该矩阵反映了图像灰度在不同方向、不同距离上的分布情况。例如,计算水平方向上距离为1的像素对的灰度共生矩阵,能体现图像在水平方向上的纹理变化。
- 特征提取与比较:从灰度共生矩阵中提取能量、熵、对比度、相关性等特征。比较两幅图相同区域的这些特征值,计算它们之间的差值或距离,如欧氏距离,距离越小,说明相同区域的纹理相似度越高。
- 局部二值模式
- 原理:以每个像素为中心,将其邻域像素与中心像素的灰度值进行比较,根据比较结果生成一个二进制编码,这个编码反映了该像素点的局部纹理特征。例如,对于一个3×3的邻域,将周围8个像素与中心像素比较,大于中心像素记为1,小于记为0,得到一个8位的二进制码。
- 特征提取与比较:将图像中每个像素的局部二值模式进行统计,得到局部二值模式直方图。通过比较两幅图相同区域的局部二值模式直方图的相似度来衡量纹理相似度,常用的方法有直方图相交法、巴氏距离等。
基于频谱的方法
- 傅里叶变换
- 原理:将图像从空间域转换到频率域,得到图像的频谱。图像中的纹理信息在频率域中表现为不同频率成分的能量分布。例如,图像中的高频部分通常对应着纹理的细节信息,低频部分对应着纹理的大致轮廓。
- 特征提取与比较:对两幅图相同区域的频谱进行分析,提取频谱的能量分布、相位等特征。比较这些特征的相似性,如计算频谱能量的相关性,相关性越高,说明纹理相似度越高。
- 小波变换
- 原理:通过小波函数对图像进行多尺度分解,将图像分解为不同频率子带的系数。不同尺度和方向的小波系数能够捕捉到图像不同层次的纹理信息,如水平、垂直和对角方向的纹理细节。
- 特征提取与比较:从各子带中提取能量、方差等特征,构建特征向量。比较两幅图相同区域的小波特征向量的距离或相似度,如采用欧氏距离或余弦相似度,以此判断纹理的相似程度。
还可以使用多种方法基于纹理检测来实现相同尺寸图像的相似度比较,以下是一些常见的方法及示例代码:
灰度共生矩阵(GLCM)
灰度共生矩阵是一种通过统计图像中灰度值的空间相关性来描述纹理特征的方法。可以计算图像的GLCM特征,然后比较这些特征来衡量图像的相似度。
from skimage.feature import greycomatrix, greycoprops
import numpy as np
import cv2
def glcm_similarity(image1, image2):
# 计算灰度共生矩阵
glcm1 = greycomatrix(image1, distances=[1], angles=[0], levels=256, symmetric=True, normed=True)
glcm2 = greycomatrix(image2, distances=[1], angles=[0], levels=256, symmetric=True, normed=True)
# 计算对比度、相关性、能量和同质性等特征
props1 = [greycoprops(glcm1, prop) for prop in ['contrast', 'correlation', 'energy', 'homogeneity']]
props2 = [greycoprops(glcm2, prop) for prop in ['contrast', 'correlation', 'energy', 'homogeneity']]
# 计算特征向量之间的欧氏距离作为相似度度量
similarity = np.linalg.norm(np.array(props1) - np.array(props2))
return similarity
# 读取图像并转换为灰度图
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
similarity = glcm_similarity(image1, image2)
print("GLCM Similarity:", similarity)
局部二值模式(LBP)
局部二值模式是一种用于描述图像局部纹理特征的方法,它通过比较中心像素与周围像素的灰度值来生成特征。
from skimage.feature import local_binary_pattern
import numpy as np
import cv2
def lbp_similarity(image1, image2):
# 设置LBP参数
radius = 1
n_points = 8 * radius
# 计算LBP特征
lbp1 = local_binary_pattern(image1, n_points, radius, method='uniform')
lbp2 = local_binary_pattern(image2, n_points, radius, method='uniform')
# 计算LBP直方图
hist1, _ = np.histogram(lbp1.ravel(), bins=np.arange(0, n_points + 3), range=(0, n_points + 2))
hist2, _ = np.histogram(lbp2.ravel(), bins=np.arange(0, n_points + 3), range=(0, n_points + 2))
# 归一化直方图
hist1 = hist1.astype("float") / hist1.sum()
hist2 = hist2.astype("float") / hist2.sum()
# 计算直方图的卡方距离作为相似度度量
similarity = 0.5 * np.sum([((a - b) ** 2) / (a + b + 1e-10) for a, b in zip(hist1, hist2)])
return similarity
# 读取图像并转换为灰度图
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
similarity = lbp_similarity(image1, image2)
print("LBP Similarity:", similarity)
小波变换
小波变换可以将图像分解为不同频率的子带,通过分析这些子带的系数来提取纹理特征。
import pywt
import numpy as np
import cv2
def wavelet_similarity(image1, image2):
# 进行小波变换
coeffs1 = pywt.dwt2(image1, 'haar')
coeffs2 = pywt.dwt2(image2, 'haar')
# 提取小波系数
cA1, (cH1, cV1, cD1) = coeffs1
cA2, (cH2, cV2, cD2) = coeffs2
# 计算系数的差异
diff_A = np.linalg.norm(cA1 - cA2)
diff_H = np.linalg.norm(cH1 - cH2)
diff_V = np.linalg.norm(cV1 - cV2)
diff_D = np.linalg.norm(cD1 - cD2)
# 综合差异作为相似度度量
similarity = diff_A + diff_H + diff_V + diff_D
return similarity
# 读取图像并转换为灰度图
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
similarity = wavelet_similarity(image1, image2)
print("Wavelet Similarity:", similarity)
以上代码中,相似度的值越小,表示图像越相似。在实际应用中,可以根据具体需求调整参数和相似度计算方法。
基于结构的方法
- 形态学方法
- 原理:利用形态学的基本运算,如腐蚀、膨胀、开运算、闭运算等,来提取图像中的纹理结构信息。例如,通过腐蚀运算可以去除图像中的一些细小纹理,突出主要的纹理结构。
- 特征提取与比较:对经过形态学运算后的图像进行分析,提取纹理的几何形状、大小、分布等特征。比较两幅图相同区域的这些结构特征,计算特征之间的相似度,如形状相似度、分布密度相似度等,来判断纹理的相似性。
- 骨架提取方法
- 原理:提取图像中纹理的骨架,骨架可以看作是纹理的中心轴线,它反映了纹理的大致形状和走向。例如,对于一些具有线条状纹理的图像,通过骨架提取算法可以得到这些线条的中心路径。
- 特征提取与比较:比较两幅图相同区域的骨架特征,如骨架的长度、曲率、分支点等。计算这些特征的差异或相似度,以此来衡量纹理的相似程度。
基于模型的方法
- 马尔可夫随机场模型
- 原理:将图像中的纹理看作是一个马尔可夫随机场,利用马尔可夫随机场的概率模型来描述纹理的统计特性。模型中的参数反映了纹理的局部依赖关系和空间分布规律。
- 特征提取与比较:估计马尔可夫随机场模型的参数,如邻域像素之间的相互作用参数。通过比较两幅图相同区域的模型参数的相似度来判断纹理的相似性,常用的方法有计算参数之间的距离或进行模型拟合度的比较。
- 高斯混合模型
- 原理:将图像的纹理特征用高斯混合模型来建模,假设纹理特征是由多个高斯分布混合而成的。每个高斯分布代表了纹理的一种局部特征模式。
- 特征提取与比较:估计高斯混合模型的参数,包括均值、协方差等。比较两幅图相同区域的高斯混合模型的参数,计算参数之间的差异或相似度,如采用KL散度等方法来衡量两个高斯混合模型的相似程度,从而判断纹理的相似度。