opencv利用cvCalcHist获得手的肤色直方图的比较汇总

116 篇文章 2 订阅
39 篇文章 3 订阅


1)cvNormalizeHist:直方图归一化

cvNormalizeHist(CvHistogram *  hist,  double  factor);

hist:表示直方图

factor:表示直方图归一化以后的数值(通常情况下设置为1)。这里它是一个double类型的数据,尽管函数CvHistogram 的内部数据类型通常都是float类型。


2)cvThreshHist:直方图阀值化

cvThreshHist(CvHistogram *  hist, double  factor);

hist:表示直方图

factor:是一个开关阀值。进行直方图阀值化处理之后,小于给定阀值的各个bin的值都被设为0。


3)cvCopyHist:复制直方图

void  cvCopyHist(const  CvHistogram *  src,  CvHistogram  * * dst);

将一个直方图的信息复制到另一个直方图中。

第二个参数是指向直方图的指针的指针。


4)cvGetMinMaxHistValue:输出直方图中找到的最大值和最小值

void  cvGetMinMaxHistValue(const  CvHistogram *  hist,  float  *  min_value,  float *  max_value,

int  *  min_idx = NULL,  int  *  max_idx = NULL);

hist 
直方图 
min_value 
直方图最小值的指针 
max_value 
直方图最大值的指针 
min_idx 
数组中最小坐标的指针 
max_idx 
数组中最大坐标的指针 
函数 cvGetMinMaxHistValue 发现最大和最小直方块以及它们的位置。任何输出变量都是可选的。在具有同样值几个极值中,返回具有最小下标索引(以字母排列顺序定)的那一个。 


5)cvCalcHist:计算图像image(s)像素点 的直方图 

void cvCalcHist( IplImage** image, CvHistogram* hist,
                 int accumulate=0, const CvArr* mask=NULL );
image 
输入图像s (虽然也可以使用 CvMat** ),这允许利用多个图像通道,对于多通道图像(如HSV或RGB),在调用函数cvCalcHist之前,先要用函数cvSplit()将图像分为单通道的。
hist 
直方图指针 
accumulate 
累计标识。如果设置非0,则表示直方图在开始时没有被清零。注意,变量accumulate 允许cvCalcHist在一个数据采集循环中被多次调用这个特征保证可以为多个图像计算一个单独的直方图,或者在线更新直方图。 
mask 
操作 mask, 确定输入图像的哪个象素被计数 
函数 cvCalcHist 计算单通道或多通道图像的直方图。 用来增加直方块的数组元素可从相应输入图像的同样位置提取。


6)cvCompareHist:比较两个直方图的相似度

double  cvCompareHist(const  CvHistogram *  hist1,

const  CvHistogram *  hist2,  int  method);


前两个参数是要比较的大小相同的直方图,第三个参数是所选择的距离标准。

method有CV_COMP_CORREL(相关), CV_COMP_CHISQR(卡方),
CV_COMP_INTERSECT(直方图相交),CV_COMP_BHATTACHARYYA(距离)
四种方法,对应公式如下:
7)cvCvtPixToPlane:分割多通道数组成几个单通道数组或者从数组中提取一个通道

可以看作cvSplit是他的宏:

  #define cvCvtPixToPlane cvSplit
  void cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,

CvArr* dst2, CvArr* dst3 );

一般用法是cvCvtPixToPlane(IplImage * src,IplImage * dst1,IplImage *dst2,IplImage * dst3,IplImage *dst4)
  第一个参数是源图像,后面是分离出来每个通道的目标图像,如果原图像是3通道的,可以把最后一个参数设置为空。例如cvCvtPixToPlane(IplImage * src,IplImage * dst1,IplImage *dst2,IplImage * dst3,NULL),NULL也可以写为0.

代码:

#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <opencv2/legacy/legacy.hpp>
using namespace cv;
using namespace std;

CvHistogram * Create3DHistogram(const int dims, int bins);
void CreateSingleImage(IplImage * image_Src, IplImage **image_r, IplImage **image_g, IplImage **image_b);
void DrawHistogram(IplImage ** image_hist, const CvHistogram * histogram, int scaleValue);

