第七章 学习OpenCV——直方图与匹配

本文详细介绍了使用OpenCV进行直方图计算、显示、匹配以及相关应用,包括EMD直方图匹配、反向投影、模板匹配等,通过多个实例展示了在图像处理中的实际操作。
摘要由CSDN通过智能技术生成

第七章 学习OpenCV——直方图与匹配

目录

例7-1 直方图的计算与显示

根据输入的图像计算出一个色相饱和度(hue-saturation)直方图,然后利用网格的方式将该直方图以网格形式显示出来,具体代码如下:

#include <cv.h>
#include <highgui.h>  
#include <stdlib.h>  
#include <stdio.h> 
#include <math.h>

using namespace std;

CvPoint Current_Point;              //值为255点当前点 全局变量才可通过普通成员引用变更其值

bool find_point(IplImage *img, char val);

int main(int argc, char* argv[])
{
    int threshold_type = CV_THRESH_BINARY;      //阈值类型
    int Last_Area = 0;                          //上一个区域面积       
    int Current_Area = 0;                       //当前区域面积
    double threshold = 65;                      //阈值

    CvPoint Last_Point;                         //值为255点的上一点
    CvConnectedComp comp;                       //被填充区域统计属性
    IplImage *src1, *hsv, *Igray, *Ithreshold, *Itemp, *Iopen, *Imask;      //源图像 HSV格式图像

    Last_Point = cvPoint(0, 0);         //初始化上一点
    Current_Point = cvPoint(0, 0);      //初始化当前点

    if (!(src1 = cvLoadImage("D:\\Template\\OpenCV\\Template46_hue-saturation_Hist\\Debug\\handdd.jpg")))
        return -1;

    //此处调入图像掩码应为单通道
    //if (!(Imask = cvLoadImage("D:\\Template\\OpenCV\\Template46_hue-saturation_Hist\\Debug\\cup2.jpg", CV_LOAD_IMAGE_GRAYSCALE)))
    //  return -2;

    hsv=cvCreateImage(cvGetSize(src1), src1->depth, src1->nChannels);
    Igray = cvCreateImage(cvGetSize(src1), src1->depth, 1);
    Ithreshold = cvCreateImage(cvGetSize(src1), src1->depth, 1);
    Itemp = cvCreateImage(cvGetSize(src1), src1->depth, 1);
    Iopen = cvCreateImage(cvGetSize(src1), src1->depth, 1);
    Imask = cvCreateImage(cvGetSize(src1), src1->depth, 1); //生成手掌掩码图像用

    cvCvtColor(src1, hsv, CV_BGR2HSV);      //源图像->HSV格式图像
    cvCvtColor(src1, Igray, CV_BGR2GRAY);   //源图像->灰度图像

    cvThreshold(Igray, Ithreshold, threshold, 255, threshold_type); //二值阈值化
    //开运算,去除小亮区域,其他联结 NULL:3*3参考点为中心的核
    cvMorphologyEx(Ithreshold, Iopen, Itemp, NULL, CV_MOP_OPEN, 1); 

    cvNamedWindow("src1", 1);
    cvNamedWindow("GRAY_Image", 1);
    cvNamedWindow("THRESHHOLD_Image", 1);
    cvNamedWindow("OPEN_Image", 1);
    cvNamedWindow("FLOOD_FILL", 1);

    cvShowImage("src1", src1);
    cvShowImage("GRAY_Image", Igray);
    cvShowImage("THRESHHOLD_Image", Ithreshold);
    cvShowImage("OPEN_Image", Iopen);
    cvShowImage("FLOOD_FILL", Imask);

    //漫水填充 获得手掌掩码
    cvNamedWindow("FLOOD_FILL", 1);
    cvCopy(Iopen, Imask);           //复制生成手掌掩码

    do
    {
        if (find_point(Imask, 255))    //找像素值为255的像素点
        {

            cout << " X: " << Current_Point.x << " Y: " << Current_Point.y << endl;

            cvFloodFill(Imask, Current_Point, cvScalar(100), cvScalar(0), cvScalar(0),
                &comp, 8 | CV_FLOODFILL_FIXED_RANGE);       //对值为255的点进行漫水填充,值100
            Current_Area = comp.area;                       //当前区域面积

            if (Last_Area<Current_Area)                     //当前区域大于上一区域,上一区域清0
            {
                if (Last_Area>0)
                    cvFloodFill(Imask, Last_Point, cvScalar(0), cvScalar(0), cvScalar(0),
                    &comp, 8 | CV_FLOODFILL_FIXED_RANGE);   //上一区域赋值0
                cvShowImage("FLOOD_FILL", Imask);
                cvWaitKey(500);

                Last_Area = Current_Area;                               //当前区域赋值给上一区域
                Last_Point = Current_Point;                             //当前点赋值给上一点
                //memcpy(&Last_Point, &Current_Point, sizeof(CvPoint)); //错误,此方法复制无法正常使用掩码
            }
            else                                            //当前区域小于等于上一区域,当前区域清0
            {
                if (Current_Area>0)
                    cvFloodFill(Imask, Current_Point, cvScalar(0), cvScalar(0), cvScalar(0),
                    &comp, 8 | CV_FLOODFILL_FIXED_RANGE);   //当前区域赋值0
                cvShowImage("FLOOD_FILL", Imask);
                cvWaitKey(500);
            }
        }
        else                                                //最后剩余的最大区域赋值255
        {
            cvFloodFill(Imask, Last_Point, cvScalar(255), cvScalar(0), cvScalar(0), &comp, 8 | CV_FLOODFILL_FIXED_RANGE);
            cvShowImage("FLOOD_FILL", Imask);
            cvWaitKey(500);
            //上一区域赋值0
            break;
        }
    } while (true);

    cvSaveImage("Imask.jpg", Imask);

    //色调(hue) 饱和度(saturation) 明度(value)
    IplImage *h_plane = cvCreateImage(cvSize(hsv->width, hsv->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane = cvCreateImage(cvSize(hsv->width, hsv->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane = cvCreateImage(cvSize(hsv->width, hsv->height), IPL_DEPTH_8U, 1);

    IplImage *planes[] = {h_plane,s_plane};                     //色相饱和度数组

    cvCvtPixToPlane(hsv, h_plane, s_plane, v_plane, NULL);      //图像分割
    //cvSplit(hsv, h_plane, s_plane, v_plane, NULL);

    int h_bins = 30, s_bins = 32;                               

    //建立直方图
    CvHistogram *hist;

    int hist_size[] = { h_bins, s_bins };       //对应维数包含bins个数的数组
    float h_ranges[] = { 0, 180 };              //H通道划分范围 饱和度0-180
    float s_ranges[] = { 0, 255 };              //S通道划分范围
    float* ranges[] = { h_ranges, s_ranges };   //划分范围数对, ****均匀bin,range只要最大最小边界
    //创建直方图 (维数,对应维数bins个数,密集矩阵方式存储,划分范围数对,均匀直方图)
    hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);

    cvCalcHist(planes, hist, 0, Imask); //计算直方图(图像,直方图结构,不累加,掩码)
    cvNormalizeHist(hist, 1.0);         //直方图归一化

    //绘制可视化直方图
    int scale = 10;
    IplImage* hist_img = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3);   //300*320
    cvZero(hist_img);

    //以小灰度块填充图像
    float max_value = 0;
    cvGetMinMaxHistValue(hist, NULL, &max_value, NULL, NULL);       //获取直方图最大值

    for (int h = 0; h < h_bins; h++)
    {
        for (int s = 0; s < s_bins; s++)
        {
            float bin_val = cvQueryHistValue_2D(hist, h, s);    //获取直方图相应bin中的浮点数
            int intensity = cvRound(bin_val * 255 / max_value); //映射到255空间,归一后太小,难辨
            cvRectangle(hist_img, cvPoint(h*scale, s*scale),        
                cvPoint((h + 1)*scale - 1, (s + 1)*scale - 1), 
                CV_RGB(intensity, intensity, intensity), CV_FILLED);
        }
    }

    cvNamedWindow("HIST_Image", 1);
    cvShowImage("HIST_Image", hist_img);

    cvWaitKey();

    cvReleaseHist(&hist);

    cvReleaseImage(&src1);
    cvReleaseImage(&hsv);
    cvReleaseImage(&Igray);
    cvReleaseImage(&Ithreshold);
    cvReleaseImage(&Itemp);
    cvReleaseImage(&Iopen);
    cvReleaseImage(&Imask);
    cvReleaseImage(&h_plane);
    cvReleaseImage(&s_plane);
    cvReleaseImage(&v_plane);
    cvReleaseImage(&hist_img);

    cvDestroyWindow("src1");
    cvDestroyWindow("HIST_Image");
    cvDestroyWindow("GRAY_Image");
    cvDestroyWindow("THRESHHOLD_Image");
    cvDestroyWindow("OPEN_Image");
    cvDestroyWindow("FLOOD_FILL");
    cvDestroyWindow("HIST_Image");

}

/******************遍历图像,指针算法********************/
bool find_point(IplImage *img, char val)
{
    char* ptr = NULL;

    if (img->nChannels == 1)
    {
        ptr = img->imageData;
        if (ptr != NULL)
        {
            for (int i = 0; i < img->height; i++)       //矩阵指针行寻址
            {
                ptr = (img->imageData + i*(img->widthStep));   //i 行 j 列
                for (int j = 0; j < img->width; j++)    //矩阵指针列寻址
                {
                    if (ptr[j] == val)              //判断某点像素是否为255
                    {
                        Current_Point.x = j;        /********局部变量此方式 无法实现赋值********/
                        Current_Point.y = i;
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

运行结果如下图:
计算显示H-S直方图

例7-2 从EMD直方图创建signature,用EMD度量相似性

根据输入的图像计算色相饱和度(hue-saturation)直方图,然后利用该直方图创建EMD接口参数signature,最后利用EMD来度量两个分布之间的相似性,程序中src1与src2已经过处理,有40的亮度值偏移,具体代码如下:

#include <cv.h>
#include <highgui.h>  
#include <stdlib.h>  
#include <stdio.h> 
#include <math.h>

using namespace std;

int main(int argc, char* argv[])
{
    IplImage* src1,*src2,*Imask,*hsv1,*hsv2;                //源图像 HSV格式图像

    if (!(src1 = cvLoadImage("D:\\Template\\OpenCV\\Template47_hue-saturation_EMD\\Debug\\hand1.jpg")))
        return -1;
    if (!(src2 = cvLoadImage("D:\\Template\\OpenCV\\Template47_hue-saturation_EMD\\Debug\\hand3.jpg")))
        return -2;
    if (!(Imask = cvLoadImage("D:\\Template\\OpenCV\\Template47_hue-saturation_EMD\\Debug\\Imask.jpg", CV_LOAD_IMAGE_GRAYSCALE)))
        return -3;

    hsv1 = cvCreateImage(cvGetSize(src1), src1->depth, src1->nChannels);
    hsv2 = cvCreateImage(cvGetSize(src2), src2->depth, src2->nChannels);

    cvCvtColor(src1, hsv1, CV_BGR2HSV); //源图像->HSV格式图像
    cvCvtColor(src2, hsv2, CV_BGR2HSV); //源图像->HSV格式图像

    //色调(hue) 饱和度(saturation) 明度(value)
    IplImage *h_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);

    IplImage *h_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);

    IplImage *planes1[] = { h_plane_1, s_plane_1 };                     //色相饱和度数组
    IplImage *planes2[] = { h_plane_2, s_plane_2 };                     //色相饱和度数组

    cvCvtPixToPlane(hsv1, h_plane_1, s_plane_1, v_plane_1, NULL);       //图像分割
    cvCvtPixToPlane(hsv2, h_plane_2, s_plane_2, v_plane_2, NULL);       //图像分割
    //cvSplit(hsv, h_plane, s_plane, v_plane, NULL);

    int h_bins = 30, s_bins = 32;                               

    //建立直方图
    CvHistogram *hist1,*hist2;

    int hist_size[] = { h_bins, s_bins };       //对应维数包含bins个数的数组
    float h_ranges[] = { 0, 180 };              //H通道划分范围 饱和度0-180
    float s_ranges[] = { 0, 255 };              //S通道划分范围
    float* ranges[] = { h_ranges, s_ranges };   //划分范围数对, ****均匀bin,range只要最大最小边界
    //创建直方图 (维数,对应维数bins个数,密集矩阵方式存储,划分范围数对,均匀直方图)
    hist1 = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
    hist2 = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);

    cvCalcHist(planes1, hist1, 0, 0);       //计算直方图(图像,直方图结构,不累加,掩码)
    cvCalcHist(planes2, hist2, 0, 0);       //计算直方图(图像,直方图结构,不累加,掩码)

    //cvCalcHist(planes1, hist1, 0, Imask);     //计算直方图(图像,直方图结构,不累加,掩码)
    //cvCalcHist(planes2, hist2, 0, Imask);     //计算直方图(图像,直方图结构,不累加,掩码)

    cvNormalizeHist(hist1, 1.0);            //直方图归一化
    cvNormalizeHist(hist2, 1.0);            //直方图归一化

    CvMat *sig1, *sig2;
    int numrows = h_bins*s_bins;

    sig1 = cvCreateMat(numrows, 3, CV_32FC1);   //numrows行 3列 矩阵
    sig2 = cvCreateMat(numrows, 3, CV_32FC1);

    for (int h = 0; h < h_bins; h++)
    {
        for (int s = 0; s < s_bins; s++)
        {
            float bin_val = cvQueryHistValue_2D(hist1, h, s);
            //h:行数 s_bins:总列数(行长度)s:列数  h*s_bins+s 当前bin对应的sig行数   
            cvSet2D(sig1, h*s_bins + s, 0, cvScalar(bin_val));  
            cvSet2D(sig1, h*s_bins + s, 1, cvScalar(h));
            cvSet2D(sig1, h*s_bins + s, 2, cvScalar(s));

            bin_val = cvQueryHistValue_2D(hist2, h, s);
            cvSet2D(sig2, h*s_bins + s, 0, cvScalar(bin_val));
            cvSet2D(sig2, h*s_bins + s, 1, cvScalar(h));
            cvSet2D(sig2, h*s_bins + s, 2, cvScalar(s));
        }
    }

    float emd = cvCalcEMD2(sig1, sig2, CV_DIST_L2);
    printf("EMD距离:%f; ", emd);

    cvNamedWindow("SRC1",1);
    cvNamedWindow("SRC2",2);

    cvShowImage("SRC1", src1);
    cvShowImage("SRC2", src2);

    cvWaitKey(0);
    //system("pause");

    cvReleaseMat(&sig1);
    cvReleaseMat(&sig2);

    cvReleaseHist(&hist1);
    cvReleaseHist(&hist2);

    cvReleaseImage(&src1);
    cvReleaseImage(&src2);
    cvReleaseImage(&Imask);
    cvReleaseImage(&hsv1);
    cvReleaseImage(&hsv2);
    cvReleaseImage(&h_plane_1);
    cvReleaseImage(&s_plane_1);
    cvReleaseImage(&v_plane_1);
    cvReleaseImage(&h_plane_2);
    cvReleaseImage(&s_plane_2);
    cvReleaseImage(&v_plane_2);

    cvDestroyAllWindows();
}

运行结果如下图:
EMD距离

例7-3 基于像素点的反向投影(cvCalcBackProject)

根据输入的图像计算色相饱和度(hue-saturation)直方图,以网格形式显示,利用肤色模板直方图进行基于像素点的反向投影,在测试图像中找出该肤色模板直方图对应的区域,对应具体代码如下:

#include <cv.h>
#include <highgui.h>  
#include <stdlib.h>  
#include <stdio.h> 
#include <math.h>

using namespace std;

int main(int argc, char* argv[])
{
    IplImage* src1,*src2,*Imask,*hsv1,*hsv2;    //源图像 HSV格式图像

    if (!(src1 = cvLoadImage("D:\\Template\\OpenCV\\Template48_hue-saturation_BackProjection\\Debug\\hand1.jpg")))
        return -1;
    if (!(src2 = cvLoadImage("D:\\Template\\OpenCV\\Template48_hue-saturation_BackProjection\\Debug\\hand3.jpg")))
        return -2;
    //此处调入图像掩码应为单通道
    if (!(Imask = cvLoadImage("D:\\Template\\OpenCV\\Template48_hue-saturation_BackProjection\\Debug\\Imask.jpg", CV_LOAD_IMAGE_GRAYSCALE)))
        return -3;

    cvXorS(Imask, cvScalar(255), Imask);        //掩码图像按位异或,求反生成新的掩码处理模板
    cvSet(src1, cvScalarAll(0), Imask);

    hsv1 = cvCreateImage(cvGetSize(src1), src1->depth, src1->nChannels);
    hsv2 = cvCreateImage(cvGetSize(src2), src2->depth, src2->nChannels);

    cvCvtColor(src1, hsv1, CV_BGR2HSV); //源图像->HSV格式图像
    cvCvtColor(src2, hsv2, CV_BGR2HSV); //源图像->HSV格式图像

    //反向投影图像
    IplImage *back_projection = cvCreateImage(cvGetSize(src2), IPL_DEPTH_8U, 1);

    //色调(hue) 饱和度(saturation) 明度(value)
    IplImage *h_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);

    IplImage *h_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);

    IplImage *planes1[] = { h_plane_1, s_plane_1 };                     //色相饱和度数组
    IplImage *planes2[] = { h_plane_2, s_plane_2 };                     //色相饱和度数组

    cvCvtPixToPlane(hsv1, h_plane_1, s_plane_1, v_plane_1, NULL);       //图像分割
    cvCvtPixToPlane(hsv2, h_plane_2, s_plane_2, v_plane_2, NULL);       //图像分割
    //cvSplit(hsv, h_plane, s_plane, v_plane, NULL);

    int h_bins = 30, s_bins = 32;                               

    //建立直方图
    CvHistogram *hist_model,*hist_test;

    int hist_size[] = { h_bins, s_bins };       //对应维数包含bins个数的数组
    float h_ranges[] = { 0, 180 };              //H通道划分范围 饱和度0-180
    float s_ranges[] = { 0, 255 };              //S通道划分范围
    float* ranges[] = { h_ranges, s_ranges };   //划分范围数对, ****均匀bin,range只要最大最小边界
    //创建直方图 (维数,对应维数bins个数,密集矩阵方式存储,划分范围数对,均匀直方图)
    hist_model = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
    hist_test = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);


    cvCalcHist(planes1, hist_model, 0, 0);      //计算直方图(图像,直方图结构,不累加,掩码)
    cvCalcHist(planes2, hist_test, 0, 0);       //计算直方图(图像,直方图结构,不累加,掩码)

    //cvNormalizeHist(hist_model, 1.0);         //直方图归一化
    //cvNormalizeHist(hist_test, 1.0);          //直方图归一化

    //绘制可视化直方图
    int scale = 10;
    IplImage* hist_img_model = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3); //300*320
    IplImage* hist_img_test = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3);  //300*320

    cvZero(hist_img_model);
    cvZero(hist_img_test);

    //以小灰度块填充图像
    float max_value_model = 0;
    float max_value_test = 0;

    cvGetMinMaxHistValue(hist_model, NULL, &max_value_model, NULL, NULL);   //获取直方图最大值
    cvGetMinMaxHistValue(hist_test, NULL, &max_value_test, NULL, NULL);     //获取直方图最大值

    for (int h = 0; h < h_bins; h++)
    {
        for (int s = 0; s < s_bins; s++)
        {
            float bin_val_model = cvQueryHistValue_2D(hist_model, h, s);    //获取直方图相应bin中的浮点数
            float bin_val_test = cvQueryHistValue_2D(hist_test, h, s);      //获取直方图相应bin中的浮点数

            int intensity1 = cvRound(bin_val_model * 255 / max_value_model);//映射到255空间
            int intensity2 = cvRound(bin_val_test * 255 / max_value_test);  //归一后太小

            cvRectangle(hist_img_model, cvPoint(h*scale, s*scale),
                cvPoint((h + 1)*scale - 1, (s + 1)*scale - 1),
                CV_RGB(intensity1, intensity1, intensity1), CV_FILLED);
            cvRectangle(hist_img_test, cvPoint(h*scale, s*scale),
                cvPoint((h + 1)*scale - 1, (s + 1)*scale - 1),
                CV_RGB(intensity2, intensity2, intensity2), CV_FILLED);
        }
    }

    cvCalcBackProject(planes2, back_projection, hist_model);        //像素点的反射投影

    cvNamedWindow("Mask", 1);
    cvNamedWindow("Model", 1);
    cvNamedWindow("Test", 1);
    cvNamedWindow("HIST_Model", 1);
    cvNamedWindow("HIST_Test", 1);
    cvNamedWindow("BACK_Projection", 1);

    cvShowImage("Mask", Imask);
    cvShowImage("Model", src1);
    cvShowImage("Test", src2);
    cvShowImage("HIST_Model", hist_img_model);
    cvShowImage("HIST_Test", hist_img_test);
    cvShowImage("BACK_Projection", back_projection);

    cvWaitKey(0);
    //system("pause");

    cvReleaseHist(&hist_model);
    cvReleaseHist(&hist_test);

    cvReleaseImage(&Imask);
    cvReleaseImage(&src1);
    cvReleaseImage(&src2);
    cvReleaseImage(&hist_img_model);
    cvReleaseImage(&hist_img_test);
    cvReleaseImage(&h_plane_1);
    cvReleaseImage(&s_plane_1);
    cvReleaseImage(&v_plane_1);
    cvReleaseImage(&h_plane_2);
    cvReleaseImage(&s_plane_2);
    cvReleaseImage(&v_plane_2);
    cvReleaseImage(&back_projection);

    cvDestroyAllWindows();
}

