如何比较两幅图的相似度

更新时间:2023-06-16 16:14:28 点击次数:1281次
比较两幅图的相似度可以使用多种方法,以下是其中几种常用的方法:

1. 均方误差(MSE):将两幅图像的像素值逐个进行比较,计算均方误差。均方误差越小,表示两幅图像越相似。

以下是使用 OpenCV 在 C++ 和 Python 中演示均方误差(MSE)的示例代码。

C++ 代码:

```cpp
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    // 读入两张图像
    Mat img1 = imread("image1.jpg", IMREAD_GRAYSCALE);
    Mat img2 = imread("image2.jpg", IMREAD_GRAYSCALE);

    // 如果图像为空,输出错误信息并退出
    if (img1.empty() || img2.empty()) {
        cout << "Failed to read image file." << endl;
        return -1;
    }

    // 计算均方误差
    double mse = mean((img1 - img2).mul(img1 - img2))[0];

    // 输出均方误差值
    cout << "MSE: " << mse << endl;

    return 0;
}
```

Python 代码:

```python
import cv2

# 读入两张图像
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 如果图像为空,输出错误信息并退出
if img1 is None or img2 is None:
    print('Failed to read image file.')
    exit()

# 计算均方误差
mse = cv2.mean((img1 - img2) ** 2)[0]

# 输出均方误差值
print('MSE:', mse)
```

其中,`image1.jpg` 和 `image2.jpg` 分别为需要比较的两幅图像的文件名,代码中使用了 OpenCV 的 `imread` 函数读入图像,使用 `mean` 函数计算均方误差,输出结果为 MSE 的值。

2. 结构相似性指数(SSIM):主要考虑了人眼的感知特性,比较两幅图像的亮度、对比度和结构等特征。SSIM 取值范围在 [-1, 1] 之间,越接近 1 表示两幅图像越相似。

以下是使用 OpenCV 在 C++ 和 Python 中演示结构相似性指数(SSIM)的示例代码。

C++ 代码:

```cpp
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    // 读入两张图像
    Mat img1 = imread("image1.jpg", IMREAD_GRAYSCALE);
    Mat img2 = imread("image2.jpg", IMREAD_GRAYSCALE);

    // 如果图像为空,输出错误信息并退出
    if (img1.empty() || img2.empty()) {
        cout << "Failed to read image file." << endl;
        return -1;
    }

    // 计算结构相似性指数
    double ssim = 0;
    Scalar mssim = getMSSIM(img1, img2);
    ssim = (mssim[0] + mssim[1] + mssim[2]) / 3;

    // 输出结构相似性指数值
    cout << "SSIM: " << ssim << endl;

    return 0;
}
```

Python 代码:

```python
import cv2

# 读入两张图像
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 如果图像为空,输出错误信息并退出
if img1 is None or img2 is None:
    print('Failed to read image file.')
    exit()

# 计算结构相似性指数
ssim = cv2.SSIM(img1, img2)

# 输出结构相似性指数值
print('SSIM:', ssim)
```

其中,`image1.jpg` 和 `image2.jpg` 分别为需要比较的两幅图像的文件名,代码中使用了 OpenCV 的 `imread` 函数读入图像,使用 `getMSSIM` 函数计算结构相似性指数,或者直接使用 `SSIM` 函数计算,输出结果为 SSIM 的值。

3. 相关系数(Correlation Coefficient):计算两幅图像的像素值的相关系数,取值范围在 [-1, 1] 之间,越接近 1 表示两幅图像越相似。

以下是使用 OpenCV 在 C++ 和 Python 中演示相关系数(Correlation Coefficient)的示例代码。

C++ 代码:

```cpp
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    // 读入两张图像
    Mat img1 = imread("image1.jpg", IMREAD_GRAYSCALE);
    Mat img2 = imread("image2.jpg", IMREAD_GRAYSCALE);

    // 如果图像为空,输出错误信息并退出
    if (img1.empty() || img2.empty()) {
        cout << "Failed to read image file." << endl;
        return -1;
    }

    // 计算相关系数
    Mat img1_norm, img2_norm;
    normalize(img1, img1_norm, 0, 1, NORM_MINMAX, CV_32F);
    normalize(img2, img2_norm, 0, 1, NORM_MINMAX, CV_32F);
    double correlation = sum(img1_norm.mul(img2_norm))[0];

    // 输出相关系数值
    cout << "Correlation Coefficient: " << correlation << endl;

    return 0;
}
```

Python 代码:

```python
import cv2

# 读入两张图像
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 如果图像为空,输出错误信息并退出
if img1 is None or img2 is None:
    print('Failed to read image file.')
    exit()

# 计算相关系数
img1_norm = cv2.normalize(img1, None, 0, 1, cv2.NORM_MINMAX, cv2.CV_32F)
img2_norm = cv2.normalize(img2, None, 0, 1, cv2.NORM_MINMAX, cv2.CV_32F)
correlation = cv2.sumElems(img1_norm * img2_norm)[0]

# 输出相关系数值
print('Correlation Coefficient:', correlation)
```

其中,`image1.jpg` 和 `image2.jpg` 分别为需要比较的两幅图像的文件名,代码中使用了 OpenCV 的 `imread` 函数读入图像,使用 `normalize` 函数对图像进行归一化处理,计算相关系数的方法是将两幅图像对应像素值相乘,然后求和,输出结果为相关系数的值。

4. 直方图比较:将两幅图像的像素直方图进行比较,可以使用相似度度量方法,如交叉熵、卡方距离等。

以下是使用 OpenCV 在 C++ 和 Python 中演示直方图比较的示例代码。

C++ 代码:

