天天看点

openFrameworks使用ofxOpencv进行肤色检测

由于ofx Opencv 里的ofxCVColorImage是RGB格式的,没想到调用getCvImage()函数得到的IplImage居然也是RGB格式,结果害得我一开始肤色检测的结果十分诡异。。。作者也够懒的,这么简单居然也不做个转换!

这个就是调换RB通道的代码:

void testApp::cvRGB_or_BGR(IplImage* src_image, IplImage* dst_image)
{
    if (src_image != NULL && dst_image != NULL)
    {
        uchar* src_data=(uchar *)src_image->imageData;
        uchar* dst_data=(uchar *)dst_image->imageData;
 
        int step = src_image->widthStep/sizeof(uchar);
        int channels = src_image->nChannels;
        //uchar *b,*g,*r;
 
        for(int i=0;i<src_image->height;i++)
        {
            for(int j=0;j<src_image->width;j++)
            {
                dst_data[i*step+j*channels + 2] = src_data[i*step+j*channels + 0];  // b
                dst_data[i*step+j*channels + 1] = src_data[i*step+j*channels + 1];  // g
                dst_data[i*step+j*channels] = src_data[i*step+j*channels + 2];      // r
            }
        }
    }
 
    //cvShowImage("RGB", dst_image);    // debug
}      

以下是在网上找到的opencv基于c的肤色检测代码:

void testApp::cvSkinSegment(IplImage* img, IplImage* mask)  // mask是单通道的
{
    CvSize imageSize = cvSize(img->width, img->height);
    IplImage *imgY = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
    IplImage *imgCr = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
    IplImage *imgCb = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
 
    IplImage *imgYCrCb = cvCreateImage(imageSize, img->depth, img->nChannels);
    cvCvtColor(img,imgYCrCb,CV_BGR2YCrCb);
    //cvShowImage("img", img);          // debug
    //cvShowImage("YCrCb", imgYCrCb);   // debug
 
    cvSplit(imgYCrCb, imgY, imgCr, imgCb, 0);
    int y, cr, cb, l, x1, y1, value;
    unsigned char *pY, *pCr, *pCb, *pMask;
 
    pY = (unsigned char *)imgY->imageData;
    pCr = (unsigned char *)imgCr->imageData;
    pCb = (unsigned char *)imgCb->imageData;
    pMask = (unsigned char *)mask->imageData;
    cvSetZero(mask);
 
    l = img->height * img->width;
 
    for (int i = 0; i < l; i++)
    {
        y  = *pY;
        cr = *pCr;
        cb = *pCb;
        cb -= 109;
        cr -= 152
            ;
        x1 = (819*cr-614*cb)/32 + 51;
        y1 = (819*cr+614*cb)/32 + 77;
        x1 = x1*41/1024;
        y1 = y1*73/1024;
        value = x1*x1+y1*y1;
 
        if(y<100)   
            (*pMask)=(value<700) ? 255:0;
        else        
            (*pMask)=(value<850)? 255:0;
 
        pY++;
        pCr++;
        pCb++;
        pMask++;
    }
    
    //cvShowImage("mask", mask);    // debug
 
    cvReleaseImage(&imgY);
    cvReleaseImage(&imgCr);
    cvReleaseImage(&imgCb);
    cvReleaseImage(&imgYCrCb);
 
    //return mask;
}      

我移植的基于c++的肤色检测代码:

void testApp::cvSkinSegment(cv::Mat img, cv::Mat mask)  // mask是单通道的
{
    cv::Size imageSize = img.size();
    cv::Mat imgY, imgCr, imgCb;
    cv::Mat imgYCrCb = cv::Mat(imageSize, CV_8UC3);
    vector<cv::Mat> imgVec;
 
    cvtColor(img,imgYCrCb,CV_BGR2YCrCb);
    
    split(imgYCrCb, imgVec);
    imgY = imgVec[0];
    imgCr = imgVec[1];
    imgCb = imgVec[2];
 
    int y, cr, cb, x1, y1, value;
    uchar *pY, *pCr, *pCb, *pMask;
 
    mask.zeros(mask.size(), mask.type());
    
    int nRows = img.rows;
    int nCols = img.cols;
 
    for (int i = 0; i < nRows; i++)
    {
        pY = imgY.ptr<uchar>(i);
        pCr = imgCr.ptr<uchar>(i);
        pCb = imgCb.ptr<uchar>(i);
        pMask = mask.ptr<uchar>(i);
 
        for (int j = 0; j<nCols; j++)
        {
            y  = pY[j];
            cr = pCr[j];
            cb = pCb[j];
            cb -= 109;
            cr -= 152;
 
            x1 = (819*cr - 614*cb)/32 + 51;
            y1 = (819*cr + 614*cb)/32 + 77;
            x1 = x1 * 41/1024;
            y1 = y1 * 73/1024;
            value = x1*x1 + y1*y1;
 
            if(y<100)   
                (pMask[j])=(value<700) ? 255:0;
            else        
                (pMask[j])=(value<850)? 255:0;
        }
        
    }
    
}      

其原理请移步

这里

继续阅读