int main()
{
    const char * soutceFile_InDoor = "D:\\VC98\\C++项目\\opencv\\page244.2_\\page244.2_\\hand2.jpg";
    const char * soutceFile_OutDoor = "D:\\VC98\\C++项目\\opencv\\page244.2_\\page244.2_\\hand3.jpg";
    const char * soutceFile_OutDoorSun = "D:\\VC98\\C++项目\\opencv\\page244.2_\\page244.2_\\hand4.jpg";

    IplImage * image_Source_Indoor = cvLoadImage(soutceFile_InDoor, CV_LOAD_IMAGE_UNCHANGED);
    assert(image_Source_Indoor);
    IplImage * image_Source_Outdoor = cvLoadImage(soutceFile_OutDoor, CV_LOAD_IMAGE_UNCHANGED);
    assert(image_Source_Outdoor);
    IplImage * image_Source_OutdoorSun = cvLoadImage(soutceFile_OutDoorSun, CV_LOAD_IMAGE_UNCHANGED);
    assert(image_Source_OutdoorSun);

    IplImage * image_r;
    IplImage * image_g;
    IplImage * image_b;
    CvHistogram * histgram_3D_InDoor;
    CvHistogram * histgram_3D_OutDoor;
    CvHistogram * histgram_3D_OutDoorSun;

    double histCompare;
    const int dims = 3;//3维
    int bin_N[] = { 2, 8, 16, 32, 256 };
    size_t length_bin_N = sizeof(bin_N) / sizeof(bin_N[0]);//typedef _W64 unsigned int   size_t;

    for (size_t i = 0; i < length_bin_N; ++i)
    {
        //室内直方图
        CreateSingleImage(image_Source_Indoor, &image_r, &image_g, &image_b);//创建一个3维直方图
//分割多通道数组成几个单通道数组或者从数组中提取一个通道
        cvCvtPixToPlane(image_Source_Indoor, image_r, image_g, image_b, NULL);
        IplImage *allImagePlane[3] = { image_r, image_g, image_b };//用一个数组来存放3个通道图像

        histgram_3D_InDoor = Create3DHistogram(dims, bin_N[i]);//创建一个3维直方图
        cvCalcHist(allImagePlane, histgram_3D_InDoor);//计算直方图的总像素点
        cvNormalizeHist(histgram_3D_InDoor, 1.0);//归一化
        cvReleaseImage(&image_r);
        cvReleaseImage(&image_g);
        cvReleaseImage(&image_b);

        //室外直方图
        CreateSingleImage(image_Source_Outdoor, &image_r, &image_g, &image_b);
        cvCvtPixToPlane(image_Source_Outdoor, image_r, image_g, image_b, NULL);
        allImagePlane[0] = image_r;
        allImagePlane[1] = image_g;
        allImagePlane[2] = image_b;

        histgram_3D_OutDoor = Create3DHistogram(dims, bin_N[i]);
        cvCalcHist(allImagePlane, histgram_3D_OutDoor);//计算直方图的总像素点
        cvNormalizeHist(histgram_3D_OutDoor, 1.0);//归一化直方图
        cvReleaseImage(&image_r);
        cvReleaseImage(&image_g);
        cvReleaseImage(&image_b);

        //室外阳光直方图
        CreateSingleImage(image_Source_OutdoorSun, &image_r, &image_g, &image_b);//这里复杂,要细看
//分割多通道数组成几个单通道数组或者从数组中提取一个通道
        cvCvtPixToPlane(image_Source_OutdoorSun, image_r, image_g, image_b, NULL);
        allImagePlane[0] = image_r;
        allImagePlane[1] = image_g;
        allImagePlane[2] = image_b;

        histgram_3D_OutDoorSun = Create3DHistogram(dims, bin_N[i]);
        cvCalcHist(allImagePlane, histgram_3D_OutDoorSun);
        cvNormalizeHist(histgram_3D_OutDoorSun, 1.0);

        cvReleaseImage(&image_r);
        cvReleaseImage(&image_g);
        cvReleaseImage(&image_b);
        if (bin_N[i] == 8)
        {
            cvNamedWindow("bin等于8时的室内直方图", CV_WINDOW_AUTOSIZE);
            cvNamedWindow("bin等于8时的室外直方图", CV_WINDOW_AUTOSIZE);
            cvNamedWindow("bin等于8时的室外阳光直方图", CV_WINDOW_AUTOSIZE);

            IplImage *histImage_Indoor;
            IplImage *histImage_Outdoor;
            IplImage *histImage_OutdoorSun;

            DrawHistogram(&histImage_Indoor, histgram_3D_InDoor, 1000);
            cvShowImage("bin等于8时的室内直方图", histImage_Indoor);
    cvSaveImage("result1.jpg",histImage_Indoor);
            cvReleaseImage(&histImage_Indoor);

            DrawHistogram(&histImage_Outdoor, histgram_3D_OutDoor, 1000);
            cvShowImage("bin等于8时的室外直方图", histImage_Outdoor);
    cvSaveImage("result2.jpg",histImage_Outdoor);
            cvReleaseImage(&histImage_Outdoor);

            DrawHistogram(&histImage_OutdoorSun, histgram_3D_OutDoorSun, 1000);
            cvShowImage("bin等于8时的室外阳光直方图", histImage_OutdoorSun);
    cvSaveImage("result3.jpg",histImage_OutdoorSun);
            cvReleaseImage(&histImage_OutdoorSun);
        }
            
        //输出匹配结果
        cout << "--  bin为"<<bin_N[i]<<"  --  " << endl;
        cout << "===============================================================================" << endl;

        cout << "CV_COMP_CORREL方法:数值越大越匹配,范围:完全匹配:1,完全不匹配:-1,无关联:0" << endl;
        cout << "-------------------------------------------------------------------------------" << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_CORREL);
        cout << "InDoor与OutDoor    :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_CORREL);
        cout << "InDoor与OutDoorSun :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_CORREL);
        cout << "OutDoor与OutDoorSun:" << histCompare << endl;
       cout << endl;

        cout << "CV_COMP_CHISQR方法:数值越小越匹配,范围:0到无穷大" << endl;
        cout << "-------------------------------------------------------------------------------" << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_CHISQR);
        cout << "InDoor与OutDoor    :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_CHISQR);
        cout << "InDoor与OutDoorSun :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_CHISQR);
        cout << "OutDoor与OutDoorSun:" << histCompare << endl;
        cout << endl;

        cout << "CV_COMP_INTERSECT方法:低分代表坏的匹配,范围:如果两个直方图都被归一化到1,则0~1" << endl;
        cout << "-------------------------------------------------------------------------------" << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_INTERSECT);
        cout << "InDoor与OutDoor    :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_INTERSECT);
        cout << "InDoor与OutDoorSun :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_INTERSECT);
        cout << "OutDoor与OutDoorSun:" << histCompare << endl;
        cout << endl;


        cout << "CV_COMP_BHATTACHARYYA方法:低分代表好的匹配,范围:0~1" << endl;
        cout << "-------------------------------------------------------------------------------" << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoor, CV_COMP_BHATTACHARYYA);
        cout << "InDoor与OutDoor    :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_InDoor, histgram_3D_OutDoorSun, CV_COMP_BHATTACHARYYA);
        cout << "InDoor与OutDoorSun :" << histCompare << endl;
        histCompare = cvCompareHist(histgram_3D_OutDoor, histgram_3D_OutDoorSun, CV_COMP_BHATTACHARYYA);
        cout << "OutDoor与OutDoorSun:" << histCompare << endl;

        cout << endl;
        cout << endl;
        cout << endl;
        cvReleaseHist(&histgram_3D_InDoor);
        cvReleaseHist(&histgram_3D_OutDoor);
        cvReleaseHist(&histgram_3D_OutDoorSun);
    }
    //system("pause");
    cvWaitKey();
    cvReleaseImage(&image_Source_Indoor);
    cvReleaseImage(&image_Source_Outdoor);
    cvReleaseImage(&image_Source_OutdoorSun);
    cvDestroyAllWindows();
    return 0;
}

