六种方法分别是:基于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
分享到:
相关推荐
毕业设计:基于OpenCV&外部特征的个体鱼识别算法研究 毕业设计:基于OpenCV&外部特征的个体鱼识别算法研究 毕业设计:基于OpenCV&外部特征的个体鱼识别算法研究 毕业设计:基于OpenCV&外部特征的个体鱼识别算法研究 ...
Android:基于OpenCV实现身份证识别(C++)——移植图像算法 原文链接:... 我们要做一个Android上的身份证号码识别功能,在上一篇用OpenCV做了图像处理,本文目标是将我们的C++程序移植到Android程序中。
Python基于OpenCV的人脸识别系统源码.zipPython基于OpenCV的人脸识别系统源码.zipPython基于OpenCV的人脸识别系统源码.zipPython基于OpenCV的人脸识别系统源码.zipPython基于OpenCV的人脸识别系统源码.zipPython基于...
基于OpenCV的视频道路车道检测源码 基于OpenCV的视频道路车道检测源码 基于OpenCV的视频道路车道检测源码 基于OpenCV的视频道路车道检测源码 基于OpenCV的视频道路车道检测源码 基于OpenCV的视频道路车道...
基于MATLAB OpenCv的人脸识别系统源码基于MATLAB OpenCv的人脸识别系统源码基于MATLAB OpenCv的人脸识别系统源码基于MATLAB OpenCv的人脸识别系统源码基于MATLAB OpenCv的人脸识别系统源码基于MATLAB OpenCv的人脸...
研一图像处理期末大作业:基于openCV的人脸识别.zip
Android+OpenCV+人脸识别源码(完整)Android系统调用opencv实现人体识别。可以实现多个人脸的识别
源码实现的功能描述如下:从含有车牌的图像中提取车牌,判断车牌的倾斜程度并矫正,分割出车牌部分,对车牌进行处理后分割车牌字符,通过特征识别字符并输出识别结果。
基于Opencv的车牌分割源码,用于Android 开发,使用jni调用c++,进行车牌分割,代码只有c++部分,在vs调试可用,需要配置opencv环境。
基于opencv的车牌识别源码,亲测可用,包括提前提取车牌区域,字符分割以及字符识别整个车牌识别过程。在提取车牌区域时用过SVM支持向量机来识别,最后的车牌字符识别通过神经网络识别。将两种机器学习算法都用到了...
本资源包含基于C++的OpenCV3.3图像处理源码及素材整理 包含以下源码及用到所有素材文件: 实例1:opencv对单张DCM文件的读取并显示 实例2:opencv读取DCM图像并另存为JPG图像 实例3:opencv批量读取指定路径DCM图像...
基于opencv图像识别的笔迹识别系统源码+教程(毕业设计).zip已获导师指导并通过的高分项目,内附说明书,小白也可操作,也可作为课程设计、期末大作业 包含:项目源码、项目说明等,该项目可以直接作为毕设使用。 ...
Python基于OpenCV和CNN的汉字手写识别系统源码.zip
毕业设计:基于OpenCV全景图像拼接系统的设计与实现(源码 + 数据库 + 说明文档) 2 开发工具及技术 2 2.1 B/S结构的介绍 2 2.2 PYTHON技术的介绍 2 2.3 HTML技术的介绍 2 2.4 MYSQL数据库的介绍 3 2.5 OpenCV技术的...
基于openCV的检测系统源码.zip基于openCV的检测系统源码.zip基于openCV的检测系统源码.zip基于openCV的检测系统源码.zip基于openCV的检测系统源码.zip基于openCV的检测系统源码.zip基于openCV的检测系统源码.zip基于...
1. 完整介绍基于Java的Android OpenCV环境配置 2.实现人脸识别 参考博客:https://blog.csdn.net/weixin_38346042/article/details/124015488?spm=1001.2014.3001.5502
基于opencv实现象棋识别及棋谱定位python源码+数据集(含代码注释)人工智能课程设计.zip 基于opencv实现象棋识别及棋谱定位python源码+数据集(含代码注释)人工智能课程设计.zip基于opencv实现象棋识别及棋谱定位...
用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪人脸,进而对检测到的人脸进行脸部识别的一系列相关技术,通常也叫做人像识别、面部识别 本系统主要基于基于Python的人脸识别。 涉及技术 1....
基于OPENCV的车牌识别系统源码(python课程设计).zip 已获导师指导并通过的97分高分课程大作业项目,代码完整下载可用。 基于OPENCV的车牌识别系统源码(python课程设计).zip 已获导师指导并通过的97分高分课程...
对印刷数字识别。 过程: 1对图片进行灰度化二值化. 2对图片上的数字进行切割 3.制作匹配印刷体数字模板 4.平方和最小原则对数字识别 配置环境: VS2013+,OPENCV2.4.xx都可以(opencv3不支持,可以配置多版本opencv...