互联网@时事传播散文读书

【图像处理】OpenCV系列三十三--- 直方图与反向投影详解

2019-05-16  本文已影响66人  307656af5a04

一、直方图(calcHist)

1、函数原型

// 原型一
void calcHist(const Mat *images,
    int nimages,
    const int *channels,
    InputArray mask,
    OutputArray hist,
    int dims,
    const int *histSize,
    const float **ranges,
    bool uniform = true,
    bool accumulate = false)

// 原型二
void calcHist(const Mat *images,
    int nimages,
    const int *channels,
    InputArray mask,
    SparseMat &hist,
    int dims,
    const int *histSize,
    const float **ranges,
    bool uniform = true,
    bool accumulate = false)    

// 原型三
void calcHist(InputArrayOfArrays images,
    const std::vector<int> &channels,
    InputArray mask,
    OutputArray hist,
    const std::vector<int> &histSize,
    const std::vector<float> &ranges,
    bool accumulate = false)    

2、函数功能
计算一幅或多幅图像的直方图,在元组中增量一个直方图的时候,就是从输入图像组中的原位置提取一幅图像,并计算出它的直方图,并添加到元组中。

当参数dims>1时,输出矩阵Hist是二维矩阵;

3、参数详解

二、归一化处理(normalize)

1、函数原型

// 原型一
void normalize(InputArray src,
    InputOutputArray dst,
    double alpha = 1,
    double beta = 0,
    int norm_type = NORM_L2,
    int dtype = -1,
    InputArray mask = noArray())    

// 原型二
void normalize(const SparseMat &src,
    SparseMat &dst,
    double alpha,
    int normType)   

2、函数功能
归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内;

3、参数详解

可以有以下的取值:
(1) NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用;
(2) NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值) ;

具体公式

(3) NORM_L1 : 归一化数组的L1-范数(绝对值的和);

具体公式

(4) NORM_L2: 归一化数组的(欧几里德)L2-范数;

具体公式

(5) NORM_L2SQR

具体公式

三、方向投影(calcBackProject)

1、反向投影

反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式;

简单的讲, 所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征;

反向投影在某一位置的值就是原图对应位置像素值在原图像中的总数目;

例如, 你有一个肤色直方图 ,你可以用它来寻找图像中的肤色区域;

2、反向投影原理

(1) 例如一幅灰度图像如下:

                  Image=

                  0    1    2    3
                  4    5    6    7
                  8    9   10   11
                  8    9   14   15

(2) 该灰度图的直方图为(bin指定的区间为[0,3),[4,7),[8,11),[12,16))

 Histogram =  4    4    6    2

(3)反向投影图

            Back_Projection=

                  4    4    4    4
                  4    4    4    4
                  6    6    6    6
                  6    6    2    2

例如位置(0,0)上的像素值为0,对应的bin为[0,3),所以反向投影在该位置上的值为直方图上对应区域的值为4;

3、函数原型

// 原型一
void calcBackProject(const Mat *images,
    int nimages,
    const int *channels,
    InputArray hist,
    OutputArray backProject,
    const float **ranges,
    double scale = 1,
    bool uniform = true )

// 原型二
void calcBackProject(const Mat *images,
    int nimages,
    const int *channels,
    const SparseMat &hist,
    OutputArray backProject,
    const float **ranges,
    double scale = 1,
    bool uniform = true)    

// 原型三
void calcBackProject(InputArrayOfArrays images,
    const std::vector<int> &channels,
    InputArray hist,
    OutputArray dst,
    const std::vector<float> &ranges,
    double scale)

4、函数功能
计算直方图的反向投影;与calculHist函数类似,在每个(x,y)位置,函数从输入图像中的选定通道收集值,并找到相应的直方图bin;但是,函数不是递增它,而是读取bin值,按比例缩放,并存储在backProject(x,y)中;

在统计方面,该函数根据直方图所表示的经验概率分布计算每个元素值的概率;

