六种方法分别是:基于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文件里增加如下代码:
- INCLUDEPATH += /usr/include/opencv
- LIBS += /usr/lib/libcv.so \
- /usr/lib/libcvaux.so \
- /usr/lib/libcxcore.so \
- /usr/lib/libhighgui.so \
- /usr/lib/libml.so
请看源码:
- #include <iostream>
- #include "cv.h"
- #include "highgui.h"
- void SkinRGB(IplImage* rgb,IplImage* _dst);
- void cvSkinRG(IplImage* rgb,IplImage* gray);
- void cvThresholdOtsu(IplImage* src, IplImage* dst);
- void cvSkinOtsu(IplImage* src, IplImage* dst);
- void cvSkinYCbCr(IplImage* img, IplImage* mask);
- void cvSkinYUV(IplImage* src,IplImage* dst);
- void cvSkinHSV(IplImage* src,IplImage* dst);
- using namespace std;
- // skin region location using rgb limitation
- int main()
- {
- IplImage *srcImg = cvLoadImage("/home/yan/download/testPalm4.jpg", 1);
- IplImage *dstRGB = cvCreateImage(cvGetSize(srcImg), 8, 3);
- IplImage *dstRG = cvCreateImage(cvGetSize(srcImg), 8, 1);
- IplImage* dst_crotsu=cvCreateImage(cvGetSize(srcImg),8,1);
- IplImage* dst_ycbcr=cvCreateImage(cvGetSize(srcImg),8,1);
- IplImage* dst_yuv=cvCreateImage(cvGetSize(srcImg),8,3);
- IplImage* dst_hsv=cvCreateImage(cvGetSize(srcImg),8,3);
- SkinRGB(srcImg, dstRGB);
- cvSaveImage("/home/yan/download/1_dstRGB.jpg", dstRGB);
- cvSkinRG(srcImg, dstRG);
- cvSaveImage("/home/yan/download/2_dstRG.jpg", dstRG);
- cvSkinOtsu(srcImg, dst_crotsu);
- cvSaveImage("/home/yan/download/3_dst_crotsu.jpg", dst_crotsu);
- cvSkinYCbCr(srcImg, dst_ycbcr);
- cvSaveImage("/home/yan/download/4_dst_ycbcr.jpg", dst_ycbcr);
- cvSkinYUV(srcImg, dst_yuv);
- cvSaveImage("/home/yan/download/5_dst_yuv.jpg", dst_yuv);
- cvSkinHSV(srcImg, dst_hsv);
- cvSaveImage("/home/yan/download/6_dst_hsv.jpg", dst_hsv);
- cvNamedWindow("srcImg", 1);
- cvShowImage("srcImg", srcImg);
- cvNamedWindow("dstRGB", 1);
- cvShowImage("dstRGB", dstRGB);
- cvNamedWindow("dstRG", 1);
- cvShowImage("dstRG", dstRG);
- cvNamedWindow("dstcrotsu", 1);
- cvShowImage("dstcrotsu", dst_crotsu);
- cvNamedWindow("dst_ycbcr", 1);
- cvShowImage("dst_ycbcr", dst_ycbcr);
- cvNamedWindow("dst_yuv", 1);
- cvShowImage("dst_yuv", dst_yuv);
- cvNamedWindow("dst_hsv", 1);
- cvShowImage("dst_hsv", dst_hsv);
- cvWaitKey(0);
- cout << "Hello World!" << endl;
- return 0;
- }
- void SkinRGB(IplImage* rgb,IplImage* _dst)
- {
- cout<<"111"<<endl;
- assert(rgb->nChannels==3&& _dst->nChannels==3);
- static const int R=2;
- static const int G=1;
- static const int B=0;
- IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3);
- cvZero(dst);
- for (int h=0;h<rgb->height;h++) {
- unsigned char* prgb=(unsigned char*)rgb->imageData+h*rgb->widthStep;
- unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep;
- for (int w=0;w<rgb->width;w++) {
- if ((prgb[R]>95 && prgb[G]>40 && prgb[B]>20 &&
- prgb[R]-prgb[B]>15 && prgb[R]-prgb[G]>15/*&&
- !(prgb[R]>170&&prgb[G]>170&&prgb[B]>170)*/)||//uniform illumination
- (prgb[R]>200 && prgb[G]>210 && prgb[B]>170 &&
- abs(prgb[R]-prgb[B])<=15 && prgb[R]>prgb[B]&& prgb[G]>prgb[B])//lateral illumination
- ) {
- memcpy(pdst,prgb,3);
- }
- prgb+=3;
- pdst+=3;
- }
- }
- cvCopyImage(dst,_dst);
- cvReleaseImage(&dst);
- }
- void cvSkinRG(IplImage* rgb,IplImage* gray)
- {
- assert(rgb->nChannels==3&&gray->nChannels==1);
- const int R=2;
- const int G=1;
- const int B=0;
- double Aup=-1.8423;
- double Bup=1.5294;
- double Cup=0.0422;
- double Adown=-0.7279;
- double Bdown=0.6066;
- double Cdown=0.1766;
- for (int h=0; h<rgb->height; h++)
- {
- unsigned char* pGray=(unsigned char*)gray->imageData+h*gray->widthStep;
- unsigned char* pRGB=(unsigned char* )rgb->imageData+h*rgb->widthStep;
- for (int w=0; w<rgb->width; w++)
- {
- int s=pRGB[R]+pRGB[G]+pRGB[B];
- double r=(double)pRGB[R]/s;
- double g=(double)pRGB[G]/s;
- double Gup=Aup*r*r+Bup*r+Cup;
- double Gdown=Adown*r*r+Bdown*r+Cdown;
- double Wr=(r-0.33)*(r-0.33)+(g-0.33)*(g-0.33);
- if (g<Gup && g>Gdown && Wr>0.004)
- {
- *pGray=255;
- }
- else
- {
- *pGray=0;
- }
- pGray++;
- pRGB+=3;
- }
- }
- }
- void cvThresholdOtsu(IplImage* src, IplImage* dst)
- {
- int height=src->height;
- int width=src->width;
- //histogram
- float histogram[256]= {0};
- for(int i=0; i<height; i++)
- {
- unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;
- for(int j=0; j<width; j++)
- {
- histogram[*p++]++;
- }
- }
- //normalize histogram
- int size=height*width;
- for(int i=0; i<256; i++)
- {
- histogram[i]=histogram[i]/size;
- }
- //average pixel value
- float avgValue=0;
- for(int i=0; i<256; i++)
- {
- avgValue+=i*histogram[i];
- }
- int threshold;
- float maxVariance=0;
- float w=0,u=0;
- for(int i=0; i<256; i++)
- {
- w+=histogram[i];
- u+=i*histogram[i];
- float t=avgValue*w-u;
- float variance=t*t/(w*(1-w));
- if(variance>maxVariance)
- {
- maxVariance=variance;
- threshold=i;
- }
- }
- cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);
- }
- void cvSkinOtsu(IplImage* src, IplImage* dst)
- {
- assert(dst->nChannels==1&& src->nChannels==3);
- IplImage* ycrcb=cvCreateImage(cvGetSize(src),8,3);
- IplImage* cr=cvCreateImage(cvGetSize(src),8,1);
- cvCvtColor(src,ycrcb,CV_BGR2YCrCb);
- cvSplit(ycrcb,0,cr,0,0);
- cvThresholdOtsu(cr,cr);
- cvCopyImage(cr,dst);
- cvReleaseImage(&cr);
- cvReleaseImage(&ycrcb);
- }
- void cvSkinYCbCr(IplImage* img, IplImage* 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);
- 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++;
- }
- cvReleaseImage(&imgY);
- cvReleaseImage(&imgCr);
- cvReleaseImage(&imgCb);
- cvReleaseImage(&imgYCrCb);
- }
- void cvSkinYUV(IplImage* src,IplImage* dst)
- {
- IplImage* ycrcb=cvCreateImage(cvGetSize(src),8,3);
- //IplImage* cr=cvCreateImage(cvGetSize(src),8,1);
- //IplImage* cb=cvCreateImage(cvGetSize(src),8,1);
- cvCvtColor(src,ycrcb,CV_BGR2YCrCb);
- //cvSplit(ycrcb,0,cr,cb,0);
- static const int Cb=2;
- static const int Cr=1;
- static const int Y=0;
- //IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3);
- cvZero(dst);
- for (int h=0; h<src->height; h++)
- {
- unsigned char* pycrcb=(unsigned char*)ycrcb->imageData+h*ycrcb->widthStep;
- unsigned char* psrc=(unsigned char*)src->imageData+h*src->widthStep;
- unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep;
- for (int w=0; w<src->width; w++)
- {
- if (pycrcb[Cr]>=133&&pycrcb[Cr]<=173&&pycrcb[Cb]>=77&&pycrcb[Cb]<=127)
- {
- memcpy(pdst,psrc,3);
- }
- pycrcb+=3;
- psrc+=3;
- pdst+=3;
- }
- }
- //cvCopyImage(dst,_dst);
- //cvReleaseImage(&dst);
- }
- void cvSkinHSV(IplImage* src,IplImage* dst)
- {
- IplImage* hsv=cvCreateImage(cvGetSize(src),8,3);
- //IplImage* cr=cvCreateImage(cvGetSize(src),8,1);
- //IplImage* cb=cvCreateImage(cvGetSize(src),8,1);
- cvCvtColor(src,hsv,CV_BGR2HSV);
- //cvSplit(ycrcb,0,cr,cb,0);
- static const int V=2;
- static const int S=1;
- static const int H=0;
- //IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3);
- cvZero(dst);
- for (int h=0; h<src->height; h++)
- {
- unsigned char* phsv=(unsigned char*)hsv->imageData+h*hsv->widthStep;
- unsigned char* psrc=(unsigned char*)src->imageData+h*src->widthStep;
- unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep;
- for (int w=0; w<src->width; w++)
- {
- if (phsv[H]>=7&&phsv[H]<=29)
- {
- memcpy(pdst,psrc,3);
- }
- phsv+=3;
- psrc+=3;
- pdst+=3;
- }
- }
- //cvCopyImage(dst,_dst);
- //cvReleaseImage(&dst);
- }
下面是效果图:
测试图片:
下图的贴图依次对应上面的六种方法:
从上面的结果对比图中可以清晰看的,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种肤色分割 源码和效果图的更多相关文章
-
FFmpeg在Android上的移植之第一步
http://blog.sina.com.cn/s/blog_69a04cf40100x1fr.html 从事多媒体软件开发的人几乎没有不知道FFmpeg的,很多视频播放器都是基于FFmpeg开发的. ...
-
.Net Core 认证系统之基于Identity Server4 Token的JwtToken认证源码解析
介绍JwtToken认证之前,必须要掌握.Net Core认证系统的核心原理,如果你还不了解,请参考.Net Core 认证组件源码解析,且必须对jwt有基本的了解,如果不知道,请百度.最重要的是你还 ...
-
基于Redis缓存的Session共享(附源码)
基于Redis缓存的Session共享(附源码) 在上一篇文章中我们研究了Redis的安装及一些基本的缓存操作,今天我们就利用Redis缓存实现一个Session共享,基于.NET平台的Seesion ...
-
基于LNMP的Zabbbix之Zabbix Agent源码详细安装,但不给图
基于LNMP的Zabbbix之Zabbix Server源码详细安装:http://www.cnblogs.com/losbyday/p/5828547.html wget http://jaist. ...
-
在Android上使用ZXing识别条形码/二维码
越来越多的手机具备自动对焦的拍摄功能,这也意味着这些手机可以具备条码扫描的功能.......手机具备条码扫描的功能,可以优化购物流程,快速存储电子名片(二维码)等. 本文使用ZXing 1.6实现条码 ...
-
android愤怒小鸟游戏、自定义View、掌上餐厅App、OpenGL自定义气泡、抖音电影滤镜效果等源码
Android精选源码 精练的范围选择器,范围和单位可以自定义 自定义View做的小鸟游戏 android popwindow选择商品规格颜色尺寸效果源码 实现Android带有锯齿背景的优惠样式源码 ...
-
Android系统篇之—-编写简单的驱动程序并且将其编译到内核源码中【转】
本文转载自:大神 通过之前的一篇文章,我们了解了 Android中的Binder机制和远程服务调用 在这篇文章中主要介绍了Android中的应用在调用一些系统服务的时候的原理,那么接下来就继续来介绍一 ...
-
Java并发包源码学习系列:基于CAS非阻塞并发队列ConcurrentLinkedQueue源码解析
目录 非阻塞并发队列ConcurrentLinkedQueue概述 结构组成 基本不变式 head的不变式与可变式 tail的不变式与可变式 offer操作 源码解析 图解offer操作 JDK1.6 ...
-
【只需3步】Linux php的安装与配置[源码安装]
作者小波/QQ463431476欢迎转载! Linux:redhat 6/centos 6 继续上一篇笔记Apache的配置http://www.cnblogs.com/xiaobo-Linux/p/ ...
随机推荐
-
java中同步嵌套引起的死锁事例代码
/* 目的:自己写一个由于同步嵌套引起的死锁! 思路:多个线程在执行时,某一时刻,0-Thread绑定了LockA锁,1-Thread绑定了LockB锁! 当0-Thread要去绑定LockB锁时 和 ...
-
Windows Azure Virtual Network (10) 使用Azure Access Control List(ACL)设置客户端访问权限
<Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的China Azure. 我们在创建完Windows Azure Virtual Machi ...
-
DOM--1 遵循最佳实践
为重用命名空间而进行规划 (function() { function $(id) { return document.getElementById(id); } function alertNode ...
-
Ubuntu 14.04怎样升级到Ubuntu 14.10
Ubuntu 14.04怎样升级到Ubuntu 14.10 Ubuntu 14.10 Utopic Unicorn 将在10月23日正式发布,9月25日最终测试版本已经发布,Ubuntu 14 ...
-
linux set
linux set 命令 功能说明:设置shell. 语 法:set [+-abCdefhHklmnpPtuvx] 补充说明:用set 命令可以设置各种shell选项或者列 出shell变量.单个选 ...
-
Exchanger, Changing data between concurrent tasks
The Java concurrency API provides a synchronization utility that allows the interchange of data betw ...
-
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 的背包 ...
-
[Redux] Refactoring the Entry Point
We will learn how to better separate the code in the entry point to prepare it for adding the router ...
-
QTP自传之web常用对象
随着科技的进步,“下载-安装-运行”这经典的三步曲已离我们远去.web应用的高速发展,改变了我们的思维和生活习惯,同时也使web方面的自动化测试越来越重要.今天,介绍一下我对web对象的识别,为以后的 ...
-
C# 利用ReportViewer生成报表
本文主要是利用微软自带的控件ReportViewer进行报表设计的小例子,仅供学习分享使用,如有不足之处,还请指正. 涉及知识点: ReportViewer :位于Microsoft.Reportin ...