图像对比是在计算机视觉和图像处理中常见的任务之一。它可以用于识别重复图片、图像搜索、图像相似性比较等应用场景。实现图片对比方法的方法有多种,根据不同的需求和图片类型,可以选择适合的实现方案。如果对于简单的图片对比需求,可以选择基于像素比较或直方图比较的方法;如果对于复杂的图片对比需求,可以选择基于特征提取和匹配或深度学习模型的方法。
图片相似度对比的需求,可以考虑以下几种实现方案:
实现方式:计算两张图片的直方图,并比较直方图的相似度(如卡方距离、余弦相似度等)。直方图对比是一种基于图像颜色分布的对比方法。它通过计算两张图片的直方图,并比较直方图之间的差异来评估图像的相似性。直方图对比方法适用于图像颜色分布较为重要的场景,如图像分类、图像搜索等。
在直方图对比方法中,通常使用颜色直方图来表示图像的颜色分布。颜色直方图将图像中每个像素的颜色值统计为不同颜色区间的频次,从而得到一个描述图像颜色分布的直方图。常用的颜色空间包括RGB、HSV和Lab等。
优点:对于颜色分布相似但像素值不同的图片具有较好的效果,适用于某些类型的图片(如艺术作品)。
缺点:对于颜色分布差异较大的图片,可能无法准确判断相似度。
直方图对比方法的步骤如下:
import cv2
import numpy as np
def compare_images_pixel(img1_path, img2_path):
# 读取两张图片
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
# 确保两张图片具有相同的尺寸
img1 = cv2.resize(img1, (img2.shape[1], img2.shape[0]))
# 计算两张图片的差异
diff = cv2.absdiff(img1, img2)
diff_gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
# 将差异图像转换为二值图像
_, threshold = cv2.threshold(diff_gray, 30, 255, cv2.THRESH_BINARY)
# 计算相似度
similarity = np.mean(threshold)
return similarity
# 示例用法
img1_path = 'image1.jpg'
img2_path = 'image2.jpg'
similarity = compare_images_pixel(img1_path, img2_path)
print('相似度:', similarity)
上述代码中,使用OpenCV库读取两张图片,并确保它们具有相同的尺寸。然后,计算两张图片的差异,并将差异图像转换为二值图像。最后,通过计算二值图像的平均值作为相似度指标。较小的平均值表示两张图片的像素差异较小,相似度较高。
计算结构相似性(SSIM)指标:
cv2.cvtColor
函数将两张图片转换为灰度图像。skimage.measure.compare_ssim
函数计算两张灰度图像的SSIM指标。计算方差参数:
cv2.cvtColor
函数将两张图片转换为灰度图像。numpy.var
函数。综合考虑SSIM指标和方差参数:
下面是一个示例代码,演示如何使用SSIM指标和方差参数优化基于像素比较的相似度判断:
import cv2
import numpy as np
#from skimage.measure import compare_ssim 原因:因为在skimage高版本中原来的compare_psnr和compare_ssim已经被移除
from skimage.metrics import structural_similarity as compare_ssim
from skimage.metrics import peak_signal_noise_ratio as compare_psnr
def compare_images_pixel(img1_path, img2_path):
# 读取两张图片
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
# 确保两张图片具有相同的尺寸
img1 = cv2.resize(img1, (img2.shape[1], img2.shape[0]))
# 计算结构相似性(SSIM)指标
img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ssim_score = compare_ssim(img1_gray, img2_gray)
# 计算方差参数
img1_var = np.var(img1_gray)
img2_var = np.var(img2_gray)
var_diff = np.abs(img1_var - img2_var)
# 综合考虑SSIM指标和方差参数,得到最终的相似度评分
similarity = ssim_score * (1 - var_diff)
return similarity
# 示例用法
img1_path = 'image1.jpg'
img2_path = 'image2.jpg'
similarity = compare_images_pixel(img1_path, img2_path)
print('相似度:', similarity)
在上述示例代码中,首先使用OpenCV的cv2.cvtColor
函数将两张图片转换为灰度图像。然后,使用skimage.measure.compare_ssim
函数计算灰度图像的SSIM指标。接下来,计算灰度图像的方差参数,通过numpy.var
函数计算。最后,通过加权综合考虑SSIM指标和方差参数,得到最终的相似度评分。这样可以更好地处理颜色、亮度、尺寸等变化较大的图片,提高相似度判断的准确性。
加权的数值可以根据具体需求和实际情况进行调整和优化。在示例代码中,我使用了一个简单的加权方案,将SSIM指标和方差参数进行加权综合。具体来说,我将SSIM指标乘以(1 - var_diff)作为最终的相似度评分。
这个加权方案的目的是在保持结构相似性的基础上,对方差参数进行一定程度的惩罚。当两张图片的方差差异较大时,相似度评分会相应降低。这样可以更好地处理颜色、亮度、尺寸等变化较大的图片,提高相似度判断的准性。
然而,这个加权方案可能并不适用于所有情况。根据具体的应用场景和需求,你可能需要根据实际情况进行调整和优化加权的数值。可以尝试不同的加权方案,并通过测试和评估来确定最佳的加权参数。这样可以根据具体情况优化解决像素比较方法对于颜色、亮度、尺寸等变化较大的图片的相似度判断。
基于直方图比较的图像相似度对比可以通过计算两张图片的颜色直方图差异来实现。下面是一个简单的示例代码:
import cv2
import numpy as np
def compare_images_histogram(img1_path, img2_path):
# 读取两张图片
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
# 将图片转换为HSV颜色空间
img1_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
img2_hsv = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
# 计算图片的直方图
hist1 = cv2.calcHist([img1_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
hist2 = cv2.calcHist([img2_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 归一化直方图
cv2.normalize(hist1, hist1, 0, 1, cv2.NORM_MINMAX, -1)
cv2.normalize(hist2, hist2, 0, 1, cv2.NORM_MINMAX, -1)
# 计算直方图的差异
similarity = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
return similarity
# 示例用法
img1_path = 'image1.jpg'
img2_path = 'image2.jpg'
similarity = compare_images_histogram(img1_path, img2_path)
print('相似度:', similarity)
上述代码中,使用OpenCV库读取两张图片,并将它们转换为HSV颜色空间。然后,计算图片的颜色直方图,并归一化直方图。最后,通过使用cv2.compareHist
函数计算直方图的相关性作为相似度指标。相关性的范围是[-1, 1],值越接近1表示两张图片的颜色分布越相似,相似度越高。
使用SIFT算法的示例代码:
import cv2
def compare_images(img1_path, img2_path):
# 读取两张图片
img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
# 创建SIFT特征提取器
sift = cv2.xfeatures2d.SIFT_create()
# 在两张图片上检测关键点和计算特征描述子
keypoints1, descriptors1 = sift.detectAndCompute(img1, None)
keypoints2, descriptors2 = sift.detectAndCompute(img2, None)
# 创建FLANN匹配器
flann = cv2.FlannBasedMatcher()
# 使用knnMatch进行特征匹配
matches = flann.knnMatch(descriptors1, descriptors2, k=2)
# 进行筛选,保留较好的匹配结果
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
# 计算相似度
similarity = len(good_matches) / max(len(descriptors1), len(descriptors2))
return similarity
# 示例用法
img1_path = 'image1.jpg'
img2_path = 'image2.jpg'
similarity = compare_images(img1_path, img2_path)
print('相似度:', similarity)
上述代码中,使用SIFT算法提取图片的特征描述子,然后使用FLANN匹配器进行特征匹配。通过筛选出较好的匹配结果,计算匹配点数目与特征描述子数目的比值,作为相似度指标。
使用SURF(加速稳健特征)算法的示例代码:
import cv2
def compare_images_surf(img1_path, img2_path):
# 读取两张图片
img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
# 创建SURF特征提取器
surf = cv2.xfeatures2d.SURF_create()
# 在两张图片上检测关键点和计算特征描述子
keypoints1, descriptors1 = surf.detectAndCompute(img1, None)
keypoints2, descriptors2 = surf.detectAndCompute(img2, None)
# 创建FLANN匹配器
flann = cv2.FlannBasedMatcher()
# 使用knnMatch进行特征匹配
matches = flann.knnMatch(descriptors1, descriptors2, k=2)
# 进行筛选,保留较好的匹配结果
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
# 计算相似度
similarity = len(good_matches) / max(len(descriptors1), len(descriptors2))
return similarity
# 示例用法
img1_path = 'image1.jpg'
img2_path = 'image2.jpg'
similarity = compare_images_surf(img1_path, img2_path)
print('相似度:', similarity)
使用ORB算法的示例代码:
import cv2
def compare_images_orb(img1_path, img2_path):
# 读取两张图片
img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
# 创建ORB特征提取器
orb = cv2.ORB_create()
# 在两张图片上检测关键点和计算特征描述子
keypoints1, descriptors1 = orb.detectAndCompute(img1, None)
keypoints2, descriptors2 = orb.detectAndCompute(img2, None)
# 创建BFMatcher匹配器
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 使用match进行特征匹配
matches = bf.match(descriptors1, descriptors2)
# 进行筛选,保留较好的匹配结果
good_matches = sorted(matches, key=lambda x: x.distance)[:int(len(matches) * 0.15)]
# 计算相似度
similarity = len(good_matches) / max(len(descriptors1), len(descriptors2))
return similarity
# 示例用法
img1_path = 'image1.jpg'
img2_path = 'image2.jpg'
similarity = compare_images_orb(img1_path, img2_path)
print('相似度:', similarity)
在上述代码中,使用SURF算法或ORB算法提取图片的特征描述子,并使用FLANN匹配器或BFMatcher匹配器进行特征匹配。通过筛选出较好的匹配结果,计算匹配点数目与特征描述子数目的比值,作为相似度指标。
SIFT(尺度不变特征变换)算法:
SURF(加速稳健特征)算法:
ORB(Oriented FAST and Rotated BRIEF)算法:
总体而言,SIFT算法在精度和鲁棒性方面表现良好,但计算量较大;SURF算法在速度上有所改进,对尺度和旋转变化较大的图片具有较好的效果;ORB算法在速度和内存占用方面具有优势,适用于实时应用和计算资源有限的场景。选择哪种算法取决于具体应用场景和对速度、精度、计算资源的要求。
基于深度学习模型的图像相似度对比可以通过使用卷积神经网络(Convolutional Neural Network, CNN)来提取图像的特征表示,并计算特征之间的相似度来实现。下面是一个示例代码,演示如何使用预训练的CNN模型来计算图像相似度:
import cv2
import numpy as np
from tensorflow.keras.applications import VGG16
from tensorflow.keras.models import Model
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.vgg16 import preprocess_input
def extract_features(img_path, model):
# 读取图像并预处理
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
# 提取特征
features = model.predict(x)
return features.flatten()
def compare_images_deep(img1_path, img2_path):
# 加载预训练的VGG16模型(不包括顶层分类器)
base_model = VGG16(weights='imagenet', include_top=False)
model = Model(inputs=base_model.input, outputs=base_model.get_layer('block5_pool').output)
# 提取图像特征
img1_features = extract_features(img1_path, model)
img2_features = extract_features(img2_path, model)
# 计算特征之间的余弦相似度
similarity = np.dot(img1_features, img2_features) / (np.linalg.norm(img1_features) * np.linalg.norm(img2_features))
return similarity
# 示例用法
img1_path = 'image1.jpg'
img2_path = 'image2.jpg'
similarity = compare_images_deep(img1_path, img2_path)
print('相似度:', similarity)
在上述示例代码中,首先加载预训练的VGG16模型,并提取模型的某一层的输出作为图像的特征表示。然后,使用extract_features
函数读取图片并预处理,然后通过模型提取特征。接下来,计算两张图片特征之间的余弦相似度,作为相似度评分。余弦相似度的范围是[-1, 1],值越接近1表示两张图片的特征表示越相似,相似度越高。
需要注意的是,上述示例代码使用了预训练的VGG16模型作为示例,你也可以根据具体需求选择其他的预训练模型,或者自己训练一个适合特定任务的深度学习模型。同时,根据具体情况,你可能需要对模型进行微调或调整参数,以获得更好的相似度判断效果。
运行上述代码需python版本小于3.7,opencv版本建议版本 3.4.2.17,否则由于版权问题SURF ORB SIFT算法无法使用,请不要使用最新版的opencv。