六种方法分别是:基于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. }
    275.  

    下面是效果图:

    测试图片:

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

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

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

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

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

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

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

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

    从上面的结果对比图中可以清晰看的,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