由于ofxOpencv里的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; } } }
其原理请移步这里