OpenCV进行图像相似度对比的几种办法

本文介绍了三种图像相似度对比方法:PSNR(峰值信噪比)、感知哈希算法和OpenCV中的特征点计算。通过这些方法,可以评估图像的失真程度和相似性,适用于图像检索和识别场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处:http://blog.youkuaiyun.com/wangyaninglm/article/details/43853435
来自:shiter编写程序的艺术


这里写图片描述

对计算图像相似度的方法,本文做了如下总结,主要有三种办法:


1.PSNR峰值信噪比

PSNR(Peak Signal to Noise Ratio),一种全参考的图像质量评价指标。

简介:https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio

PSNR是最普遍和使用最为广泛的一种图像客观评价指标,然而它是基于对应像素点间的误差,即基于误差敏感的图像质量评价。由于并未考虑到人眼的视觉特性(人眼对空间频率较低的对比差异敏感度较高,人眼对亮度对比差异的敏感度较色度高,人眼对一个区域的感知结果会受到其周围邻近区域的影响等),因而经常出现评价结果与人的主观感觉不一致的情况。

SSIM(structural similarity)结构相似性,也是一种全参考的图像质量评价指标,它分别从亮度、对比度、结构三方面度量图像相似性。

这里写图片描述

SSIM取值范围[0,1],值越大,表示图像失真越小.

在实际应用中,可以利用滑动窗将图像分块,令分块总数为N,考虑到窗口形状对分块的影响,采用高斯加权计算每一窗口的均值、方差以及协方差,然后计算对应块的结构相似度SSIM,最后将平均值作为两图像的结构相似性度量,即平均结构相似性MSSIM:


参考资料

[1] 峰值信噪比-维基百科

[2] 王宇庆,刘维亚,王勇. 一种基于局部方差和结构相似度的图像质量评价方法[J]. 光电子激光,2008。
[3]http://www.cnblogs.com/vincent2012/archive/2012/10/13/2723152.html

官方文档的说明,不过是GPU版本的,我们可以修改不用gpu不然还得重新编译

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.html#videoinputpsnrmssim
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/gpu/gpu-basics-similarity/gpu-basics-similarity.html?highlight=psnr


// PSNR.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <iostream>                   // Console I/O
#include <sstream>                    // String to number conversion

#include <opencv2/core/core.hpp>      // Basic OpenCV structures
#include <opencv2/imgproc/imgproc.hpp>// Image processing methods for the CPU
#include <opencv2/highgui/highgui.hpp>// Read images
#include <opencv2/gpu/gpu.hpp>        // GPU structures and methods

using namespace std;
using namespace cv;

double getPSNR(const Mat& I1, const Mat& I2);      // CPU versions
Scalar getMSSIM( const Mat& I1, const Mat& I2);

double getPSNR_GPU(const Mat& I1, const Mat& I2);  // Basic GPU versions
Scalar getMSSIM_GPU( const Mat& I1, const Mat& I2);

struct BufferPSNR                                     // Optimized GPU versions
{   // Data allocations are very expensive on GPU. Use a buffer to solve: allocate once reuse later.
    gpu::GpuMat gI1, gI2, gs, t1,t2;

    gpu::GpuMat buf;
};
double getPSNR_GPU_optimized(const Mat& I1, const Mat& I2, BufferPSNR& b);

struct BufferMSSIM                                     // Optimized GPU versions
{   // Data allocations are very expensive on GPU. Use a buffer to solve: allocate once reuse later.
    gpu::GpuMat gI1, gI2, gs, t1,t2;

    gpu::GpuMat I1_2, I2_2, I1_I2;
    vector<gpu::GpuMat> vI1, vI2;

    gpu::GpuMat mu1, mu2; 
    gpu::GpuMat mu1_2, mu2_2, mu1_mu2; 

    gpu::GpuMat sigma1_2, sigma2_2, sigma12; 
    gpu::GpuMat t3; 

    gpu::GpuMat ssim_map;

    gpu::GpuMat buf;
};
Scalar getMSSIM_GPU_optimized( const Mat& i1, const Mat& i2, BufferMSSIM& b);

void help()
{
    cout
        << "\n--------------------------------------------------------------------------" << endl
        << "This program shows how to port your CPU code to GPU or write that from scratch." << endl
        << "You can see the performance improvement for the similarity check methods (PSNR and SSIM)."  << endl
        << "Usage:"                                                               << endl
        << "./gpu-basics-similarity referenceImage comparedImage numberOfTimesToRunTest(like 10)." << endl
        << "--------------------------------------------------------------------------"   << endl
        << endl;
}

