【新】opencv肤色检测源码

举报
ShaderJoy 发表于 2021/12/30 01:21:48 2021/12/30
【摘要】 //第一种:RGB color space // skin region location using rgb limitationvoid ImageSkin::ImageSkinRGB(const Mat& rgb, Mat& _dst){ assert(rgb.channels() == 3 &&am...

  
  1. //第一种:RGB color space
  2. // skin region location using rgb limitation
  3. void ImageSkin::ImageSkinRGB(const Mat& rgb, Mat& _dst)
  4. {
  5. assert(rgb.channels() == 3 && _dst.channels() == 3);
  6. static const int R=2;
  7. static const int G=1;
  8. static const int B=0;
  9. Mat dst = Mat(_dst.size(), _dst.type(), 3);
  10. dst.setTo(Scalar(0, 0, 0));
  11. for (int h=0; h<rgb.rows; h++)
  12. {
  13. for (int w=0; w<rgb.cols; w++)
  14. {
  15. // 数组的一份拷贝
  16. Vec3b prgb = rgb.at<Vec3b>(h, w);
  17. Vec3b pdst = dst.at<Vec3b>(h, w);
  18. //auto* pdst111 = &dst.at<Vec3b>(h, w);
  19. if ((prgb[R]>95 && prgb[G]>40 && prgb[B]>20 &&
  20. prgb[R]-prgb[B]>15 && prgb[R]-prgb[G]>15) || //uniform illumination
  21. (prgb[R]>200 && prgb[G]>210 && prgb[B]>170 &&
  22. abs(prgb[R]-prgb[B])<=15 && prgb[R]>prgb[B] && prgb[G]>prgb[B])
  23. )
  24. {
  25. // 赋值切不可用pdst!
  26. memcpy(&dst.at<Vec3b>(h, w), &prgb/*rgb.at<Vec3b>(h, w)*/, 3);
  27. // 同上
  28. //dst.at<Vec3b>(h, w)[R] = rgb.at<Vec3b>(h, w)[R];
  29. //dst.at<Vec3b>(h, w)[G] = rgb.at<Vec3b>(h, w)[G];
  30. //dst.at<Vec3b>(h, w)[B] = rgb.at<Vec3b>(h, w)[B];
  31. }
  32. }
  33. }
  34. dst.copyTo(_dst);
  35. dst.release();
  36. }
  37. //第二种:RG color space
  38. // skin detection in rg space
  39. void ImageSkin::ImageSkinRG(const Mat& rgb, Mat& gray)
  40. {
  41. assert(rgb.channels() == 3 && gray.channels() == 1);
  42. const int R=2;
  43. const int G=1;
  44. const int B=0;
  45. double Aup=-1.8423;
  46. double Bup=1.5294;
  47. double Cup=0.0422;
  48. double Adown=-0.7279;
  49. double Bdown=0.6066;
  50. double Cdown=0.1766;
  51. for (int h=0; h<rgb.rows; h++)
  52. {
  53. for (int w=0; w<rgb.cols; w++)
  54. {
  55. auto* pGray = &gray.at<uchar>(h, w);
  56. auto pRGB = rgb.at<Vec3b>(h, w);
  57. int s=pRGB[R]+pRGB[G]+pRGB[B];
  58. double r=(double)pRGB[R]/s;
  59. double g=(double)pRGB[G]/s;
  60. double Gup=Aup*r*r+Bup*r+Cup;
  61. double Gdown=Adown*r*r+Bdown*r+Cdown;
  62. double Wr=(r-0.33)*(r-0.33)+(g-0.33)*(g-0.33);
  63. if (g<Gup && g>Gdown && Wr>0.004)
  64. {
  65. *pGray=255;
  66. }
  67. else
  68. {
  69. *pGray=0;
  70. }
  71. }
  72. }
  73. }
  74. //
  75. //第三种:otsu阈值化【仅限单通道】
  76. // reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB
  77. void ImageSkin::ImageThresholdOtsu(const Mat& src, Mat& dst)
  78. {
  79. int height=src.rows;
  80. int width=src.cols;
  81. // 统计直方图
  82. float histogram[256]= {0};
  83. for(int i=0; i<height; i++)
  84. {
  85. for(int j=0; j<width; j++)
  86. {
  87. uchar p = src.at<uchar>(i, j);
  88. histogram[p]++;
  89. }
  90. }
  91. // 直方图归一化
  92. int size=height*width;
  93. for(int i=0; i<256; i++)
  94. {
  95. histogram[i]=histogram[i]/size;
  96. }
  97. // 求像素平均值
  98. float avgValue=0;
  99. for(int i=0; i<256; i++)
  100. {
  101. avgValue+=i*histogram[i];
  102. }
  103. int tH;
  104. float maxVariance=0;
  105. float w=0,u=0;
  106. for(int i=0; i<256; i++)
  107. {
  108. w+=histogram[i];
  109. u+=i*histogram[i];
  110. float t=avgValue*w-u;
  111. float variance=t*t/(w*(1-w));
  112. if(variance>maxVariance)
  113. {
  114. maxVariance=variance;
  115. tH=i;
  116. }
  117. }
  118. threshold(src, dst, tH, 255, CV_THRESH_BINARY);
  119. }
  120. //
  121. //第四种:Ycrcb之cr分量+otsu阈值化
  122. void ImageSkin::ImageSkinOtsu(const Mat& src, Mat& dst)
  123. {
  124. assert(dst.channels() == 1 && src.channels() == 3);
  125. Mat ycrcb = Mat(src.size(), src.type(), 3);
  126. Mat yCRcb[3];
  127. cvtColor(src, ycrcb, CV_BGR2YCrCb);
  128. split(ycrcb, yCRcb);
  129. ImageThresholdOtsu(yCRcb[1], yCRcb[1]);
  130. yCRcb[1].copyTo(dst);
  131. yCRcb[1].release();
  132. ycrcb.release();
  133. }
  134. //
  135. //第五种:YCrCb中133<=Cr<=173 77<=Cb<=127
  136. void ImageSkin::ImageSkinYUV(const Mat& src, Mat& dst)
  137. {
  138. Mat ycrcb = Mat(src.size(), src.type(), 3);
  139. cvtColor(src, ycrcb, CV_BGR2YUV); // CV_BGR2YCrCb
  140. static const int Cb=2;
  141. static const int Cr=1;
  142. static const int Y=0;
  143. dst.setTo(Scalar(0, 0, 0));
  144. for (int h=0; h<src.rows; h++)
  145. {
  146. for (int w=0; w<src.cols; w++)
  147. {
  148. const Vec3b* pycrcb = &ycrcb.at<Vec3b>(h, w);
  149. const Vec3b* psrc = &src.at<Vec3b>(h, w);
  150. //const uchar* pdst = &dst.at<uchar>(h, w);
  151. if ((*pycrcb)[Cr]>=133 && (*pycrcb)[Cr]<=173 && (*pycrcb)[Cb]>=77 && (*pycrcb)[Cb]<=127)
  152. {
  153. memcpy(&dst.at<Vec3b>(h, w), psrc, 3);
  154. }
  155. }
  156. }
  157. }