运行结果如下图:
基于点的反向投影

例7-4 基于块的反向投影(cvCalcArrBackProjectPatch)

根据输入的图像计算色相饱和度(hue-saturation)直方图,以网格形式显示,利用颜色模板直方图进行基于块的反向投影,在测试图像中找出该颜色模板直方图对应的区域,程序中,对于手的检测cvCalcArrBackProjectPatch()做区域检测器,对于杯子的检测cvCalcArrBackProjectPatch()做目标检测器,对应具体代码如下:

#include <cv.h>
#include <highgui.h>  
#include <stdlib.h>  
#include <stdio.h> 
#include <math.h>

using namespace std;

int main(int argc, char* argv[])
{
    //源图像 HSV格式图像
    IplImage* Ihand_model, *Ihand_test, *Ihand_mask, *hsv1, *hsv2, *hsv3, *hsv4, *Icup_model, *Icup_test, *Icup_mask;   

    //未处理的肤色模板图像
    if (!(Ihand_model = cvLoadImage("D:\\Template\\OpenCV\\Template49_hue-saturation_BackProjection_Patch\\Debug\\hand1.jpg")))
        return -1;
    //寻找手掌反向投影的测试图像
    if (!(Ihand_test = cvLoadImage("D:\\Template\\OpenCV\\Template49_hue-saturation_BackProjection_Patch\\Debug\\hand3.jpg")))
        return -2;
    //用于处理肤色模板图像的掩码,此处调入图像掩码应为单通道
    if (!(Ihand_mask = cvLoadImage("D:\\Template\\OpenCV\\Template49_hue-saturation_BackProjection_Patch\\Debug\\Imask.jpg",
        CV_LOAD_IMAGE_GRAYSCALE)))
        return -3;
    //未处理的杯子颜色模板图像
    if (!(Icup_model = cvLoadImage("D:\\Template\\OpenCV\\Template49_hue-saturation_BackProjection_Patch\\Debug\\cup2.jpg")))
        return -4;
    //寻找杯子反向投影的测试图像
    if (!(Icup_test = cvLoadImage("D:\\Template\\OpenCV\\Template49_hue-saturation_BackProjection_Patch\\Debug\\cup1.jpg")))
        return -5;
    //用于处理杯子颜色模板图像的掩码 可获取杯子反向投影块大小
    if (!(Icup_mask = cvLoadImage("D:\\Template\\OpenCV\\Template49_hue-saturation_BackProjection_Patch\\Debug\\cup3.jpg",
        CV_LOAD_IMAGE_GRAYSCALE)))
        return -6;

    int hand_patch_width = 5;                       //手掌反向投影块宽度
    int hand_patch_height = 5;                      //手掌反向投影块高度

    int cup_patch_width = Icup_model->width;        //杯子反向投影块宽度
    int cup_patch_height = Icup_model->height;      //杯子反向投影块高度

    cvXorS(Ihand_mask, cvScalar(255), Ihand_mask);          //掩码图像按位异或,求反,以手掌以外区域作为掩码
    cvXorS(Icup_mask, cvScalar(255), Icup_mask);            //掩码图像按位异或,求反,以杯子以外区域作为掩码

    cvSet(Ihand_model, cvScalarAll(0), Ihand_mask);         //将手掌以外区域变黑,生成肤色模板图像
    cvSet(Icup_model, cvScalarAll(0), Icup_mask);           //将手掌以外区域变黑,生成肤色模板图像

    hsv1 = cvCreateImage(cvGetSize(Ihand_model), Ihand_model->depth, Ihand_model->nChannels);   //HSV
    hsv2 = cvCreateImage(cvGetSize(Ihand_test), Ihand_test->depth, Ihand_test->nChannels);      //HSV
    hsv3 = cvCreateImage(cvGetSize(Icup_model), Icup_model->depth, Icup_model->nChannels);      //HSV
    hsv4 = cvCreateImage(cvGetSize(Icup_test), Icup_test->depth, Icup_test->nChannels);         //HSV

    cvCvtColor(Ihand_model, hsv1, CV_BGR2HSV);      //源图像->HSV格式图像
    cvCvtColor(Ihand_test, hsv2, CV_BGR2HSV);       //源图像->HSV格式图像
    cvCvtColor(Icup_model, hsv3, CV_BGR2HSV);       //源图像->HSV格式图像
    cvCvtColor(Icup_test, hsv4, CV_BGR2HSV);        //源图像->HSV格式图像

    //反向投影图像 大小:测试图像-块的大小 浮点型数组
    IplImage *Iback_projection_patch_hand = cvCreateImage(
        cvSize(Ihand_test->width - hand_patch_width + 1, Ihand_test->height - hand_patch_height + 1), 
        IPL_DEPTH_32F, 1);
    IplImage *Iback_projection_patch_cup = cvCreateImage(
        cvSize(Icup_test->width - cup_patch_width + 1, Icup_test->height - cup_patch_height + 1),
        IPL_DEPTH_32F, 1);

    //色调(hue) 饱和度(saturation) 明度(value) 创建三通道图像
    IplImage *h_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);

    IplImage *h_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);

    IplImage *h_plane_3 = cvCreateImage(cvSize(hsv3->width, hsv3->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_3 = cvCreateImage(cvSize(hsv3->width, hsv3->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_3 = cvCreateImage(cvSize(hsv3->width, hsv3->height), IPL_DEPTH_8U, 1);

    IplImage *h_plane_4 = cvCreateImage(cvSize(hsv4->width, hsv4->height), IPL_DEPTH_8U, 1);
    IplImage *s_plane_4 = cvCreateImage(cvSize(hsv4->width, hsv4->height), IPL_DEPTH_8U, 1);
    IplImage *v_plane_4 = cvCreateImage(cvSize(hsv4->width, hsv4->height), IPL_DEPTH_8U, 1);

    IplImage *planes1[] = { h_plane_1, s_plane_1 };                     //色相饱和度数组
    IplImage *planes2[] = { h_plane_2, s_plane_2 };                     //色相饱和度数组
    IplImage *planes3[] = { h_plane_3, s_plane_3 };                     //色相饱和度数组
    IplImage *planes4[] = { h_plane_4, s_plane_4 };                     //色相饱和度数组

    cvCvtPixToPlane(hsv1, h_plane_1, s_plane_1, v_plane_1, NULL);       //图像分割
    cvCvtPixToPlane(hsv2, h_plane_2, s_plane_2, v_plane_2, NULL);       //图像分割
    cvCvtPixToPlane(hsv3, h_plane_3, s_plane_3, v_plane_3, NULL);
    cvCvtPixToPlane(hsv4, h_plane_4, s_plane_4, v_plane_4, NULL);
    //cvSplit(hsv4, h_plane_4, s_plane_4, v_plane_4, NULL);             //两函数效果相似

    int h_bins = 30, s_bins = 32;               //h维bins的个数,s维bins的个数               

    //建立模板和测试直方图
    CvHistogram *hist_model_hand, *hist_test_hand, *hist_model_cup, *hist_test_cup;

    int hist_size[] = { h_bins, s_bins };       //对应维数包含bins个数的数组
    float h_ranges[] = { 0, 180 };              //H通道划分范围 饱和度0-180
    float s_ranges[] = { 0, 255 };              //S通道划分范围
    float* ranges[] = { h_ranges, s_ranges };   //划分范围数对, ****均匀bin,range只要最大最小边界

    //创建直方图 (维数,对应维数bins个数,密集矩阵方式存储,划分范围数对,均匀直方图)
    hist_model_hand = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
    hist_test_hand = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
    hist_model_cup= cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
    hist_test_cup = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
    //计算直方图
    cvCalcHist(planes1, hist_model_hand, 0, 0);     //计算直方图(图像,直方图结构,不累加,掩码)肤色直方图
    cvCalcHist(planes2, hist_test_hand, 0, 0);      //计算直方图(图像,直方图结构,不累加,掩码)测试直方图
    cvCalcHist(planes3, hist_model_cup, 0, 0);      //计算直方图(图像,直方图结构,不累加,掩码)杯色直方图
    cvCalcHist(planes4, hist_test_cup, 0, 0);       //计算直方图(图像,直方图结构,不累加,掩码)测试直方图
    //直方图归一化
    cvNormalizeHist(hist_model_hand, 1.0);          //直方图归一化
    cvNormalizeHist(hist_test_hand, 1.0);           //直方图归一化
    cvNormalizeHist(hist_model_cup, 1.0);           //直方图归一化
    cvNormalizeHist(hist_test_cup, 1.0);            //直方图归一化

    //绘制可视化直方图
    int scale = 10;     //直方图颜色值图像显示倍数
    IplImage* Ihist_model_hand = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3);   //300*320
    IplImage* Ihist_test_hand = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3);    //300*320
    IplImage* Ihist_model_cup = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3);    //300*320
    IplImage* Ihist_test_cup = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3);     //300*320

    //直方图颜色值图像清零
    cvZero(Ihist_model_hand);
    cvZero(Ihist_test_hand);
    cvZero(Ihist_model_cup);
    cvZero(Ihist_test_cup);

    //以小灰度块填充图像
    float max_value_model_hand = 0; //直方图中最大值,为映射做准备
    float max_value_test_hand = 0;
    float max_value_model_cup = 0;  //直方图中最大值,为映射做准备
    float max_value_test_cup = 0;

    cvGetMinMaxHistValue(hist_model_hand, NULL, &max_value_model_hand, NULL, NULL); //直方图最大值
    cvGetMinMaxHistValue(hist_test_hand, NULL, &max_value_test_hand, NULL, NULL);   //直方图最大值
    cvGetMinMaxHistValue(hist_model_cup, NULL, &max_value_model_cup, NULL, NULL);   //直方图最大值
    cvGetMinMaxHistValue(hist_test_cup, NULL, &max_value_test_cup, NULL, NULL);     //直方图最大值

    for (int h = 0; h < h_bins; h++)
    {
        for (int s = 0; s < s_bins; s++)
        {
            float bin_val_model_hand = cvQueryHistValue_2D(hist_model_hand, h, s);  //bin中的浮点数
            float bin_val_test_hand = cvQueryHistValue_2D(hist_test_hand, h, s);    //bin中的浮点数
            float
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值