int main(int argc, char *argv[])
{
    help(); 
    Mat I1 = imread("swan1.jpg",1);           // Read the two images
    Mat I2 = imread("swan2.jpg",1);

    if (!I1.data || !I2.data)           // Check for success
    {
        cout << "Couldn't read the image";
        return 0;
    }

    BufferPSNR bufferPSNR;
    BufferMSSIM bufferMSSIM;

    int TIMES; 
    stringstream sstr("500"); 
    sstr >> TIMES;
    double time, result;

    //------------------------------- PSNR CPU ----------------------------------------------------
    time = (double)getTickCount();    

    for (int i = 0; i < TIMES; ++i)
        result = getPSNR(I1,I2);

    time = 1000*((double)getTickCount() - time)/getTickFrequency();
    time /= TIMES;

    cout << "Time of PSNR CPU (averaged for " << TIMES << " runs): " << time << " milliseconds."
        << " With result of: " <<  result << endl; 

    ////------------------------------- PSNR GPU ----------------------------------------------------
    //time = (double)getTickCount();    

    //for (int i = 0; i < TIMES; ++i)
    //  result = getPSNR_GPU(I1,I2);

    //time = 1000*((double)getTickCount() - time)/getTickFrequency();
    //time /= TIMES;

    //cout << "Time of PSNR GPU (averaged for " << TIMES << " runs): " << time << " milliseconds."
    //  << " With result of: " <<  result << endl; 
/*
    //------------------------------- PSNR GPU Optimized--------------------------------------------
    time = (double)getTickCount();                                  // Initial call
    result = getPSNR_GPU_optimized(I1, I2, bufferPSNR);
    time = 1000*((double)getTickCount() - time)/getTickFrequency();
    cout << "Initial call GPU optimized:              " << time  <<" milliseconds."
        << " With result of: " << result << endl;

    time = (double)getTickCount();    
    for (int i = 0; i < TIMES; ++i)
        result = getPSNR_GPU_optimized(I1, I2, bufferPSNR);

    time = 1000*((double)getTickCount() - time)/getTickFrequency();
    time /= TIMES;

    cout << "Time of PSNR GPU OPTIMIZED ( / " << TIMES << " runs): " << time 
        << " milliseconds." << " With result of: " <<  result << endl << en
### 使用OpenCV计算图像对比相似度的方法 在计算机视觉领域,使用OpenCV进行图像对比相似度的计算是一种常见的需求。以下是几种常用的方法及其代码示例: #### 方法一:SSIM(结构相似性指数) SSIM算法通过计算两张图像的均值、方差以及协方差来衡量它们的相似性[^2]。SSIM的结果是一个介于-1到1之间的值,其中1表示完全相同。 ```python import cv2 import numpy as np def calculate_ssim(image1_path, image2_path): # 读取图像 img1 = cv2.imread(image1_path, cv2.IMREAD_GRAYSCALE) img2 = cv2.imread(image2_path, cv2.IMREAD_GRAYSCALE) # 计算SSIM ssim_value = cv2.SSIM(img1, img2) return ssim_value # 示例调用 ssim_result = calculate_ssim('image1.jpg', 'image2.jpg') print(f"SSIM: {ssim_result}") ``` #### 方法二:dHash(感知哈希算法) dHash算法通过将图像缩小到固定尺寸并灰度化,然后比较像素差异来生成哈希值,并计算汉明距离以评估相似度[^3]。 ```python import cv2 import numpy as np def calculate_dhash(image_path): # 读取图像并调整大小为8x8 img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) img = cv2.resize(img, (9, 8)) # 计算差异 diff = [] for i in range(8): for j in range(8): if img[i][j] > img[i][j + 1]: diff.append(1) else: diff.append(0) # 转换为哈希值 dhash = ''.join(map(str, diff)) return dhash def calculate_hamming_distance(hash1, hash2): return sum(c1 != c2 for c1, c2 in zip(hash1, hash2)) # 示例调用 hash1 = calculate_dhash('image1.jpg') hash2 = calculate_dhash('image2.jpg') hamming_distance = calculate_hamming_distance(hash1, hash2) print(f"Hamming Distance: {hamming_distance}") ``` #### 方法三:直方图比较 直方图比较是另一种常用的图像相似度计算方法。通过计算两张图像的直方图并使用某种距离度量(如欧氏距离或卡方距离)来评估相似度。 ```python import cv2 import numpy as np def calculate_histogram_similarity(image1_path, image2_path): # 读取图像 img1 = cv2.imread(image1_path) img2 = cv2.imread(image2_path) # 计算直方图 hist1 = cv2.calcHist([img1], [0], None, [256], [0, 256]) hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256]) # 归一化 cv2.normalize(hist1, hist1) cv2.normalize(hist2, hist2) # 比较直方图 similarity = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL) return similarity # 示例调用 hist_similarity = calculate_histogram_similarity('image1.jpg', 'image2.jpg') print(f"Histogram Similarity: {hist_similarity}") ``` ### 注意事项 - SSIM算法适用于需要精确相似度评估的场景,但其计算复杂度较高。 - dHash算法适合快速判断图像是否相似,但对于细节差异可能不够敏感。 - 直方图比较方法对颜色分布的变化较为敏感,但可能忽略空间信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值