OpenCV25---直方图反向投影

二十五、直方图反向投影

1、反向投影(Back Projection)

  • 反向投影是反映直方图在目标图像中的分布情况
  • 简单点说就是用直方图模型去目标图像中寻找是存在否相似的对象。通常用HSV色彩空间的HS两个通道直方图模型。
  • 具体操作是先得到一张图像的直方图信息,然后遍历原图像的每一个像素,如果这个像素值在直方图的某个bin下,就用这个bin出现的频次去代替这个像素值。这样划分了多少个bin,新生成的图像就有多少个像素值种类(而不是原来的0-255的256个种类)。比如说将0-256分成16份(16个bin),计算直方图得到原图像(0,0)位置处的像素值为250,落在了第16个bin下,而原图像直方图在这个bin下的值(频次)为56(经过归一化),则反向投影图像中(0,0)位置处的像素值为56。
  • 用处举例:从某张图像中找出相似对象。假如拍摄的两张图片都含有同一目标物体(如两只手的图像)。可以用其中一张图像提取出的直方图信息,去遍历另一张图片的像素,若遍历到目标像素值,则它可以被替换为第一张图片出现该像素值的个数,如果这张图片中含有相同目标,会被显示出来。
    例如用第一张图片的直方图信息去遍历第二张图片生成反投影信息:(左侧为原图,右侧为测试图)

在这里插入图片描述

输出结果:
在这里插入图片描述

2、步骤

3、相关API

  • 加载图片imread
  • 将图像从RGB空间转换到HSV色彩空间cvtColor
    因为BGR直方图我们只能三个通道分别计算,计算后也没法合在一起,也就是不能把图片作为一个整体来比较,而H-S就可以将图片作一个整体对比,所以这里用H-S直方图来作对比。
  • 计算直方图并归一化calcHistnormlize
  • MatMatND,其中Mat表示二维数组,MatND表示三维或者多维数组,此处均可以用Mat表示
  • 计算反向投影图像calcBackProject
calcBackProject(
const Mat* images,//输入图像的指针,可以传入多张图像
int nimages,//输入图像的数量 
const int* channels,//用于计算反向投影的通道列表,通道数必须与直方图维度相匹配
InputArray hist,//输入的直方图
OutputArray backProject,//目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度 
const float ranges**//直方图中每个维度bin的取值范围 
double scale=1//可选输出反向投影的比例因子
bool uniform=true//直方图是否均匀分布(uniform)的标识符,有默认值true 
)

示例代码:(直方图反向投影与绘制)

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;

Mat src; Mat hsv; Mat hue;
int bins = 12;
void Hist_And_Projection(int, void*);

int main(int argc, char* argv) {
    src = imread("添加图片路径");
    if (src.empty()) {
  	cout << "could not load image..." << endl;
  	return -1;
    }
    const char* window_image = "input image";
    namedWindow(window_image, WINDOW_AUTOSIZE);
    namedWindow("BackPro", WINDOW_AUTOSIZE);
    namedWindow("Histogram", WINDOW_AUTOSIZE);
    
    cvtColor(src, hsv, COLOR_BGR2HSV);
    hue.create(hsv.size(), hsv.depth());//创建一个hue图像,尺寸深度和hsv相同
    int nchannels[] = { 0,0 };//映射关系
    mixChannels(&hsv, 1, &hue, 1, nchannels, 1); //mixChannels主要就是把输入的矩阵(或矩阵数组)(hsv)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)(hue)的某些通道中,其中的对应关系就由fromTo参数(nchannels)指定.
    //把hsv中的一个通道0矩阵输出给hue的一个通道0矩阵,通过nchannels映射关系,即0通道的映射
    
    createTrackbar("Histogram Bins:", window_image, &bins , 180, Hist_And_Projection);//控制bin的划分
    Hist_And_Projection(0, 0);
    
    imshow(window_image, src); 
    waitKey(0);
    return 0;
}

void Hist_And_Projection(int, void*) {
    //计算直方图与归一化
    float range[] = { 0, 180 };
    const float *histRanges = { range };
    Mat h_hist;
    calcHist(&hue, 1, 0, Mat(), h_hist,1, &bins, &histRanges, true, false);
    normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());//出现的频次应在0-255之间,因为要用这个频次做为反投影图像的像素值
    //反向投影
    Mat backProjectimage;
    calcBackProject(&hue, 1, 0, h_hist, backProjectimage, &histRanges, 1, true);
    imshow("BackPro", backProjectimage);
    //绘制直方图
    int hist_h = 400;
    int hist_w = 400;
    Mat hist_image(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));//创建一张直方图图像
    int bin_w = (hist_w) / bins;//直方图bin的宽度
    for (int i = 1; i <= bins; i++) {
  	rectangle(hist_image, 
   	Point((i - 1)*bin_w, hist_h - h_hist.at<float>(i - 1) / 255 * 400), //矩形框的第一个点,直方图的左上角顶点。因为之前将其归一化到0-255之间,而整张图片的高度为400,所以y的值最后要在图像的尺度下表示
   	Point(i*bin_w, hist_h), //矩形框的第二个点,直方图的右下角顶点
   	Scalar(0, 0, 255), -1);  
    }  
    imshow("Histogram", hist_image);
    return;
}

输出图像效果:

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值