Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报
 
原文链接  http://blog.csdn.net/yanzi1225627/article/details/8600169

六种方法分别是:基于RGB分割,基于RG同道的分割,ycrcb+otsu(ostu可以参考http://blog.csdn.net/onezeros/article/details/6136770,

http://wenku.baidu.com/view/05c47e03bed5b9f3f90f1ce4.html),YCrCb空间,YUV空间,HSV空间。下一步就是通过JNI将这些检测移植到android上,最终目标是实现Android智能手机利用掌纹开关机。

环境是在qt下,.pro文件里增加如下代码:

  1. INCLUDEPATH += /usr/include/opencv
  2. LIBS += /usr/lib/libcv.so \
  3. /usr/lib/libcvaux.so \
  4. /usr/lib/libcxcore.so \
  5. /usr/lib/libhighgui.so \
  6. /usr/lib/libml.so

请看源码:

  1. #include <iostream>
  2. #include "cv.h"
  3. #include "highgui.h"
  4. void SkinRGB(IplImage* rgb,IplImage* _dst);
  5. void cvSkinRG(IplImage* rgb,IplImage* gray);
  6. void cvThresholdOtsu(IplImage* src, IplImage* dst);
  7. void cvSkinOtsu(IplImage* src, IplImage* dst);
  8. void cvSkinYCbCr(IplImage* img, IplImage* mask);
  9. void cvSkinYUV(IplImage* src,IplImage* dst);
  10. void cvSkinHSV(IplImage* src,IplImage* dst);
  11. using namespace std;
  12. // skin region location using rgb limitation
  13. int main()
  14. {
  15. IplImage *srcImg = cvLoadImage("/home/yan/download/testPalm4.jpg", 1);
  16. IplImage *dstRGB = cvCreateImage(cvGetSize(srcImg), 8, 3);
  17. IplImage *dstRG = cvCreateImage(cvGetSize(srcImg), 8, 1);
  18. IplImage* dst_crotsu=cvCreateImage(cvGetSize(srcImg),8,1);
  19. IplImage* dst_ycbcr=cvCreateImage(cvGetSize(srcImg),8,1);
  20. IplImage* dst_yuv=cvCreateImage(cvGetSize(srcImg),8,3);
  21. IplImage* dst_hsv=cvCreateImage(cvGetSize(srcImg),8,3);
  22. SkinRGB(srcImg, dstRGB);
  23. cvSaveImage("/home/yan/download/1_dstRGB.jpg", dstRGB);
  24. cvSkinRG(srcImg, dstRG);
  25. cvSaveImage("/home/yan/download/2_dstRG.jpg", dstRG);
  26. cvSkinOtsu(srcImg, dst_crotsu);
  27. cvSaveImage("/home/yan/download/3_dst_crotsu.jpg", dst_crotsu);
  28. cvSkinYCbCr(srcImg, dst_ycbcr);
  29. cvSaveImage("/home/yan/download/4_dst_ycbcr.jpg", dst_ycbcr);
  30. cvSkinYUV(srcImg, dst_yuv);
  31. cvSaveImage("/home/yan/download/5_dst_yuv.jpg", dst_yuv);
  32. cvSkinHSV(srcImg, dst_hsv);
  33. cvSaveImage("/home/yan/download/6_dst_hsv.jpg", dst_hsv);
  34. cvNamedWindow("srcImg", 1);
  35. cvShowImage("srcImg", srcImg);
  36. cvNamedWindow("dstRGB", 1);
  37. cvShowImage("dstRGB", dstRGB);
  38. cvNamedWindow("dstRG", 1);
  39. cvShowImage("dstRG", dstRG);
  40. cvNamedWindow("dstcrotsu", 1);
  41. cvShowImage("dstcrotsu", dst_crotsu);
  42. cvNamedWindow("dst_ycbcr", 1);
  43. cvShowImage("dst_ycbcr", dst_ycbcr);
  44. cvNamedWindow("dst_yuv", 1);
  45. cvShowImage("dst_yuv", dst_yuv);
  46. cvNamedWindow("dst_hsv", 1);
  47. cvShowImage("dst_hsv", dst_hsv);
  48. cvWaitKey(0);
  49. cout << "Hello World!" << endl;
  50. return 0;
  51. }
  52. void SkinRGB(IplImage* rgb,IplImage* _dst)
  53. {
  54. cout<<"111"<<endl;
  55. assert(rgb->nChannels==3&& _dst->nChannels==3);
  56. static const int R=2;
  57. static const int G=1;
  58. static const int B=0;
  59. IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3);
  60. cvZero(dst);
  61. for (int h=0;h<rgb->height;h++) {
  62. unsigned char* prgb=(unsigned char*)rgb->imageData+h*rgb->widthStep;
  63. unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep;
  64. for (int w=0;w<rgb->width;w++) {
  65. if ((prgb[R]>95 && prgb[G]>40 && prgb[B]>20 &&
  66. prgb[R]-prgb[B]>15 && prgb[R]-prgb[G]>15/*&&
  67. !(prgb[R]>170&&prgb[G]>170&&prgb[B]>170)*/)||//uniform illumination
  68. (prgb[R]>200 && prgb[G]>210 && prgb[B]>170 &&
  69. abs(prgb[R]-prgb[B])<=15 && prgb[R]>prgb[B]&& prgb[G]>prgb[B])//lateral illumination
  70. ) {
  71. memcpy(pdst,prgb,3);
  72. }
  73. prgb+=3;
  74. pdst+=3;
  75. }
  76. }
  77. cvCopyImage(dst,_dst);
  78. cvReleaseImage(&dst);
  79. }
  80. void cvSkinRG(IplImage* rgb,IplImage* gray)
  81. {
  82. assert(rgb->nChannels==3&&gray->nChannels==1);
  83. const int R=2;
  84. const int G=1;
  85. const int B=0;
  86. double Aup=-1.8423;
  87. double Bup=1.5294;
  88. double Cup=0.0422;
  89. double Adown=-0.7279;
  90. double Bdown=0.6066;
  91. double Cdown=0.1766;
  92. for (int h=0; h<rgb->height; h++)
  93. {
  94. unsigned char* pGray=(unsigned char*)gray->imageData+h*gray->widthStep;
  95. unsigned char* pRGB=(unsigned char* )rgb->imageData+h*rgb->widthStep;
  96. for (int w=0; w<rgb->width; w++)
  97. {
  98. int s=pRGB[R]+pRGB[G]+pRGB[B];
  99. double r=(double)pRGB[R]/s;
  100. double g=(double)pRGB[G]/s;
  101. double Gup=Aup*r*r+Bup*r+Cup;
  102. double Gdown=Adown*r*r+Bdown*r+Cdown;
  103. double Wr=(r-0.33)*(r-0.33)+(g-0.33)*(g-0.33);
  104. if (g<Gup && g>Gdown && Wr>0.004)
  105. {
  106. *pGray=255;
  107. }
  108. else
  109. {
  110. *pGray=0;
  111. }
  112. pGray++;
  113. pRGB+=3;
  114. }
  115. }
  116. }
  117. void cvThresholdOtsu(IplImage* src, IplImage* dst)
  118. {
  119. int height=src->height;
  120. int width=src->width;
  121. //histogram
  122. float histogram[256]= {0};
  123. for(int i=0; i<height; i++)
  124. {
  125. unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;
  126. for(int j=0; j<width; j++)
  127. {
  128. histogram[*p++]++;
  129. }
  130. }
  131. //normalize histogram
  132. int size=height*width;
  133. for(int i=0; i<256; i++)
  134. {
  135. histogram[i]=histogram[i]/size;
  136. }
  137. //average pixel value
  138. float avgValue=0;
  139. for(int i=0; i<256; i++)
  140. {
  141. avgValue+=i*histogram[i];
  142. }
  143. int threshold;
  144. float maxVariance=0;
  145. float w=0,u=0;
  146. for(int i=0; i<256; i++)
  147. {
  148. w+=histogram[i];
  149. u+=i*histogram[i];
  150. float t=avgValue*w-u;
  151. float variance=t*t/(w*(1-w));
  152. if(variance>maxVariance)
  153. {
  154. maxVariance=variance;
  155. threshold=i;
  156. }
  157. }
  158. cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);
  159. }
  160. void cvSkinOtsu(IplImage* src, IplImage* dst)
  161. {
  162. assert(dst->nChannels==1&& src->nChannels==3);
  163. IplImage* ycrcb=cvCreateImage(cvGetSize(src),8,3);
  164. IplImage* cr=cvCreateImage(cvGetSize(src),8,1);
  165. cvCvtColor(src,ycrcb,CV_BGR2YCrCb);
  166. cvSplit(ycrcb,0,cr,0,0);
  167. cvThresholdOtsu(cr,cr);
  168. cvCopyImage(cr,dst);
  169. cvReleaseImage(&cr);
  170. cvReleaseImage(&ycrcb);
  171. }
  172. void cvSkinYCbCr(IplImage* img, IplImage* mask)
  173. {
  174. CvSize imageSize = cvSize(img->width, img->height);
  175. IplImage *imgY = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
  176. IplImage *imgCr = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
  177. IplImage *imgCb = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
  178. IplImage *imgYCrCb = cvCreateImage(imageSize, img->depth, img->nChannels);
  179. cvCvtColor(img,imgYCrCb,CV_BGR2YCrCb);
  180. cvSplit(imgYCrCb, imgY, imgCr, imgCb, 0);
  181. int y, cr, cb, l, x1, y1, value;
  182. unsigned char *pY, *pCr, *pCb, *pMask;
  183. pY = (unsigned char *)imgY->imageData;
  184. pCr = (unsigned char *)imgCr->imageData;
  185. pCb = (unsigned char *)imgCb->imageData;
  186. pMask = (unsigned char *)mask->imageData;
  187. cvSetZero(mask);
  188. l = img->height * img->width;
  189. for (int i = 0; i < l; i++){
  190. y  = *pY;
  191. cr = *pCr;
  192. cb = *pCb;
  193. cb -= 109;
  194. cr -= 152
  195. ;
  196. x1 = (819*cr-614*cb)/32 + 51;
  197. y1 = (819*cr+614*cb)/32 + 77;
  198. x1 = x1*41/1024;
  199. y1 = y1*73/1024;
  200. value = x1*x1+y1*y1;
  201. if(y<100)    (*pMask)=(value<700) ? 255:0;
  202. else        (*pMask)=(value<850)? 255:0;
  203. pY++;
  204. pCr++;
  205. pCb++;
  206. pMask++;
  207. }
  208. cvReleaseImage(&imgY);
  209. cvReleaseImage(&imgCr);
  210. cvReleaseImage(&imgCb);
  211. cvReleaseImage(&imgYCrCb);
  212. }
  213. void cvSkinYUV(IplImage* src,IplImage* dst)
  214. {
  215. IplImage* ycrcb=cvCreateImage(cvGetSize(src),8,3);
  216. //IplImage* cr=cvCreateImage(cvGetSize(src),8,1);
  217. //IplImage* cb=cvCreateImage(cvGetSize(src),8,1);
  218. cvCvtColor(src,ycrcb,CV_BGR2YCrCb);
  219. //cvSplit(ycrcb,0,cr,cb,0);
  220. static const int Cb=2;
  221. static const int Cr=1;
  222. static const int Y=0;
  223. //IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3);
  224. cvZero(dst);
  225. for (int h=0; h<src->height; h++)
  226. {
  227. unsigned char* pycrcb=(unsigned char*)ycrcb->imageData+h*ycrcb->widthStep;
  228. unsigned char* psrc=(unsigned char*)src->imageData+h*src->widthStep;
  229. unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep;
  230. for (int w=0; w<src->width; w++)
  231. {
  232. if (pycrcb[Cr]>=133&&pycrcb[Cr]<=173&&pycrcb[Cb]>=77&&pycrcb[Cb]<=127)
  233. {
  234. memcpy(pdst,psrc,3);
  235. }
  236. pycrcb+=3;
  237. psrc+=3;
  238. pdst+=3;
  239. }
  240. }
  241. //cvCopyImage(dst,_dst);
  242. //cvReleaseImage(&dst);
  243. }
  244. void cvSkinHSV(IplImage* src,IplImage* dst)
  245. {
  246. IplImage* hsv=cvCreateImage(cvGetSize(src),8,3);
  247. //IplImage* cr=cvCreateImage(cvGetSize(src),8,1);
  248. //IplImage* cb=cvCreateImage(cvGetSize(src),8,1);
  249. cvCvtColor(src,hsv,CV_BGR2HSV);
  250. //cvSplit(ycrcb,0,cr,cb,0);
  251. static const int V=2;
  252. static const int S=1;
  253. static const int H=0;
  254. //IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3);
  255. cvZero(dst);
  256. for (int h=0; h<src->height; h++)
  257. {
  258. unsigned char* phsv=(unsigned char*)hsv->imageData+h*hsv->widthStep;
  259. unsigned char* psrc=(unsigned char*)src->imageData+h*src->widthStep;
  260. unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep;
  261. for (int w=0; w<src->width; w++)
  262. {
  263. if (phsv[H]>=7&&phsv[H]<=29)
  264. {
  265. memcpy(pdst,psrc,3);
  266. }
  267. phsv+=3;
  268. psrc+=3;
  269. pdst+=3;
  270. }
  271. }
  272. //cvCopyImage(dst,_dst);
  273. //cvReleaseImage(&dst);
  274. }

下面是效果图:

测试图片:

Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

下图的贴图依次对应上面的六种方法:

Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

从上面的结果对比图中可以清晰看的,ycrcb+ostu的效果无疑是最好的。其次是rgb和yuv方法。这个图片效果之所以这么好是因为测试图片拍摄的时候背景为白色。然后,遗憾的是,当背景色不纯的时候,比如有红也有黑,效果就很不理想了。实验发现,当背景为纯色,且是白色或黑色时,效果最好。

参考:

http://blog.sina.com.cn/s/blog_9ce5a1b501017otq.html

http://blog.csdn.net/scyscyao/article/details/5468577

http://wenku.baidu.com/view/05c47e03bed5b9f3f90f1ce4.html

http://blog.csdn.net/onezeros/article/details/6136770

--------------------------本掌纹是作者自己的,转载请注明作者yanzi1225627

上一篇:iOS 2.0 版本切入点


下一篇:maven中classpath路径(转)