第7章 直方图与匹配

直方图的基本数据结构

简单的说,直方图就是对数据进行统计,将统计值组织到一系列事先定义好的bin中。bin中的数值是从数据中计算出的特征的统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。无论如何,直方图获得的是数据分布的统计图。通常直方图的维度要低于原始数据。

  • 直方图数据结构的定义:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 直方图数据结构
    typedef struct CvHistogram
    {
    int type;
    CvArr* bins;
    float thresh[CV_MAX_DIM][2];
    float** thresh2;
    CvMatND mat;
    }
    CvHistogram;
  • 创建新的直方图:

    1
    2
    // 创建直方图
    cvHistogram* cvCreateHist(int dims, int* sizes, int type, float** ranges=NULL, int uniform=1);
  • 指定直方图的ranges值:

    1
    2
    // 指定ranges值
    void cvSetHistBinRanges(CvHistogram* hist, float** ranges, int uniform=1);
  • 根据已给出数据创建直方图:

    1
    CvHistogram* cvMakeHistHeaderForArray(int dims, int* sizes, CvHistogram* hist, float* data, float** ranges=NULL, int uniform=1);

访问直方图

1
2
3
4
5
6
7
8
9
// 访问直方图数据的函数
double cvQueryHistValue_1D(CvHistogram* hist, int idx0);
double cvQueryHistValue_2D(CvHistogram* hist, int idx0, int idx1);
double cvQueryHistValue_3D(CvHistogram* hist, int idx0, int idx1, int idx2);
double cvQueryHistValue_nD(CvHistogram* hist, int* idxN);
float* cvGetHistValue_1D(CvHistogram* hist, int idx0);
float* cvGetHistValue_2D(CvHistogram* hist, int idx0, int idx1);
float* cvGetHistValue_3D(CvHistogram* hist, int idx0, int idx1, idx2);
float* cvGetHistValue_nD(CvHistogram* hist, int idxN);

直方图的基本操作

  • 直方图归一化

    1
    2
    // 归一化
    cvNormalizeHist(CvHistogram* hist, double factor);
  • 阈值处理

    1
    2
    // 阈值函数
    cvThreshHist(CvHistogram* hist, double factor);
  • 复制直方图

    1
    2
    // 复制函数
    void cvCopyHist(const CvHistogram* src, CvHistogram** dst);
  • 输出直方图的最小值和最大值

    1
    void cvGetMinMaxHistValue(const CvHistogram* hist, float* min_value, float* max_value, int* min_idx=NULL, int* max_idx=NULL);
  • 自动计算直方图

    1
    void cvCalcHist(IplImage** image, CvHistogram* hist, int accumulate=0, const CvArr* mask=NULL);
  • 对比两个直方图

    1
    2
    // 相似度对比
    double cvCompareHist(const CvHistogram* hist1, CvHistogram* hist2, int method);

其中method有四种选择,相关(method=CV_COMP_CORREL)、卡方(method=CV_COMP_CHISQR)、直方图相交(method=CV_COMP_INTERSECT)、Bhattacharyya距离(method=CV_COMP_BHATTACHARYYA)。

一些更复杂的策略

  • 陆地移动距离(EMD)
    陆地移动距离是一种度量准则,它实际上度量的是怎样将一个直方图的形状转变为另一个直方图的形状。

    1
    2
    // EMD函数
    float cvCalcEMD2(const CvArr* signature1, const CvArr* signature2, int distance_type, CvDistanceFunction distance_func=NULL, const CvArr* cost_matrix=NULL, CvArr* flow=NULL, float* lower_bound=NULL, void* userdata=NULL);
  • 反向投影
    反向投影是一种记录像素点或像素块如何适应直方图模型中分布的方式。例如,我们有一个颜色直方图,可以利用反向投影在图像中找到该区域。

    1
    2
    3
    4
    // 基于像素点的反向投影函数
    void cvCalcBackProject(IplImage** image, CvArr* back_project, const CvHistogram* hist);
    // 基于块的反向投影函数
    void cvCalcBackProjectPatch(IplImage** images, CvArr* dst, CvSize patch_size, CvHistogram* hist, int method, float factor);
  • 模板匹配
    模板匹配不是基于直方图的,是通过在输入图像上滑动图像块对实际的图像块和输入图像进行匹配。

    1
    2
    // 模板匹配函数
    void cvMatchTemplate(const CvArr* image, const CvArr* temp1, CvArr* result, int method);

其中method有三种可选择方法,平方差匹配法(method=CV_TM_SQDIFF)、相关匹配法(method=CV_TM_CCORR)、相关匹配法(method=CV_TM_CCOEFF)。