```cpp
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    // 读入两张图像
    Mat img1 = imread("image1.jpg", IMREAD_GRAYSCALE);
    Mat img2 = imread("image2.jpg", IMREAD_GRAYSCALE);

    // 如果图像为空,输出错误信息并退出
    if (img1.empty() || img2.empty()) {
        cout << "Failed to read image file." << endl;
        return -1;
    }

    // 计算直方图
    Mat hist1, hist2;
    int channels[] = { 0 };
    int histSize[] = { 256 };
    float range[] = { 0, 256 };
    const float* ranges[] = { range };
    calcHist(&img1, 1, channels, Mat(), hist1, 1, histSize, ranges, true, false);
    calcHist(&img2, 1, channels, Mat(), hist2, 1, histSize, ranges, true, false);

    // 归一化直方图
    normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, Mat());
    normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());

    // 计算直方图比较结果
    double cmp = compareHist(hist1, hist2, HISTCMP_CORREL);

    // 输出直方图比较结果
    cout << "Histogram Comparison: " << cmp << endl;

    return 0;
}
```

Python 代码:

```python
import cv2

# 读入两张图像
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 如果图像为空,输出错误信息并退出
if img1 is None or img2 is None:
    print('Failed to read image file.')
    exit()

# 计算直方图
hist1 = cv2.calcHist([img1], [0], None, [256], [0, 256])
hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256])

# 归一化直方图
hist1 = cv2.normalize(hist1, None, 0, 1, cv2.NORM_MINMAX)
hist2 = cv2.normalize(hist2, None, 0, 1, cv2.NORM_MINMAX)

# 计算直方图比较结果
cmp = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)

# 输出直方图比较结果
print('Histogram Comparison:', cmp)
```

其中,`image1.jpg` 和 `image2.jpg` 分别为需要比较的两幅图像的文件名,代码中使用了 OpenCV 的 `imread` 函数读入图像,使用 `calcHist` 函数计算直方图,使用 `normalize` 函数归一化直方图,然后使用 `compareHist` 函数计算直方图比较结果,输出结果为直方图比较的值。

5. 特征匹配:使用特征点提取和匹配算法,比如 SIFT、SURF、ORB 等,找到两幅图像中相同的特征点,计算它们之间的距离或相似性度量来衡量两幅图像的相似度。

以下是使用 OpenCV 在 C++ 和 Python 中演示特征匹配的示例代码。

C++ 代码:

```cpp
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    // 读入两张图像
    Mat img1 = imread("image1.jpg", IMREAD_GRAYSCALE);
    Mat img2 = imread("image2.jpg", IMREAD_GRAYSCALE);

    // 如果图像为空,输出错误信息并退出
    if (img1.empty() || img2.empty()) {
        cout << "Failed to read image file." << endl;
        return -1;
    }

    // 检测关键点和计算描述符
    Ptr<FeatureDetector> detector = ORB::create();
    Ptr<DescriptorExtractor> extractor = ORB::create();
    vector<KeyPoint> keypoints1, keypoints2;
    Mat descriptors1, descriptors2;
    detector->detectAndCompute(img1, Mat(), keypoints1, descriptors1);
    detector->detectAndCompute(img2, Mat(), keypoints2, descriptors2);

    // 匹配描述符
    BFMatcher matcher(NORM_HAMMING);
    vector<DMatch> matches;
    matcher.match(descriptors1, descriptors2, matches);

    // 选择最佳匹配
    double max_dist = 0, min_dist = 100;
    for (int i = 0; i < descriptors1.rows; i++) {
        double dist = matches[i].distance;
        if (dist < min_dist) min_dist = dist;
        if (dist > max_dist) max_dist = dist;
    }
    vector<DMatch> good_matches;
    for (int i = 0; i < descriptors1.rows; i++) {
        if (matches[i].distance <= max(2 * min_dist, 0.02)) {
            good_matches.push_back(matches[i]);
        }
    }

    // 绘制匹配结果
    Mat img_matches;
    drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches);
    imshow("Matches", img_matches);
    waitKey();

    return 0;
}
```

Python 代码:

```python
import cv2

# 读入两张图像
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)

# 如果图像为空,输出错误信息并退出
if img1 is None or img2 is None:
    print('Failed to read image file.')
    exit()

# 检测关键点和计算描述符
detector = cv2.ORB_create()
keypoints1, descriptors1 = detector.detectAndCompute(img1, None)
keypoints2, descriptors2 = detector.detectAndCompute(img2, None)

# 匹配描述符
matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
matches = matcher.match(descriptors1, descriptors2)

# 选择最佳匹配
max_dist = 0
min_dist = 100
for match in matches:
    dist = match.distance
    if dist < min_dist:
        min_dist = dist
    if dist > max_dist:
        max_dist = dist
good_matches = []
for match in matches:
    if match.distance <= max(2 * min_dist, 0.02):
        good_matches.append(match)

# 绘制匹配结果
img_matches = cv2.drawMatches(img1, keypoints1, img2, keypoints2, good_matches, None)
cv2.imshow('Matches', img_matches)
cv2.waitKey()
```

其中,`image1.jpg` 和 `image2.jpg` 分别为需要匹配的两幅图像的文件名,代码中使用了 OpenCV 的 `imread` 函数读入图像,使用 `ORB_create` 函数创建关键点检测器和描述符提取器,使用 `detectAndCompute` 函数检测关键点和计算描述符,使用 `BFMatcher` 函数进行匹配,选择最佳匹配后使用 `drawMatches` 函数绘制匹配结果,然后使用 `imshow` 和 `waitKey` 函数显示结果。

需要注意的是,不同的方法适用于不同的场景和应用,需要根据具体的需求选择合适的方法。同时,在实际应用中还需要考虑计算速度、鲁棒性、噪声和变形等因素,综合考虑选择相似度度量方法。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!