zoukankan      html  css  js  c++  java
  • 【练习7.6】漫水填充获取掩码并以此计算肤色直方图、用以查找肤色区域即颜色识别

    提纲
    题目要求
    程序代码
    结果图片
    要言妙道
    借鉴参考

      

    题目要求:

     建立感兴趣的肤色区域检测器

    a、在“室内条件下”,利用手来建立肤色直方图(原题是建立RGB直方图,我使用的是HSV直方图)

    b、加载另一幅包含手的图像,利用函数cvClacBackProject找到肤色区域 

    程序代码:

      1 // OpenCVExerciseTesting.cpp : 定义控制台应用程序的入口点。
      2 //
      3 //D:\Work\Work_Programming\Source\Image\lena.jpg
      4 
      5 #include "stdafx.h"
      6 #include <cv.h>
      7 #include <highgui.h>
      8 #include <iostream>
      9 
     10 #include <opencv2/legacy/legacy.hpp>
     11 //#pragma comment(lib, "opencv_legacy2411.lib")
     12 
     13 using namespace cv;
     14 using namespace std;
     15 
     16 //全局变量-->--->-->--->-->--->-->--->/:
     17 
     18 const char * soutceFile_InDoor = "D:\Work\Work_Programming\Source\Image\OpenCVExerciseImage\第7章\hand_sample3.jpg";
     19 IplImage *image_Source = cvLoadImage(soutceFile_InDoor, CV_LOAD_IMAGE_UNCHANGED);
     20 const char * soutceFile_Dst = "D:\Work\Work_Programming\Source\Image\OpenCVExerciseImage\第7章\hand_sample2.jpg";
     21 IplImage *image_Dst = cvLoadImage(soutceFile_Dst, CV_LOAD_IMAGE_UNCHANGED);
     22 
     23 IplImage * image_mask = cvCreateImage(cvSize(image_Source->width+2,image_Source->height+2), IPL_DEPTH_8U, 1);//②注意mask图像的大小
     24 const char * mask_windowName = "掩码图像窗口";
     25 
     26 //<--<--<--<--<--<--<--<--<--全局变量/。
     27 
     28 
     29 //函数声明-->--->-->--->-->--->-->--->//
     30 
     31 void DrawHistogram(IplImage ** image_hist, const CvHistogram * histogram, int scaleValue);
     32 
     33 void onTrackbarSlide_low(int pos);
     34 void onTrackbarSlide_up(int pos);
     35 void GetMaskImage(int pos, bool isUpValue);
     36 CvHistogram * CalcHSHistogramByMask(const IplImage* image_RGB, IplImage *mask);
     37 void CalcHSBackProject(const IplImage* image_RGB, const CvHistogram *HSHist);
     38 
     39 //<--<--<--<--<--<--<--<--<--函数声明//
     40 
     41 int _tmain(int argc, _TCHAR* argv[])
     42 {
     43     const char * src_windowName = "原始图像窗口";
     44     cvNamedWindow(src_windowName, CV_WINDOW_AUTOSIZE);
     45 
     46     int slider_position_low = 5;
     47     int slider_position_up = 30;
     48     cvCreateTrackbar("loDiff", src_windowName, &slider_position_low, 255, onTrackbarSlide_low);
     49     cvCreateTrackbar("upDiff", src_windowName, &slider_position_up, 255, onTrackbarSlide_up);
     50 
     51     cvShowImage(src_windowName, image_Source);
     52     //接下来在TrackBar的回调函数中完成后续的一系列操作
     53 
     54     cvWaitKey();
     55     cvReleaseImage(&image_Source);
     56     cvReleaseImage(&image_Dst);
     57     cvReleaseImage(&image_mask);
     58 
     59     cvDestroyAllWindows();
     60 
     61     return 0;
     62 }
     63 
     64 
     65 //目前只实现绘制二维直方图
     66 void DrawHistogram(/*IplImage ** image_hist,*/ const CvHistogram * histogram, int scaleValue)
     67 {
     68     const char * draw_histWindow = "DrawHist";
     69     cvNamedWindow(draw_histWindow, CV_WINDOW_AUTOSIZE);
     70     //直方图:横坐标表示各个bin,纵坐标表示各个bin归一化后的值
     71     int hist_dims = histogram->mat.dims;
     72 
     73     int bin_size1, bin_size2/*, bin_size3*/;
     74 
     75     if (hist_dims == 2)
     76     {
     77         bin_size1 = histogram->mat.dim[0].size;
     78         bin_size2 = histogram->mat.dim[1].size;
     79         //bin_size3 = histogram->mat.dim[2].size;
     80     }
     81     else
     82     {
     83         return;
     84     }
     85 
     86     int bin_count = bin_size1*bin_size2/**bin_size3*/;
     87     float max_temp;
     88     cvGetMinMaxHistValue(histogram, NULL, &max_temp);
     89     int max_value = (int)(max_temp*scaleValue) + 1;
     90     CvSize hist_imageSize = cvSize(bin_count, max_value);
     91     IplImage*image_hist = cvCreateImage(hist_imageSize, IPL_DEPTH_8U, 1);
     92     (image_hist)->origin = 1;
     93     cvZero(image_hist);
     94 
     95     int x;
     96     int value;
     97 
     98     for (int r = 0; r < bin_size1; ++r)
     99     {
    100         for (int g = 0; g < bin_size2; ++g)
    101         {
    102             //for (int b = 0; b < bin_size3; ++b)
    103             {
    104                 //x = r*(bin_size1*bin_size2) + g*bin_size2 + b;
    105                 x = r* bin_size1 + g;
    106                 value = (int)(cvQueryHistValue_2D(histogram, r, g)*scaleValue);
    107 
    108                 //value = (int)(cvQueryHistValue_3D(histogram, r, g, b)*scaleValue);
    109                 /*        if (value == 0)
    110                 {
    111                 value = 10;
    112                 }*/
    113                 cvRectangle(image_hist, cvPoint(x, 0), cvPoint(x, value), cvScalar(255));
    114             }
    115         }
    116     }
    117     cvShowImage(draw_histWindow, image_hist);
    118 }
    119 
    120 void onTrackbarSlide_low(int pos)
    121 {
    122     GetMaskImage(pos, false);
    123 }
    124 
    125 void onTrackbarSlide_up(int pos)
    126 {
    127     GetMaskImage(pos, true);
    128 }
    129 
    130 void GetMaskImage(int pos ,bool isUpValue)
    131 {
    132     static int lowValue = 0;
    133     static int upValue = 0;
    134     CvPoint seedPoint = cvPoint(image_Source->width / 3 * 2, image_Source->height / 3 * 2);
    135 
    136     if (isUpValue == true)
    137     {
    138         upValue = pos;
    139     }
    140     else
    141     {
    142         lowValue = pos;
    143     }
    144 
    145     if (lowValue > upValue)
    146     {
    147         lowValue ^= upValue ^= lowValue ^= upValue;//交换两个变量的值
    148     }
    149 
    150     int flags = 8
    151         | CV_FLOODFILL_MASK_ONLY
    152         | CV_FLOODFILL_FIXED_RANGE
    153         | (255 << 8);
    154 
    155     cvZero(image_mask);//①重要
    156     cvNamedWindow(mask_windowName, CV_WINDOW_AUTOSIZE);
    157 
    158     //漫水填充找掩码
    159     cvFloodFill(image_Source, seedPoint, cvScalar(255, 255, 255), cvScalar(lowValue, lowValue, lowValue), cvScalar(upValue, upValue, upValue), NULL, flags, image_mask);
    160 
    161     //使用掩码计算直方图
    162     CvRect rect_ROI = cvRect(1, 1, image_mask->width - 2, image_mask->height - 2);
    163     cvSetImageROI(image_mask, rect_ROI); //
    164     cvShowImage(mask_windowName, image_mask);
    165     CvHistogram * hist_ImageSource = CalcHSHistogramByMask(image_Source, image_mask);
    166     cvResetImageROI(image_mask);
    167 
    168     //反向投影
    169     CalcHSBackProject(image_Dst, hist_ImageSource);
    170 
    171     cvNormalizeHist(hist_ImageSource, 1.0);//重要:注意归一化直方图与反向投影的顺序
    172 
    173     DrawHistogram(hist_ImageSource, 3000);
    174 
    175     cvReleaseHist(&hist_ImageSource);
    176 }
    177 
    178 CvHistogram * CalcHSHistogramByMask(const IplImage* image_RGB,IplImage *mask)
    179 {
    180     IplImage* image_HSV = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 3);
    181     cvCvtColor(image_RGB, image_HSV, CV_BGR2HSV);
    182 
    183     IplImage* h_plane = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 1);
    184     IplImage* s_plane = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 1);
    185     IplImage* v_plane = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 1);
    186     IplImage* planes[] = { h_plane, s_plane };
    187     cvCvtPixToPlane(image_HSV, h_plane, s_plane, v_plane, 0);
    188 
    189     int dims = 2;
    190     int h_bins = 30, s_bins = 32;
    191     CvHistogram* hist;
    192     int hist_size[] = { h_bins, s_bins };
    193     float h_ranges[] = { 0, 180 }; // hue is [0,180]
    194     float s_ranges[] = { 0, 255 };
    195     float* ranges[] = { h_ranges, s_ranges };
    196 
    197     hist = cvCreateHist(
    198         dims,
    199         hist_size,
    200         CV_HIST_ARRAY,
    201         ranges,
    202         1
    203         );
    204     cvCalcHist(planes, hist, 0, mask);
    205 
    206     cvReleaseImage(&h_plane);
    207     cvReleaseImage(&s_plane);
    208     cvReleaseImage(&v_plane);
    209     cvReleaseImage(&image_HSV);
    210 
    211     return hist;
    212 }
    213 
    214 void CalcHSBackProject(const IplImage* image_RGB, const CvHistogram *HSHist)
    215 {
    216     IplImage* image_HSV = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 3);
    217     cvCvtColor(image_RGB, image_HSV, CV_BGR2HSV);
    218 
    219     IplImage* h_plane = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 1);
    220     IplImage* s_plane = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 1);
    221     IplImage* v_plane = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 1);
    222     IplImage* planes[] = { h_plane, s_plane };
    223     cvCvtPixToPlane(image_HSV, h_plane, s_plane, v_plane, 0);
    224     IplImage *  image_backProject = cvCreateImage(cvGetSize(image_RGB), IPL_DEPTH_8U, 1);
    225     cvZero(image_backProject);
    226 
    227     cvCalcBackProject(planes, image_backProject, HSHist);
    228     cvNamedWindow("反向投影", CV_WINDOW_AUTOSIZE);
    229     cvShowImage("反向投影", image_backProject);
    230 
    231     cvReleaseImage(&h_plane);
    232     cvReleaseImage(&s_plane);
    233     cvReleaseImage(&v_plane);
    234     cvReleaseImage(&image_HSV);
    235 }

    结果图片:

    要言妙道:

      

    ①可以通过掩码操作来抓取手掌所在区域的直方图,也可以使用类似Cognex拖拽矩形的方式选取兴趣区域,获得目标颜色直方图,利用本章内容,实现颜色识别

    ②注意:cvFloodFill不会覆盖mask的非零像素点,因此,如果不希望mask阻碍填充操作时,将其中元素设为0,即代码中的 cvZero(image_mask);//①重要 ,如果没有这行,会发现掩码图像是一张黑白相间的竖线组成的图片

    ③注意:cvFloodFill填充时,mask图像必须是一个单通道、8位、像素宽度和高度均比源图像大两个像素的图像。

    ④但对于cvCalcHist的掩码,又要求掩码图像必须与用于计算的各plane图像相同大小,所以,要对cvFloodFill得到的掩码图像设置兴趣区域,当然,如果mask是矩阵,可以利用OpenCV的Range函数直接得到

    ⑤注意169行和171行计算方向投影和归一化直方图的先后顺序,如果先归一化直方图,反向投影得不到理想图像,尽管不算错,《学习OpenCV》针对此有如下描述:如果直方图是归一化的吗,此值便与一个条件概率值相关(即图像中像素点为直方图hist所表征的某种成员的概率) 

    前几道题“肤色直方图”的计算不准确,应该用本题这种方式 ,在前面各篇中著注明

    借鉴参考:

     反向投影_OpenCV中文论坛教程

     cvInRangeS参考

  • 相关阅读:
    linux tcp中time_wait
    linux查看系统信息
    运行程序出错无法找到库文件
    安装keepalived
    python 深拷贝与浅拷贝
    python import eventlet包时提示ImportError: cannot import name eventlet
    [原创] 用两个queue实现stack的功能
    [原创] 用两个stack实现queue的功能
    [原创] 编写函数,实现对链表元素的排序与分类
    python 装饰器
  • 原文地址:https://www.cnblogs.com/tingshuixuan2012/p/4493253.html
Copyright © 2011-2022 走看看