当前位置: 代码网 > it编程>编程语言>C/C++ > 利用C++和OpenCV库计算图像颜色直方图并比较相似度

利用C++和OpenCV库计算图像颜色直方图并比较相似度

2025年06月05日 C/C++ 我要评论
简介图像直方图是图像中像素强度分布的图形表示。对于彩色 图像,我们通常会为每个颜色通道(例如 bgr 或 hsv)计算直方图。通过比较两张图片的直方图,我们可以获得它们在颜色分布上的相似程度。open

简介

图像直方图是图像中像素强度分布的图形表示。对于彩色 图像,我们通常会为每个颜色通道(例如 bgr 或 hsv)计算直方图。通过比较两张图片的直方图,我们可以获得它们在颜色分布上的相似程度。opencv 提供了 cv::calchist 函数用于计算直方图,以及 cv::comparehist 函数用于比较两个直方图。

先决条件

  • c++ 编译器: 如 g++ (mingw for windows), clang, msvc。
  • opencv 库: 需要正确安装并配置好编译环境 (版本 3.x 或 4.x)。
  • 两张待比较的图像: 准备好两张图片文件(例如 image1.jpg 和 image2.jpg)。

核心步骤

  1. 加载图像: 使用 cv::imread 读取两张待比较的图像。
  2. 色彩空间转换 (可选但推荐): 将图像从 bgr 转换到 hsv 色彩空间。hsv 对光照变化的鲁棒性通常比 bgr 好,尤其是 h (hue) 和 s (saturation) 通道。
  3. 计算直方图:
    • 定义直方图参数(如通道、bins 数量、取值范围)。
    • 使用 cv::calchist 为每张图像计算 h-s 二维直方图或单个通道的一维直方图。
  4. 归一化直方图 (可选但推荐): 为了消除图像尺寸差异带来的影响,通常会对直方图进行归一化,使其和为1。可以使用 cv::normalize
  5. 比较直方图: 使用 cv::comparehist 函数,选择一种比较方法(如相关性、卡方、交集、巴氏距离)来计算两个直方图之间的相似度/差异度。
  6. 输出结果: 显示比较得分。

代码实现

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

// 函数:计算并归一化图像的 h-s 直方图
cv::mat calculatehsnormalizedhistogram(const cv::mat& image) {
    cv::mat hsvimage;
    cv::cvtcolor(image, hsvimage, cv::color_bgr2hsv);

    // h-s 直方图参数
    // 我们只使用 h 和 s 两个通道
    int hbins = 50; int sbins = 60;
    int histsize[] = { hbins, sbins };

    // hue 范围 [0, 180], saturation 范围 [0, 256]
    float hranges[] = { 0, 180 };
    float sranges[] = { 0, 256 };
    const float* ranges[] = { hranges, sranges };

    // 我们计算 h 和 s 通道的直方图
    int channels[] = { 0, 1 }; // h 通道索引为 0, s 通道索引为 1

    cv::mat hist;
    cv::calchist(&hsvimage, 1, channels, cv::mat(), hist, 2, histsize, ranges, true, false);
    cv::normalize(hist, hist, 0, 1, cv::norm_minmax, -1, cv::mat());

    return hist;
}


int main(int argc, char** argv) {
    if (argc < 3) {
        std::cerr << "用法: " << argv[0] << " <图像1路径> <图像2路径>" << std::endl;
        return -1;
    }

    cv::mat image1 = cv::imread(argv[1]);
    cv::mat image2 = cv::imread(argv[2]);

    if (image1.empty() || image2.empty()) {
        std::cerr << "错误: 无法加载一张或两张图像!" << std::endl;
        return -1;
    }

    // 计算直方图
    cv::mat hist1 = calculatehsnormalizedhistogram(image1);
    cv::mat hist2 = calculatehsnormalizedhistogram(image2);

    // 比较直方图的方法
    // opencv 提供了多种比较方法,这里演示几种常用的
    // histcmp_correl: 相关性 (值越大越相似, 范围 [-1, 1])
    // histcmp_chisqr: 卡方 (值越小越相似, 范围 [0, inf))
    // histcmp_intersect: 交集 (值越大越相似, 范围 [0, sum(hist1) or sum(hist2) after normalization])
    // histcmp_bhattacharyya: 巴氏距离 (值越小越相似, 范围 [0, 1])

    std::cout << "直方图比较结果:" << std::endl;

    double correlation = cv::comparehist(hist1, hist2, cv::histcmp_correl);
    std::cout << "相关性 (correlation): " << correlation << " (越高越相似)" << std::endl;

    double chisquare = cv::comparehist(hist1, hist2, cv::histcmp_chisqr);
    std::cout << "卡方 (chi-square): " << chisquare << " (越低越相似)" << std::endl;

    double intersection = cv::comparehist(hist1, hist2, cv::histcmp_intersect);
    std::cout << "交集 (intersection): " << intersection << " (越高越相似)" << std::endl;

    double bhattacharyya = cv::comparehist(hist1, hist2, cv::histcmp_bhattacharyya);
    std::cout << "巴氏距离 (bhattacharyya): " << bhattacharyya << " (越低越相似)" << std::endl;

    // 可选:显示图像
    cv::imshow("image 1", image1);
    cv::imshow("image 2", image2);
    cv::waitkey(0);
    cv::destroyallwindows();

    return 0;
}

