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

时间:2022-09-02 11:38:02
分类: 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

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

  1. FFmpeg在Android上的移植之第一步

    http://blog.sina.com.cn/s/blog_69a04cf40100x1fr.html 从事多媒体软件开发的人几乎没有不知道FFmpeg的,很多视频播放器都是基于FFmpeg开发的. ...

  2. &period;Net Core 认证系统之基于Identity Server4 Token的JwtToken认证源码解析

    介绍JwtToken认证之前,必须要掌握.Net Core认证系统的核心原理,如果你还不了解,请参考.Net Core 认证组件源码解析,且必须对jwt有基本的了解,如果不知道,请百度.最重要的是你还 ...

  3. 基于Redis缓存的Session共享&lpar;附源码&rpar;

    基于Redis缓存的Session共享(附源码) 在上一篇文章中我们研究了Redis的安装及一些基本的缓存操作,今天我们就利用Redis缓存实现一个Session共享,基于.NET平台的Seesion ...

  4. 基于LNMP的Zabbbix之Zabbix Agent源码详细安装,但不给图

    基于LNMP的Zabbbix之Zabbix Server源码详细安装:http://www.cnblogs.com/losbyday/p/5828547.html wget http://jaist. ...

  5. 在Android上使用ZXing识别条形码&sol;二维码

    越来越多的手机具备自动对焦的拍摄功能,这也意味着这些手机可以具备条码扫描的功能.......手机具备条码扫描的功能,可以优化购物流程,快速存储电子名片(二维码)等. 本文使用ZXing 1.6实现条码 ...

  6. android愤怒小鸟游戏、自定义View、掌上餐厅App、OpenGL自定义气泡、抖音电影滤镜效果等源码

    Android精选源码 精练的范围选择器,范围和单位可以自定义 自定义View做的小鸟游戏 android popwindow选择商品规格颜色尺寸效果源码 实现Android带有锯齿背景的优惠样式源码 ...

  7. Android系统篇之—-编写简单的驱动程序并且将其编译到内核源码中【转】

    本文转载自:大神 通过之前的一篇文章,我们了解了 Android中的Binder机制和远程服务调用 在这篇文章中主要介绍了Android中的应用在调用一些系统服务的时候的原理,那么接下来就继续来介绍一 ...

  8. Java并发包源码学习系列:基于CAS非阻塞并发队列ConcurrentLinkedQueue源码解析

    目录 非阻塞并发队列ConcurrentLinkedQueue概述 结构组成 基本不变式 head的不变式与可变式 tail的不变式与可变式 offer操作 源码解析 图解offer操作 JDK1.6 ...

  9. 【只需3步】Linux php的安装与配置&lbrack;源码安装&rsqb;

    作者小波/QQ463431476欢迎转载! Linux:redhat 6/centos 6 继续上一篇笔记Apache的配置http://www.cnblogs.com/xiaobo-Linux/p/ ...

随机推荐

  1. java中同步嵌套引起的死锁事例代码

    /* 目的:自己写一个由于同步嵌套引起的死锁! 思路:多个线程在执行时,某一时刻,0-Thread绑定了LockA锁,1-Thread绑定了LockB锁! 当0-Thread要去绑定LockB锁时 和 ...

  2. Windows Azure Virtual Network &lpar;10&rpar; 使用Azure Access Control List&lpar;ACL&rpar;设置客户端访问权限

    <Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的China Azure. 我们在创建完Windows Azure Virtual Machi ...

  3. DOM--1 遵循最佳实践

    为重用命名空间而进行规划 (function() { function $(id) { return document.getElementById(id); } function alertNode ...

  4. Ubuntu 14&period;04怎样升级到Ubuntu 14&period;10

    Ubuntu 14.04怎样升级到Ubuntu 14.10     Ubuntu 14.10 Utopic Unicorn 将在10月23日正式发布,9月25日最终测试版本已经发布,Ubuntu 14 ...

  5. linux set

    linux  set 命令 功能说明:设置shell. 语 法:set [+-abCdefhHklmnpPtuvx] 补充说明:用set 命令可以设置各种shell选项或者列 出shell变量.单个选 ...

  6. Exchanger&comma; Changing data between concurrent tasks

    The Java concurrency API provides a synchronization utility that allows the interchange of data betw ...

  7. dp 0-1背包问题

    0-1背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] } f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包 ...

  8. &lbrack;Redux&rsqb; Refactoring the Entry Point

    We will learn how to better separate the code in the entry point to prepare it for adding the router ...

  9. QTP自传之web常用对象

    随着科技的进步,“下载-安装-运行”这经典的三步曲已离我们远去.web应用的高速发展,改变了我们的思维和生活习惯,同时也使web方面的自动化测试越来越重要.今天,介绍一下我对web对象的识别,为以后的 ...

  10. C&num; 利用ReportViewer生成报表

    本文主要是利用微软自带的控件ReportViewer进行报表设计的小例子,仅供学习分享使用,如有不足之处,还请指正. 涉及知识点: ReportViewer :位于Microsoft.Reportin ...