菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
301
0

OpenCV开发笔记(五十七):红胖子8分钟带你深入了解直方图反向投影(图文并茂+浅显易懂+程序源码)

原创
05/13 14:22
阅读数 57480
 

前言

  红胖子,来也 !
  做了部分人脸识别后,又回到直方图相关的研究-直方图方向投影。

 

Demo

  在这里插入图片描述
  在这里插入图片描述
  在这里插入图片描述
  在这里插入图片描述
  在这里插入图片描述

 

直方图

 

直方图反向投影

概述

  反向投影是计算像素和直方图模型中像素吻合度的一种方法。
  通俗来说,就是用已知一个对象的直方图模型去目标图像中寻找是否有相似的对象。例如,如果有肤色的直方图,可以使用反向投影来在图像中寻找肤色区域。
  有一点需要注意,反向投影中一般使用HSV色彩空间,使用HS两个通道直方图模型去进行匹配计算。

关于HSV颜色空间

  HSV是一种将RGB色彩空间中的点在倒圆锥体中的表示方法。HSV即色相(Hue)、饱和度(Saturation)、明度(Value),又称HSB(B即Brightness)。色相是色彩的基本属性,就是平常说的颜色的名称,如红色、黄色等。饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。明度(V),取0-max(计算机中HSV取值范围和存储的长度有关)。HSV颜色空间可以用一个圆锥空间模型来描述。

  • 圆锥的顶点处,V=0,H和S无定义,代表黑色;
  • 圆锥的顶面中心处V=max,S=0,H无定义,代表白色;
    在这里插入图片描述

反向投影原理

  • 步骤一:先将已知的图片进行颜色空间转换为HSV颜色空间;
  • 步骤二:对H通道进行单元划分起二维空间上计算对应直方图;
  • 步骤三:计算直方图空间上的最大值,并进行归一化绘制响应的直方图信息;
  • 步骤四:计算反向投影图像;

计算反向投影函数原型

/** @overload */
void calcBackProject( const Mat* images,
                   int nimages,
                   const int* channels,
                   const SparseMat& hist,
                   OutputArray backProject,
                   const float** ranges,
                   double scale = 1,
                   bool uniform = true );
/** @overload */
void calcBackProject( InputArrayOfArrays images,
                   const std::vector<int>& channels,
                   InputArray hist,
                   OutputArray dst,
                   const std::vector<float>& ranges,
                   double scale );
void calcBackProject( const Mat* images,
                   int nimages,
                   const int* channels,
                   InputArray hist,
                   OutputArray backProject,
                   const float** ranges,
                   double scale = 1,
                   bool uniform = true );
  • 参数一:const Mat*类型的images,输入的数组(或数组集),它们须为相同的深度(CV_8U或CV_32F)和相同的尺寸,而通道数则可以任意;
  • 参数二:int类型的nimages,输入数组的个数,也就是第一个参数中存放了多少张image;
  • 参数三:const int*类型的channels,需要统计的通道(dim)索引。第一个数组通道从0到images[0].channels()-1,而第二个数组通道从images[0].channels()到images[0].channels()+images[1].channels()–1;
  • 参数四:InputArray类型的hist,输入的直方图;
  • 参数五:OutputArray类型的backProject,目标反向投影阵列,其须为单通道,并且和image[0]有相同的大小和深度;
  • 参数六:const float**类型的ranges,表示每一个维度数组(第六个参数dims)的每一维的边界阵列,可以理解为每一维数值的取值范围;
  • 参数七:double类型的scale,有默认值1,输出的方向投影可选的缩放因子;
  • 参数八:bool类型的uniform,指示直方图是否均匀的标识符,有默认值true;
 

Demo源码

void OpenCVManager::testCalcBackProject()
{
    QString fileName1 =
            "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/19.jpg";
    cv::Mat srcMat = cv::imread(fileName1.toStdString());
    cv::Mat dstMat;
    int width = 400;
    int height = 300;

    cv::resize(srcMat, srcMat, cv::Size(width, height));

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);

    cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2,
                                         srcMat.rows * 2),
                                srcMat.type());

    cv::Mat allMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type());
    allMat = cv::Scalar(0, 0, 0);

    int bins = 255;
    while(true)
    {
        // 刷新全图黑色
        windowMat = cv::Scalar(0, 0, 0);

        // 原图复制
        cv::Mat mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                                cv::Range(srcMat.cols * 0, srcMat.cols * 1));
        cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);

        {
            // 步骤一:先将已知的图片进行颜色空间转换为HSV颜色空间;
            cv::Mat hsvMat;
            cv::cvtColor(srcMat, hsvMat, cv::COLOR_BGR2HSV);
            // 步骤二:对H和S通道进行分离,计算H上的直方图;
            cv::Mat hueMat;
            hueMat.create(hsvMat.size(), hsvMat.depth());
            int channel[] = {0, 0};
            cv::mixChannels(&hsvMat, 1, &hueMat, 1, channel, 1);
            // 步骤三:计算直方图空间上的最大值,并进行归一化绘制响应的直方图信息;
            // 调整bins值2~255
            cvui::printf(windowMat, 75 + width * 1, 20 + height * 0, "thresh");
            cvui::trackbar(windowMat, 75 + width * 1, 40 + height * 0, 165, &bins, 2, 255);
            cv::MatND hueHistMat;
            int histSize = MAX(bins, 2);
            float hueRange[] = {0, 180};
            const float *ranges = {hueRange};
            cv::calcHist(&hueMat, 1, 0, cv::Mat(), hueHistMat, 1, &histSize, &ranges, true, false);
            cv::normalize(hueHistMat, hueHistMat, 0, 255, cv::NORM_MINMAX, -1, cv::Mat());
            // 步骤四:计算反向投影图像
            cv::MatND backprojectMat;
            cv::calcBackProject(&hueMat, 1, 0, hueHistMat, backprojectMat, &ranges, 1, true);

            // copy显示
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::cvtColor(backprojectMat, dstMat, cv::COLOR_GRAY2BGR);
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);

            // 对直方图进行均衡化
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::equalizeHist(backprojectMat, dstMat);
            cv::cvtColor(dstMat, dstMat, cv::COLOR_GRAY2BGR);
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }

        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc键退出
        if(cv::waitKey(25) == 27)
        {
            break;
        }
    }
}  
 

工程模板:对应版本号v1.51.0

  对应版本号v1.51.0

 
 

发表评论

0/200
301 点赞
0 评论
收藏
为你推荐 换一批