OpenCV中直方图反向投影算法详解与实现

共 4467字,需浏览 9分钟

 ·

2021-05-30 01:48

点击上方小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

本文转自:opencv学堂

一:直方图交叉

OpenCV中直方图反向投影算法实现来自一篇论文《Indexing Via Color Histograms》其作者有两位、是Michael.J.Swain与Dana H. Ballard。论文分为两个部分,前面一部分详细描述了颜色直方图以及通过颜色直方图交叉来实现对象鉴别。可以实现对象背景区分、复杂场景中查找对象、不同光照条件影响等。假设M表示模型直方图数据、I表示图像直方图数据、直方图交叉匹配可以被描述为如下:

其中J表示直方图的范围,即bin的个数。最终得到结果是表示多少个模型颜色像素与图像中的像素相同或者相似,值越大,表示越相似。归一化表示如下:

这种方法对背景像素变换可以保持稳定性、同时对尺度变换也有一定抗干扰作用,但是无法做到尺度不变性特征。基于上述理论,两位作者发现通过该方法可以定位图像中已知物体的位置,它们把这个方法叫做直方图反向投影(Back Projection)。

二:直方图反向投影


直方图反向投影可以通过如下步骤完成

  1. 对每个直方图BIN J

  2. 对图像的每个像素点I(x,y)根据像素值获得对应的直方图分布概率

  3. 对得到分布概率图像做卷积

  4. 求取局部最大值,即得到已知物体位置信息


正是因为直方图反向投影有这样能力,所以在经典的MeanShift与CAMeanShift跟踪算法中一直是通过直方图反向投影来实现已知对象物体的定位。


三:基于OpenCV算法代码实现 


算法实现基于OpenCV的数据结构Mat来实现数据转换与存储,其它的地方基本都是自己写,上次有同学说我的代码都是Java的,这次全部改为C++啦,所以请大家继续关注本公众号!

第一步:直方图计算

OpenCV自己实现通过对直方图插值实现LUT查找,不做RGB颜色降维,本人的实现反其道而行之,对图像颜色做降维得到直方图,不再对直方图计算使用LUT插值查找。

  1. void calculate_histogram(Mat &image, Mat &hist) {

  2.    int width = image.cols;

  3.    int height = image.rows;

  4.    int r = 0, g = 0, b = 0;

  5.    int index = 0;

  6.    int level = 256 / bins;

  7.    for (int row = 0; row < height; row++) {

  8.        uchar* current = image.ptr<uchar>(row);

  9.        for (int col = 0; col < width; col++) {

  10.            if (image.channels() == 3) {

  11.                b = *current++;

  12.                g = *current++;

  13.                r = *current++;

  14.                index = (r / level) + (g / level)*bins + (b / level)*bins*bins;

  15.            }

  16.            if (image.channels() == 1) {

  17.                r = *current++;

  18.                index = (r / level);

  19.            }

  20.            hist.at<int>(index, 0)++;

  21.        }

  22.    }

  23. }

计算输入图像与模型的直方图代码如下

  1. Mat mHist = Mat::zeros(total, 1, CV_32SC1);

  2. Mat iHist = Mat::zeros(total, 1, CV_32SC1);

  3. calculate_histogram(model, mHist);

  4. calculate_histogram(src, iHist);

第二步:计算R

  1. Mat rhist = Mat::zeros(total, 1, CV_32FC1);

  2. float m = 0, t = 0;

  3. for (int i = 0; i < total; i++) {

  4.    m = mHist.at<int>(i, 0);

  5.    t = iHist.at<int>(i, 0);

  6.    rhist.at<float>(i, 0) = m / t;

  7. }

第三步:计算概率分布图像

  1. // 查找权重概率分布

  2. int r = 0, g = 0, b = 0;

  3. int level = 256 / bins;

  4. int index = 0;

  5. Mat w = Mat::zeros(src.size(), CV_32FC1);

  6. for (int row = 0; row < src.rows; row++) {

  7.    uchar* current = src.ptr<uchar>(row);

  8.    for (int col = 0; col < src.cols; col++) {

  9.        if (src.channels() == 3) {

  10.            b = *current++;

  11.            g = *current++;

  12.            r = *current++;

  13.            index = (r / level) + (g / level)*bins + (b / level)*bins*bins;

  14.            w.at<float>(row, col) = rhist.at<float>(index, 0);

  15.        } else {

  16.            r = *current++;

  17.            index = (r / level);

  18.            w.at<float>(row, col) = rhist.at<float>(index, 0);

  19.        }

  20.    }

  21. }

第四步:卷积计算

  1. Mat dst;

  2. Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1,

  3.    1, 1, 1,

  4.    1, 1, 1);

  5. filter2D(w, dst, -1, kernel);

第五步:归一化与显示反向投影结果

  1. Mat result;

  2. normalize(dst, result, 0, 255, NORM_MINMAX);

  3. imshow("BackProjection Demo", result);



四:运行演示

已知目标图像


反向投影结果



下载1:OpenCV-Contrib扩展模块中文版教程
在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲
小白学视觉公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲
小白学视觉公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群


欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~


浏览 25
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报