Opencv(C++)笔记--直方图比较、直方图反向投影

目录

1--直方图比较

1-1--四种常见比较方法

1-2--OpenCV API

1-3--代码实例

2--直方图反向投影

2-1--Opencv API

2-2--代码实例

2-3--代码分析

3--参考


1--直方图比较

        通过比较两幅图像的直方图,可以衡量两幅图像的相似和相关程度,一定程度上可以进行图像的匹配;

1-1--四种常见比较方法

① 相关系数(cv::HISTCMP_CORREL):数值越大,相关度越高,最大值为 1,最小值为 0;

② 卡方系数(cv::HISTCMP_CHISQR):数值越小,相关度越高,最大值无上界,最小值为 0;

③ 相交系数(cv::HISTCMP_INTERSECT):数值越大,相关度越高,最大值为 9.455319,最小值为 0;

④ 巴氏系数(cv::HISTCMP_BHATTACHARYYA):数值越小,相关度越高,最大值为 1,最小值为 0;

具体数学公式参考直方图比较方法数学公式

1-2--OpenCV API

 double result12 = cv::compareHist(hist_src1, hist_src2, cv::HISTCMP_CORREL);

1-3--代码实例

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

int main(int argc, char** argv){

    cv::Mat src1, src2;

    src1 = cv::imread("C:/Users/Liujinfu/Desktop/opencv_bilibili/test1.jpg");
    src2 = cv::imread("C:/Users/Liujinfu/Desktop/opencv_bilibili/test1_noise.jpg");

    cv::Mat origin1, origin2;
    src1.copyTo(origin1);
    src2.copyTo(origin2);


    if (src1.empty() ||  src2.empty()){
        printf("could not load image..\n");
        return -1;
    }
    cv::imshow("input1", src1);
    cv::imshow("input2", src2);

    cv::cvtColor(src1, src1, cv::COLOR_BGR2HSV);
    cv::cvtColor(src2, src2, cv::COLOR_BGR2HSV);

    int h_bins = 50, s_bins = 60;
    int histSize[] = {h_bins, s_bins};

    float h_ranges[] = {0, 180};
    float s_ranges[] = {0, 256};
    const float* ranges[] = {h_ranges, s_ranges};
    int channels[] = {0, 1};

    cv::MatND hist_src1, hist_src2;

    cv::calcHist(&src1, 1, channels, cv::Mat(), hist_src1, 2, histSize, ranges, true, false);
    cv::normalize(hist_src1, hist_src1, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());

    cv::calcHist(&src2, 1, channels, cv::Mat(), hist_src2, 2, histSize, ranges, true, false);
    cv::normalize(hist_src2, hist_src2, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());

    double result11 = cv::compareHist(hist_src1, hist_src1, cv::HISTCMP_CORREL);
    double result12 = cv::compareHist(hist_src1, hist_src2, cv::HISTCMP_CORREL);
    
    cv::putText(origin1, std::to_string(result11), cv::Point(50, 50), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
    cv::putText(origin2, std::to_string(result12), cv::Point(50, 50), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);

    cv::imshow("output1", origin1);
    cv::imshow("output2", origin2);

    cv::waitKey(0);
    return 0;
}

2--直方图反向投影

        反向投影用于反映 输入图像的像素点去适应直方图模型像素分布 的方式,反向投影首先计算某一特征的直方图模型,然后使用该模型去寻找原图像中存在的特征。反向投影在某一位置的像素数值,表示原图像对应位置像素值在原图像中的总数目。

        反向投影将图像特征反映到原图像上,对于图像中的物体特征识别和分割具有重要的作用。

2-1--Opencv API

void cv::calcBackProject(const cv::Mat *images, int nimages, const int *channels, cv::InputArray hist, cv::OutputArray backProject, const float **ranges, double scale = (1.0), bool uniform = true)

const cv::Mat *images:输入的图像或图像集,需要具有相同的尺寸和深度;

int nimages:输入图像的数目;

const int *channels:用于计算反向投影的通道列表,具体范围参考官方文档;

cv::InputArray hist:输入的直方图数据,即上面所说的计算得到的直方图模型;

cv::OutputArray backProject:目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度;

const float **ranges:直方图中每个维度bin的取值范围(将bin理解为横坐标,则ranges为纵坐标);

double scale = (1.0):可选输出反向投影的比例因子;

bool uniform = true:直方图是否均匀分布的标识符,默认值true

2-2--代码实例

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

void Hist_And_Backprojection(int bins, void* hue1){
    float range[] = {0, 180};
    const float *histRanges = {range}; // 直方图数据纵坐标的范围
    cv::Mat h_hist; // 输出直方图数据

    cv::Mat hue = *(cv::Mat*)(hue1); // 这里传入的是H色调,所以计算的是色调的直方图
    cv::calcHist(&hue, 1, 0, cv::Mat(), h_hist, 1, &bins, &histRanges, true, false); // 计算直方图
    cv::normalize(h_hist, h_hist, 0, 255, cv::NORM_MINMAX, -1, cv::Mat()); // 归一化到0~255

    cv::Mat backPrjImage;
    cv::calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true);
    cv::imshow("output", backPrjImage);

    // 直方图分布图
    int hist_h = 600;
    int hist_w = 600;
    cv::Mat histImage(hist_w, hist_h, CV_8UC3, cv::Scalar(0, 0, 0));
    int bin_w = cvRound((double)hist_w / bins);
    for (size_t i = 0; i < bins; i++){
        cv::rectangle(histImage,  cv::Point(i*bin_w, hist_h),
        cv::Point((i + 1) * bin_w,  hist_h - cvRound(h_hist.at<float>(i)*hist_h / 255.0)), 
        cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
    }
    cv::imshow("Histogram", histImage);
}

int main(int argc, char** argv){
    
    int bins = 12; // 初始值
    cv::Mat src1, hsv, hue;

    src1 = cv::imread("C:/Users/Liujinfu/Desktop/opencv_bilibili/test1.jpg"); // 读取图片
    if (src1.empty()){
        printf("could not load image..\n");
        return -1;
    }
    cv::imshow("input", src1);

    cv::cvtColor(src1, hsv, cv::COLOR_BGR2HSV); // BRG -> HSV
    hue.create(hsv.size(), hsv.depth()); // HSV H表示色调、S表示饱和度、V表示明暗度
    int nchannels[] = {0, 0};
    cv::mixChannels(&hsv, 1, &hue, 1, nchannels, 1); // 将一副图像的一个通道 复制到 另一幅图像的另一个通道

    // 创建 Trackbar,回调函数为 Hist_And_Backprojection
    cv::createTrackbar("Histogram Bins: ", "input", &bins, 180, Hist_And_Backprojection, &hue); 
    Hist_And_Backprojection(bins, &hue);
        
    cv::waitKey(0);
    return 0;
}

2-3--代码分析

① 上述代码计算了 H(色调)的直方图,并基于 色调的直方图特征 计算原图像的反向投影,将色调的特征反映到原图像中;

② 上述代码调用cv::createTrackbar()的方式与常规方式不同,常规方式往往会使用全局变量,不传入参数,而上面的代码传入了两个参数,避免定义全局变量;

③ 上述代码使用了一个 cv::mixChannels() 函数,用于将一副图像的一个通道复制到另一幅图像的另一个通道上;以下展示 cv::mixChannels() 的具体用法:

//void cv::mixChannels(const cv::Mat *src, size_t nsrcs, cv::Mat *dst, size_t ndsts, const int *fromTo, size_t npairs)
cv::mixChannels(&hsv, 1, &hue, 1, nchannels, 1); 

const cv::Mat *src:输入图片或图片集(即被复制的图片);

size_t nsrcs:输入图片的数目;

cv::Mat *dst:输出图片或图片集(即复制的目的图片)

size_t ndsts:输出图片的数目;

const int *fromTo:复制的索引,假设输入图片为三通道图像src1,其对应的通道为 src1[0] = 0, src1[1] = 1, src1[2] = 2; 输出图片为两个三通道图像dst1和dst2,则其对应的通道为 dst1[0] = 0, dst[1] = 1, dst1[2] = 2, dst2[0] = 3, dst2[1] = 4, dst2[2] = 5;当需要把src1的第一个通道复制到dst1的第二个通道,src1的第一个通道复制到dst2的第三个通道,则索引对需要设置为 {0, 1, 1, 5};

size_t npairs:索引对的数量,例如上面的复制索引 {0, 1, 1, 5},其索引对数目为 2;

3--参考

C++ opencv之直方图反向投影(calcBackProject)

opencv —— mixChannels 通道复制

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
反向投影是一种用于图像分割的技术,它可以将图像中某个特定区域中的像素值与整个图像中的像素值进行比较,从而实现对该区域的分离。OpenCV中提供了多通道直方图算法来实现反向投影,以下是一些示例代码: ```c++ #include <opencv2/opencv.hpp> using namespace cv; int main() { Mat image, hsv; image = imread("image.jpg"); // 转换为HSV格式 cvtColor(image, hsv, COLOR_BGR2HSV); // 设置H、S通道的范围 float h_ranges[] = { 0, 180 }; float s_ranges[] = { 0, 256 }; const float* ranges[] = { h_ranges, s_ranges }; // 设置H、S通道的数量 int h_bins = 16, s_bins = 16; int hist_sizes[] = { h_bins, s_bins }; // 计算图像的直方图 MatND hist; int channels[] = { 0, 1 }; calcHist(&hsv, 1, channels, Mat(), hist, 2, hist_sizes, ranges, true, false); // 归一化直方图 normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat()); // 反向投影 Mat dst; calcBackProject(&hsv, 1, channels, hist, dst, ranges, 1, true); // 显示结果 imshow("image", image); imshow("back projection", dst); waitKey(0); return 0; } ``` 在这个示例中,我们首先将图像转换为HSV格式,然后计算出H、S通道的直方图,并将其归一化。接下来,我们使用`calcBackProject`函数来计算反向投影图像,并将结果显示出来。 注意,我们在调用`calcHist`和`calcBackProject`函数时,都需要指定通道数量和通道范围。在本例中,我们使用了两个通道(H、S),并将H通道的范围设置为0到180,S通道的范围设置为0到256。我们还指定了16个bin用于计算直方图,这个值可以根据实际需要进行调整。 希望这些代码可以对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值