例如,请参见如何在场景中查找和跟踪亮度好的对象;

(1) 对测试图像中的每个像素 p(i,j),获取色调数据并找到该色调在直方图中的bin位置 ;

(2) 查询模型直方图中对应的bin,并读取该bin的数值;

(3) 将此数值存储在新的图像中(BackProjection);也可以先归一化模型直方图,这样测试图像的输出就可以在屏幕上显示了;

(4) 使用统计学的语言,BackProjection中存储的数值代表了测试图像中该像素属于对象的概率;

(5) 亮的区域是对象的可能性更大,而暗的区域则表示更低的可能性;

5、参数详解

三、综合实例

1、实验实例

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

//定义全局变量
Mat srcImage, hsvImage,hueImage;

const int hueBinMaxValue = 180;

int hueBinValue=25;

// 声明回调函数
void Hist_and_Backprojection(int, void*);

int main()
{
    // 载入图像
    srcImage=imread("Back_Projection.jpg");

    //判断图像是否加载成功
    if(srcImage.empty())
    {
        cout << "图像加载失败" << endl;
        return -1;
    }
    else
        cout << "图像加载成功..." << endl << endl;

    //将图像转化为HSV图像
    cvtColor(srcImage, hsvImage, CV_BGR2HSV);

    //只使用图像的H参数
    hueImage.create(hsvImage.size(), hsvImage.depth());
    
    int ch[]={0,0};
    
    mixChannels(&hsvImage, 1, &hueImage, 1, ch, 1);

    //轨迹条参数设置
    char trackBarName[20];
    sprintf(trackBarName,"Hue bin:%d",hueBinMaxValue);
    
    namedWindow("SourceImage",WINDOW_AUTOSIZE);

    //创建轨迹条并调用回调函数
    createTrackbar(trackBarName, "SourceImage", &hueBinValue, hueBinMaxValue, Hist_and_Backprojection);
    
    // 直方图与反向投影回调函数
    Hist_and_Backprojection(hueBinValue, 0);

    // 显示原图像
    imshow("SourceImage", srcImage);

    waitKey(0);
    return 0;
}

void Hist_and_Backprojection(int, void*)
{
    // 直方图
    MatND hist;
    
    int histsize=MAX(hueBinValue, 2);
    
    // 直方图的范围
    float hue_range[]={0,180};  
    
    const float* ranges={hue_range};

    // 计算图像直方图并归一化处理
    calcHist(&hueImage, 1, 0, Mat(), hist, 1, &histsize, &ranges, true, false);
    
    // 对计算的直方图进行归一化处理
    normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());

    // 获取反向投影
    MatND backProjection;
    
    // 计算反向投影
    calcBackProject(&hueImage, 1, 0, hist, backProjection, &ranges, 1, true);

    // 显示反向投影图像
    imshow("BackProjection", backProjection);

    //绘制图像直方图
    int w=400;
    int h=400;
    
    // 直方图分为多少段
    int bin_w = cvRound((double)w/histsize);
    
    // 创建直方图图像400 x 400
    Mat histImage = Mat::zeros(w, h, CV_8UC3);
    
    // 绘制直方图
    for(int i=0; i < hueBinValue; i++)
    {
        rectangle(histImage, Point(i*bin_w, h), Point((i+1)*bin_w, h-cvRound(hist.at<float>(i)*h/255.0)), Scalar(0,0,255), -1);
    }
    
    // 显示直方图图像
    imshow("HistImage", histImage);
}

2、实验结果

原图 直方图 反向投影

我是奕双,现在已经毕业将近两年了,从大学开始学编程,期间学习了C语言编程,C++语言编程,Win32编程,MFC编程,毕业之后进入一家图像处理相关领域的公司,掌握了用OpenCV对图像进行处理,如果大家对相关领域感兴趣的话,可以关注我,我这边会为大家进行解答哦!如果大家需要相关学习资料的话,可以私聊我哦!

上一篇下一篇

猜你喜欢

热点阅读