代码详解

  1. calculatehsnormalizedhistogram 函数:

    • cv::cvtcolor(image, hsvimage, cv::color_bgr2hsv);: 将输入的 bgr 图像转换为 hsv 图像。
    • hbinssbins: 定义 h (色调) 和 s (饱和度) 通道直方图的 bin (条柱) 的数量。
    • hrangessranges: 定义 h 和 s 通道像素值的范围。opencv 中 h 的范围是 [0, 179],s 和 v 的范围是 [0, 255]。
    • channels: 指定要计算直方图的通道,这里是第 0 (h) 和第 1 (s) 通道。
    • cv::calchist(...): 计算 h-s 二维直方图。
      • &hsvimage: 输入图像的指针 (这里用数组是因为可以传入多个图像,但我们只用一个)。
      • 1: 图像数量。
      • channels: 要统计的通道列表。
      • cv::mat(): 可选的掩码 (mask),这里不使用。
      • hist: 输出的直方图。
      • 2: 直方图的维度 (因为是 h-s 二维直方图)。
      • histsize: 每个维度中 bin 的数量。
      • ranges: 每个维度值的范围。
      • true: 直方图是均匀的。
      • false: 直方图在计算时不累积。
    • cv::normalize(hist, hist, 0, 1, cv::norm_minmax, -1, cv::mat());: 将直方图归一化到 [0, 1] 范围,以便比较。
  2. main 函数:

    • 加载两张图像。
    • 调用 calculatehsnormalizedhistogram 分别计算两张图像的 h-s 直方图。
    • 使用 cv::comparehist 和不同的比较方法 (cv::histcmp_correlcv::histcmp_chisqrcv::histcmp_intersectcv::histcmp_bhattacharyya) 比较两个归一化后的直方图。
    • 打印比较结果。
    • 可选地显示图像。

编译与运行

假设你的 c++ 文件名为 histogram_comparison.cpp,并且 opencv 已正确配置。

linux / macos (使用 g++):

你需要使用 pkg-config 来获取 opencv 的编译和链接标志。

g++ histogram_comparison.cpp -o histogram_comparator $(pkg-config --cflags --libs opencv4)
./histogram_comparator path/to/image1.jpg path/to/image2.jpg

如果你的 opencv 版本不是 4.x,或者 pkg-config 配置的是旧版本,你可能需要使用 opencv 替换 opencv4。

windows (使用 visual studio):

你需要在项目中配置 opencv 的包含目录、库目录,并链接相应的 opencv 库文件。

cmake (推荐的跨平台方式):

创建一个 cmakelists.txt 文件:

cmake_minimum_required(version 3.10)
project(histogramcomparator)

set(cmake_cxx_standard 11) # 或更高版本

find_package(opencv required)

include_directories(${opencv_include_dirs})

add_executable(histogram_comparator histogram_comparison.cpp)
target_link_libraries(histogram_comparator ${opencv_libs})

然后编译:

mkdir build && cd build
cmake ..
make # 或者在 visual studio 中打开生成的项目并编译
./histogram_comparator path/to/image1.jpg path/to/image2.jpg

结果解读

cv::comparehist 函数返回一个 double 值,其含义取决于所选的比较方法:

  • 相关性 (cv::histcmp_correl): 结果范围为 [-1, 1]。值越接近 1,表示两直方图越相似。接近 0 表示不相关,接近 -1 表示负相关。
  • 卡方 (cv::histcmp_chisqr): 结果范围为 [0, ∞)。值越小,表示两直方图越相似。0 表示完全相同。
  • 交集 (cv::histcmp_intersect): 对于归一化到 [0,1] 的直方图,如果两个直方图完全相同,则结果为1 (如果未归一化到和为1,则为直方图的总 bin 数或像素数)。值越大,表示重叠部分越多,越相似。
  • 巴氏距离 (cv::histcmp_bhattacharyya): 结果范围为 [0, 1]。值越小,表示两直方图越相似。0 表示完全相同。

根据应用场景选择合适的比较方法。例如,相关性和交集是衡量相似度的,而卡方和巴氏距离是衡量差异度的。

总结与扩展

直方图比较提供了一种快速评估图像颜色分布相似性的方法。虽然它不考虑空间信息(即像素在哪里),但在许多场景下仍然非常有用。

可扩展的方向包括:

  • 不同颜色空间: 尝试在 bgr 或 lab 等其他颜色空间计算直方图。
  • 一维直方图: 可以为每个颜色通道分别计算一维直方图,然后组合比较结果。
  • 加权直方图: 在计算直方图时,可以根据像素位置或其他特征给予不同的权重。
  • 结合其他特征: 将直方图特征与其他图像特征(如纹理、形状)结合起来,以获得更鲁棒的图像比较。
  • 自适应 bin 数量: 根据图像内容动态调整直方图的 bin 数量。

希望本文能帮助你理解并使用 opencv 进行图像直方图比较!

以上就是利用c++和opencv库计算图像颜色直方图并比较相似度的详细内容,更多关于c++ opencv图像直方图和相似度的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com