CvHistogram * Create3DHistogram(const int dims, int bins)//创建一个3维直方图
{
    int hist_sizes[] = { bins, bins, bins };
    int hist_type = CV_HIST_ARRAY;
    float r_range[] = { 0, 255 };
    float g_range[] = { 0, 255 };
    float b_range[] = { 0, 255 };
    float *hist_ranges[] = { r_range, g_range, b_range };

    return cvCreateHist(dims, hist_sizes, hist_type, hist_ranges, 1);
}

void CreateSingleImage(IplImage * image_Src, IplImage **image_r, IplImage **image_g, IplImage **image_b)
{
    IplImage * image_temp = cvCreateImage(cvGetSize(image_Src), IPL_DEPTH_8U, 1);
    //image_r = &image_temp; 
    //如果用上面这行这种方式,编译通过,但运行崩溃,本函数结束后image_r便被释放,
    //因为image_temp只是一个指针变量,占用四个字节的局部变量,对它取地址即&image_temp只是这个局部指针变量的地址,函数结束后自然释放掉
    //但是,将使用下面这行:将image_temp指针变量所保存的地址赋值给“*image_r”,这个地址是从cvCreateImagere中turn出来的,自然不会随函数结束而释放
    *image_r = image_temp;

    *image_g = cvCloneImage(image_temp);
    *image_b = cvCloneImage(image_temp);
    cvZero(*image_r);
    cvZero(*image_g);
    cvZero(*image_b);
}
//目前只实现绘制三维直方图
void DrawHistogram(IplImage ** image_hist, const CvHistogram * histogram,int scaleValue)
{
    //直方图:横坐标表示各个bin,纵坐标表示各个bin归一化后的值
    int hist_dims = histogram->mat.dims;
    int bin_size1, bin_size2, bin_size3;
    if (hist_dims == 3)
    {
        bin_size1 = histogram->mat.dim[0].size;
        bin_size2 = histogram->mat.dim[1].size;
        bin_size3 = histogram->mat.dim[2].size;
    }
    else
    {
        return;
    }

    int bin_count = bin_size1*bin_size2*bin_size3;
    float max_temp;
    cvGetMinMaxHistValue(histogram, NULL, &max_temp);
    int max_value = (int)(max_temp*scaleValue) + 1;
    CvSize hist_imageSize = cvSize(bin_count, max_value);
    *image_hist = cvCreateImage(hist_imageSize, IPL_DEPTH_8U, 1);
    (*image_hist)->origin = 1;
    cvZero(*image_hist);

    int x;
    int value;
    for (int r = 0; r < bin_size1; ++r)
    {
        for (int g = 0; g < bin_size2; ++g)
        {
            for (int b = 0; b < bin_size3; ++b)
            {
                x = r*(bin_size1*bin_size2) + g*bin_size2 + b;
                value = (int)(cvQueryHistValue_3D(histogram, r, g, b)*scaleValue);
        /*        if (value == 0)
                {
                    value = 10;
                }*/
                cvRectangle(*image_hist, cvPoint(x, 0), cvPoint(x, value), cvScalar(255));
            }
        }
    }
}