测试代码:


  
  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. Mat img = imread("..\\test.png", 1);
  4. Mat dstRGB = Mat(img.size(), CV_8UC3);
  5. Mat dstRG = Mat(img.size(), CV_8UC1);
  6. Mat dst_crotsu = Mat(img.size(), CV_8UC1);
  7. Mat dst_YUV = Mat(img.size(), CV_8UC3);
  8. namedWindow("Original WIN", CV_WINDOW_AUTOSIZE);
  9. imshow("Original WIN", img);
  10. waitKey(0);
  11. ImageSkin ImgS;
  12. ImgS.ImageSkinRGB(img, dstRGB);
  13. namedWindow("ImageSkinRGB WIN", CV_WINDOW_AUTOSIZE);
  14. imshow("ImageSkinRGB WIN", dstRGB);
  15. imwrite("..//ImageSkinRGB.jpg", dstRGB);
  16. waitKey(0);
  17. ImgS.ImageSkinRG(img, dstRG);
  18. namedWindow("ImageSkinRG WIN", CV_WINDOW_AUTOSIZE);
  19. imshow("ImageSkinRG WIN", dstRG);
  20. imwrite("..//ImageSkinRG.jpg", dstRG);
  21. waitKey(0);
  22. ImgS.ImageSkinOtsu(img, dst_crotsu);
  23. namedWindow("ImageSkinOtsu WIN", CV_WINDOW_AUTOSIZE);
  24. imshow("ImageSkinOtsu WIN", dst_crotsu);
  25. imwrite("..//ImageSkinOtsu.jpg", dst_crotsu);
  26. waitKey(0);
  27. ImgS.ImageSkinYUV(img, dst_YUV);
  28. namedWindow("ImageSkinYUV WIN", CV_WINDOW_AUTOSIZE);
  29. imshow("ImageSkinYUV WIN", dst_YUV);
  30. imwrite("..//ImageSkinYUV.jpg", dst_YUV);
  31. waitKey(0);
  32. return 0;
  33. }

结果显示如图:


本文代码参考了这位大牛的博客点击打开链接,我将它们修改为C++风格,便于自己和其他也习惯C++风格的朋友使用

文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/26730905

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。