效果:

使用三种光照条件下的手的图像,利用cvCalcHist来获得直方图

a、获得图像HSV三维直方图

b、匹配三种光照条件下的直方图,使用所有的匹配方法,测试bin的值为2, 8, 16, 32, 256的情况

输入3种光照条件(依次为由暗到亮)下手的图像是:

   

由于原图太大了,无法上传,我把它们截图了上传。

匹配结果:

bin=2

bin=8

bin=16

bin=32

bin=256

输出的直方图为:





有几个注意事项:

①二维直方图bin的多少是各维度bin的乘积,以h和s二维直方图来说,如果h的bin的个数为30,s的bin的个数为32,则,二维直方图的bin的个数为30×32,访问的时候要使用cvQueryHistValue_2D。

②由于需要匹配“各种光线”下的直方图,所以,代码中将BGR图像转成了HSV图像 cvCvtColor(image_Source, image_HSV, CV_BGR2HSV);。

③书中Example 7-1统计的是HS直方图,即色调和饱和度,没有统计亮度,针对三种光线下的手的图像,如果统计亮度即V的直方图,三种环境下的匹配结果值肯定不匹配度很高。这点在230页有专门的讲解,为什么只选取HS两维而避开V维,是这个道理。

④为什么说是手的肤色直方图,从图7-6的表述来看,所谓肤色直方图即肤色所在图片的直方图,在英文版更看得出这个意思。 

⑤一般情况下在对比直方图之前,都应该自行进行归一化操作,因为如果不归一化,像直方图相交等概念就没有任何意义(即使运行)。


(完)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值