OpenCV下肤色检测代码

合集下载

基于肤色的人脸检测matlab代码

基于肤色的人脸检测matlab代码

基于肤色的人脸检测matlab代码mainclose allclear allclc% 输入图像名字img_name = input('请输入图像名字(图像必须为RGB图像,输入0结束):','s'); % 当输入0时结束while ~strcmp(img_name,'0')% 进行人脸识别facedetection(img_name);img_name = input('请输入图像名字(图像必须为RGB图像,输入0结束):','s'); endfacedetectionfunctionfacedetection(img_name)% 读取RGB图像I = imread(img_name);% 转换为灰度图像gray = rgb2gray(I);% 将图像转化为YCbCr颜色空间YCbCr = rgb2ycbcr(I);% 获得图像宽度和高度heigth = size(gray,1);width = size(gray,2);% 根据肤色模型将图像二值化fori = 1:heigthfor j = 1:widthY = YCbCr(i,j,1);Cb = YCbCr(i,j,2);Cr = YCbCr(i,j,3);if(Y < 80)gray(i,j) = 0;elseif(skin(Y,Cb,Cr) == 1)gray(i,j) = 255;elsegray(i,j) = 0;endendendend% 二值图像形态学处理SE=strel('arbitrary',eye(5));%gray = bwmorph(gray,'erode');% imopen先腐蚀再膨胀gray = imopen(gray,SE);% imclose先膨胀再腐蚀%gray = imclose(gray,SE);imshow(gray);% 取出图片中所有包含白色区域的最小矩形[L,num] = bwlabel(gray,8);STATS = regionprops(L,'BoundingBox'); % 存放经过筛选以后得到的所有矩形块n = 1;result = zeros(n,4);figure,imshow(I);hold on;fori = 1:numbox = STATS(i).BoundingBox;x = box(1); %矩形坐标xy = box(2); %矩形坐标yw = box(3); %矩形宽度wh = box(4); %矩形高度h% 宽度和高度的比例ratio = h/w;ux = uint8(x);uy = uint8(y);ifux> 1ux = ux - 1;endifuy> 1uy = uy - 1;end% 可能是人脸区域的矩形应满足以下条件:% 1、高度和宽度必须都大于20,且矩形面积大于400 % 2、高度和宽度比率应该在范围(0.6,2)内% 3、函数findeye返回值为1if w < 20 || h < 20 || w*h < 400continueelseif ratio < 2 && ratio > 0.6 &&findeye(gray,ux,uy,w,h) == 1 % 记录可能为人脸的矩形区域result(n,:) = [uxuy w h];n = n+1;endend% 对可能是人脸的区域进行标记if size(result,1) == 1 && result(1,1) > 0rectangle('Position',[result(1,1),result(1,2),result(1,3),result(1, 4)],'EdgeColor','r'); else% 如果满足条件的矩形区域大于1则再根据其他信息进行筛选for m = 1:size(result,1)m1 = result(m,1);m2 = result(m,2);m3 = result(m,3);m4 = result(m,4);% 标记最终的人脸区域if m1 + m3 < width && m2 + m4 <heigth< p=""> rectangle('Position',[m1,m2,m3,m4],'EdgeColor','r');endendendfindeye% 判断二值图像中是否含有可能是眼睛的块% bImage----二值图像% x---------矩形左上角顶点X坐标% y---------矩形左上角顶点Y坐标% w---------矩形宽度% h---------矩形长度% 如果有则返回值eye等于1,否则为0function eye = findeye(bImage,x,y,w,h)% 根据矩形相关属性得到二值图像中矩形区域中的数据% 存放矩形区域二值图像信息part = zeros(h,w);% 二值化fori = y:(y+h)for j = x:(x+w)ifbImage(i,j) == 0part(i-y+1,j-x+1) = 255;elsepart(i-y+1,j-x+1) = 0;endendend[L,num] = bwlabel(part,8);% 如果区域中有两个以上的矩形则认为有眼睛ifnum< 2eye = 0;elseeye = 1;endskin% Anil K.Jain提出的基于YCbCr颜色空间的肤色模型% 根据当前点的Cb Cr值判断是否为肤色function result = skin(Y,Cb,Cr)% 参数% a = 25.39;a = 28;% b = 14.03;b=18;ecx = 1.60;ecy = 2.41;sita = 2.53;cx = 109.38;cy = 152.02;xishu = [cos(sita) sin(sita);-sin(sita) cos(sita)];% 如果亮度大于230,则将长短轴同时扩大为原来的1.1倍if(Y > 230)a = 1.1*a;b = 1.1*b;end% 根据公式进行计算Cb = double(Cb);Cr = double(Cr);t = [(Cb-cx);(Cr-cy)];temp = xishu*t;value = (temp(1) - ecx)^2/a^2 + (temp(2) - ecy)^2/b^2; % 大于1则不是肤色,返回0;否则为肤色,返回1if value > 1result = 0;elseresult = 1;end</heigth<>。

OpenCV探索之路(二十七):皮肤检测技术

OpenCV探索之路(二十七):皮肤检测技术

OpenCV探索之路(二十七):皮肤检测技术好久没写博客了,因为最近都忙着赶项目和打比赛==| 好吧,今天我打算写一篇关于使用opencv做皮肤检测的技术总结。

那首先列一些现在主流的皮肤检测的方法都有哪些:1.RGB color space2.Ycrcb之cr分量+otsu阈值化3.YCrCb中133<=Cr<=173 77<=Cb<=1274.HSV中 7<H<20 28<S<256 50<V<2565.基于椭圆皮肤模型的皮肤检测6.opencv自带肤色检测类AdaptiveSkinDetector那我们今天就来一一实现它吧!方法一:基于RGB的皮肤检测根据RGB颜色模型找出定义好的肤色范围内的像素点,范围外的像素点设为黑色。

查阅资料后可以知道,前人做了大量研究,肤色在RGB模型下的范围基本满足以下约束:在均匀光照下应满足以下判别式:R>95 AND G>40 B>20 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>B在侧光拍摄环境下:R>220 AND G>210 AND B>170 AND ABS(R-G)<=15 AND R>B AND G>B既然判别式已经确定了,所以按照判别式写程序就很简单了。

/*基于RGB范围的皮肤检测*/Mat RGB_detect(Mat& img){/*R>95 AND G>40 B>20 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>BORR>220 AND G>210 AND B>170 AND ABS(R-G)<=15 AND R>B AND G>B*/Mat detect = img.clone();detect.setT o(0);if (img.empty() || img.channels() != 3){return detect;}for (int i = 0; i < img.rows; i++){for (int j = 0; j < img.cols; j++){uchar *p_detect = detect.ptr<uchar>(i, j);uchar *p_img = img.ptr<uchar>(i, j);if ((p_img[2] > 95 && p_img[1]>40 && p_img[0] > 20 && (MAX(p_img[0], MAX(p_img[1], p_img[2])) - MIN(p_img[0], MIN(p_img[1], p_img[2])) > 15) &&abs(p_img[2] - p_img[1]) > 15 && p_img[2] > p_img[1] && p_img[1] > p_img[0]) ||(p_img[2] > 200 && p_img[1] > 210 && p_img[0] > 170 && abs(p_img[2] - p_img[1]) <= 15 &&p_img[2] > p_img[0] && p_img[1] > p_img[0])){p_detect[0] = p_img[0];p_detect[1] = p_img[1];p_detect[2] = p_img[2];}}}return detect;}检测效果如下:从检测结果可以看出,皮肤的检测效果并不好,首先皮肤检测的完整性并不高,一些稍微光线不好的区域也没法检测出皮肤来。

OpenCV实现人脸检测功能

OpenCV实现人脸检测功能

OpenCV实现⼈脸检测功能本⽂实例为⼤家分享了OpenCV实现⼈脸检测功能的具体代码,供⼤家参考,具体内容如下1、HAAR级联检测#include <opencv2/opencv.hpp>#include <iostream>using namespace cv;#include <iostream>#include <cstdlib>using namespace std;int main(int artc, char** argv) {face_detect_haar();waitKey(0);return 0;}void face_detect_haar() {CascadeClassifier faceDetector;std::string haar_data_file = "./models/haarcascades/haarcascade_frontalface_alt_tree.xml";faceDetector.load(haar_data_file);vector<Rect> faces;//VideoCapture capture(0);VideoCapture capture("./video/test.mp4");Mat frame, gray;int count=0;while (capture.read(frame)) {int64 start = getTickCount();if (frame.empty()){break;}// ⽔平镜像调整// flip(frame, frame, 1);imshow("input", frame);if (frame.channels() == 4)cvtColor(frame, frame, COLOR_BGRA2BGR);cvtColor(frame, gray, COLOR_BGR2GRAY);equalizeHist(gray, gray);faceDetector.detectMultiScale(gray, faces, 1.2, 1, 0, Size(30, 30), Size(400, 400));for (size_t t = 0; t < faces.size(); t++) {count++;rectangle(frame, faces[t], Scalar(0, 255, 0), 2, 8, 0);}float fps = getTickFrequency() / (getTickCount() - start);ostringstream ss;ss.str("");ss << "FPS: " << fps << " ; inference time: " << time << " ms";putText(frame, ss.str(), Point(20, 20), 0, 0.75, Scalar(0, 0, 255), 2, 8);imshow("haar_face_detection", frame);if (waitKey(1) >= 0) break;}printf("total face: %d\n", count);}2、 DNN⼈脸检测#include <opencv2/dnn.hpp>#include <opencv2/opencv.hpp>using namespace cv;using namespace cv::dnn;#include <iostream>#include <cstdlib>using namespace std;const size_t inWidth = 300;const size_t inHeight = 300;const double inScaleFactor = 1.0;const Scalar meanVal(104.0, 177.0, 123.0);const float confidenceThreshold = 0.7;void face_detect_dnn();void mtcnn_demo();int main(int argc, char** argv){face_detect_dnn();waitKey(0);return 0;}void face_detect_dnn() {//这⾥采⽤tensorflow模型std::string modelBinary = "./models/dnn/face_detector/opencv_face_detector_uint8.pb"; std::string modelDesc = "./models/dnn/face_detector/opencv_face_detector.pbtxt";// 初始化⽹络dnn::Net net = readNetFromTensorflow(modelBinary, modelDesc);net.setPreferableBackend(DNN_BACKEND_OPENCV);net.setPreferableTarget(DNN_TARGET_CPU);if (net.empty()){printf("Load models fail...\n");return;}// 打开摄像头// VideoCapture capture(0);VideoCapture capture("./video/test.mp4");if (!capture.isOpened()) {printf("Don't find video...\n");return;}Mat frame;int count=0;while (capture.read(frame)) {int64 start = getTickCount();if (frame.empty()){break;}// ⽔平镜像调整// flip(frame, frame, 1);imshow("input", frame);if (frame.channels() == 4)cvtColor(frame, frame, COLOR_BGRA2BGR);// 输⼊数据调整Mat inputBlob = blobFromImage(frame, inScaleFactor,Size(inWidth, inHeight), meanVal, false, false);net.setInput(inputBlob, "data");// ⼈脸检测Mat detection = net.forward("detection_out");vector<double> layersTimings;double freq = getTickFrequency() / 1000;double time = net.getPerfProfile(layersTimings) / freq;Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>()); ostringstream ss;for (int i = 0; i < detectionMat.rows; i++){// 置信度 0~1之间float confidence = detectionMat.at<float>(i, 2);if (confidence > confidenceThreshold){count++;int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * frame.cols);int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);Rect object((int)xLeftBottom, (int)yLeftBottom,(int)(xRightTop - xLeftBottom),(int)(yRightTop - yLeftBottom));rectangle(frame, object, Scalar(0, 255, 0));ss << confidence;std::string conf(ss.str());std::string label = "Face: " + conf;int baseLine = 0;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom - labelSize.height),Size(labelSize.width, labelSize.height + baseLine)),Scalar(255, 255, 255), FILLED);putText(frame, label, Point(xLeftBottom, yLeftBottom),FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));}}float fps = getTickFrequency() / (getTickCount() - start);ss.str("");ss << "FPS: " << fps << " ; inference time: " << time << " ms";putText(frame, ss.str(), Point(20, 20), 0, 0.75, Scalar(0, 0, 255), 2, 8);imshow("dnn_face_detection", frame);if (waitKey(1) >= 0) break;}printf("total face: %d\n", count);}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

OpenCV学习笔记人脸检测的代码分析

OpenCV学习笔记人脸检测的代码分析

OpenCV学习笔记人脸检测的代码分析一、预备知识:1、动态内存存储及操作函数CvMemStoragetypedef struct CvMemStorage{struct CvMemBlock* bottom;/* first allocated block */struct CvMemBlock* top; /* the current memory block - top of the stack */struct CvMemStorage* parent; /* borrows new blocks from */int block_size; /* block size */int free_space; /* free space in the top block (in bytes) */} CvMemStorage;内存存储器是一个可用来存储诸如序列,轮廓,图形,子划分等动态增长数据结构的底层结构。

它是由一系列以同等大小的内存块构成,呈列表型---bottom 域指的是列首,top 域指的是当前指向的块但未必是列尾.在bottom和top之间所有的块(包括bottom, 不包括top)被完全占据了空间;在top和列尾之间所有的块(包括块尾,不包括top)则是空的;而top 块本身则被占据了部分空间-- free_space 指的是top块剩余的空字节数。

新分配的内存缓冲区(或显示的通过cvMemStorageAlloc 函数分配,或隐示的通过cvSeqPush, cvGraphAddEdge等高级函数分配)总是起始于当前块(即top块)的剩余那部分,如果剩余那部分能满足要求(够分配的大小)。

分配后,free_space 就减少了新分配的那部分内存大小,外加一些用来保存适当列型的附加大小。

当top块的剩余空间无法满足被分配的块(缓冲区)大小时,top块的下一个存储块被置为当前块(新的top块)-- free_space 被置为先前分配的整个块的大小。

Opencv之人脸检测

Opencv之人脸检测

Opencv之人脸检测如之前所说的,运动物体检测的工作已经告一段落了,目前正式进入无所事事的阶段。

也罢,索性就Opencv进一步学习。

这里,就不得不说一下,百度确实是一个强大的工具。

我自学Opencv的资料都来自于网上,图书馆借来的书基本上都是冷宫状态。

为什么呢?用户体验感呗。

不得不喷一下,书上的理论公式啥的,哪对得上我这急性子的胃口啊!这里,推荐几个人的博客给大家,这些资料对于要从Opencv的角度学习图像处理的童鞋应该还是很有帮助的。

1、/index.php/%e9%a6%96%e9%a1%b52、/blog/morewindows/82257833、/column/details/opencv-tutorial.html这三个网站上有部分内容将会重复出现,但只要仔细观察,会发现每位博主的重点都不一样,毕竟每个人编程过程中遇到的问题都不同。

好了,讲讲人脸识别吧,我其实对于这项新起的技术没有多学术化的认识。

结合这次项目中的进度:检测出了运动物体,把它提取出来,再进行人脸检测判断是否为人类,如果是,进行跟踪判断其行为是否异常。

所以我也有必要了解它。

刚开始对于这项功能的实现还是很期待的,总觉得人的属性那么复杂,要想这么立竿见影的对它进行技术约束,应该很不容易。

结果,强大的opencv让这项功能的实现难度指数将至负。

且不说这个,他检测的结果也真是让人哭笑不得。

这里附上一图吧。

1.蓝色圆圈示意出的区域即为系统检测到的“人脸”,我初看到这个结果也甚是惊讶,难道这项技术就是把人脸的五官做成相对坐标进行备份,设置一系列阈值即可。

虽然,我的猜测有点剑走偏锋,但并不是没有依据。

因为之前我用“奶茶妹”卖萌的一张照片做检测,因为其脸是横着地,就是那种依偎在东哥肩膀上的姿势,可能这种脸的姿势违背了Opencv对于人脸五官相对坐标的分布,所以,可怜的奶茶妹没有被人脸检测出来。

(虽然事先我一直以为是长的太萌就,,,技术失效),看来是我想多了。

肤色分割人脸检测matlab代码

肤色分割人脸检测matlab代码

image = imread('im.jpg');figure,imshow(image);red = double(image(:,:,1));green = double(image(:,:,2));blue = double(image(:,:,3));[m n]=size(red);Y = zeros(m,n);Cb = zeros(m,n);Cr = zeros(m,n);I = zeros(m,n);Q = zeros(m,n);red_gama = zeros(m,n);green_gama = zeros(m,n);blue_gama = zeros(m,n);for i=1:m %gamma矫正for j=1:nif red(i,j)>0 && red(i,j)<90fai=pi*red(i,j)/180;gama=1+0.5*cos(fai);red_gama(i,j)=255*(red(i,j)/255)^(1/gama);elseif red(i,j)>=90 && red(i,j)<=170fai=pi/2;gama=1+0.5*cos(fai);red_gama(i,j)=255*(red(i,j)/255)^(1/gama);elseif red(i,j)>170 && red(i,j)<=255fai=pi-pi*(255-red(i,j))/170;gama=1+0.5*cos(fai);red_gama(i,j)=255*(red(i,j)/255)^(1/gama);endif green(i,j)>0 && green(i,j)<90fai=pi*green(i,j)/180;gama=1+0.5*cos(fai);green_gama(i,j)=255*(green(i,j)/255)^(1/gama);elseif green(i,j)>=90 && green(i,j)<=170fai=pi/2;gama=1+0.5*cos(fai);green_gama(i,j)=255*(green(i,j)/255)^(1/gama);elseif green(i,j)>170 && green(i,j)<=255fai=pi-pi*(255-green(i,j))/170;gama=1+0.5*cos(fai);green_gama(i,j)=255*(green(i,j)/255)^(1/gama);endif blue(i,j)>0 && blue(i,j)<90fai=pi*blue(i,j)/180;gama=1+0.5*cos(fai);blue_gama(i,j)=255*(blue(i,j)/255)^(1/gama);elseif blue(i,j)>=90 && blue(i,j)<=170fai=pi/2;gama=1+0.5*cos(fai);blue_gama(i,j)=255*(blue(i,j)/255)^(1/gama);elseif blue(i,j)>170 && blue(i,j)<=255fai=pi-pi*(255-blue(i,j))/170;gama=1+0.5*cos(fai);blue_gama(i,j)=255*(blue(i,j)/255)^(1/gama);endendendfor i=1:mfor j=1:nY(i,j)=0.2989*red_gama(i,j)+0.5866*green_gama(i,j)+0.1145*blue_gama(i,j) ;Cb(i,j)=-0.1688*red_gama(i,j)-0.3312*green_gama(i,j)+0.5000*blue_gama(iCr(i,j)=0.5000*red_gama(i,j)-0.4184*green_gama(i,j)-0.0817*blue_gama(i,j) ;endendemp=zeros(m,n);sita=zeros(m,n);for i=1:mfor j=1:nif Cr(i,j)>0 && Cb(i,j)>0sita(i,j)=atan(abs(Cr(i,j))/abs(Cb(i,j)))*180/pi;elseif Cr(i,j)>0 && Cb(i,j)<0sita(i,j)=180-atan(abs(Cr(i,j))/abs(Cb(i,j)))*180/pi;elseif Cr(i,j)<0 && Cb(i,j)<0sita(i,j)=180 + atan(abs(Cr(i,j))/abs(Cb(i,j)))*180/pi;elsesita(i,j)=0;endendendfor i=1:mfor j=1:nif sita(i,j)>105 && sita(i,j)<150emp(i,j)=sita(i,j);elseemp(i,j)=0;Y(i,j)=0;endendfigure,imshow(emp); figure,imshow(uint8(Y));原图像分割结果分割结果。

OpenCV Haar分类器人脸检测部分代码注释

OpenCV Haar分类器人脸检测部分代码注释

OpenCV Haar分类器人脸检测部分代码注释cvHaarDetectObjectsForROC1 CvSeq*2 cvHaarDetectObjectsForROC( const CvArr* _img,3 CvHaarClassif ie rCascade* cascade, CvMemStorage* storage,4 std::vector<int>& rejectLevels, std::vector<double>& levelWeight s,5 double scaleFactor, int minNeighbors, int flags,6 CvSize minSize, CvSize maxSize, bool outputRejectLevels )7 {8 const double GROUP_EPS = 0.2;9 CvMat stub, *img = (CvMat*)_img;10 cv::Ptr<CvMat> temp, sum, tilted, sqsum, normImg, sumcanny, imgSmall;11 CvSeq* result_seq = 0;12 cv::Ptr<CvMemStorage> temp_storage;1314 cv::ConcurrentRectV ector allCandidates;15 std::vector<cv::Rect> rectList;16 std::vector<int> rweights;17 double factor;18 int coi;19 bool doCanny Pr uning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0;//平滑区域过滤标识20 bool findBiggestObject = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0;//返回最大目标标识21 bool roughSearch = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0;//只返回第一个目标标识2223 //错误24 if( !CV_IS_HAAR_CLASSIFIER(cascade) )25 CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" );2627 if( !storage )28 CV_Error( CV_StsNullPtr, "Null storage pointer" );2930 img = cvGetMat( img, &stub, &coi );31 if( coi )32 CV_Error( CV_BadCOI, "COI is not supported" );3334 if( CV_MA T_DEPTH(img->type) != CV_8U )35 CV_Error( CV_StsUnsupportedFormat, "Only 8-bit images are supported" );3637 if( scaleFactor <= 1 )38 CV_Error( CV_StsOutOfRange, "scale factor must be > 1" );3940 //如果存在查找最大目标属性则去除SCALE_IMAGE属性41 if( findBiggestObject )42 flags &= ~CV_HAAR_SCALE_IMAGE;4344 if( maxSize.height == 0 || maxSize.width == 0 )45 {46 maxSize.height = img->rows;47 maxSize.width = img->cols;48 }4950 temp = cvCreateMat( img->rows, img->cols, CV_8UC1 );51 //注意这里rows+1.cols+1是为了建立一个0值的缓存区以提高计算效率52 sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );//积分图求和的结果53 sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 );//积分图求和的平方的结果5455 if( !cascade->hid_cascade )56 icvCreateHidHaarClassifierCascade(cascade);;//创建级联分类器5758 if( cascade->hid_cascade->has_tilted_features )59 tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );//积分图求和并倾斜45度的结果6061 result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvA vg Com p), storage );//创建用于存放检测结果的数组6263 if( CV_MA T_CN(img->type) > 1 )64 {65 cvCvtColor( img, temp, CV_BGR2GRAY );//灰度处理66 img = temp;67 }68 //如果存在查找最大目标属性则去除SCALE_IMAGE和平滑过滤属性69 if( findBiggestObject )70 flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);7172 //缩放图片而不改变检测窗口大小73 /* if( flags & CV_HAAR_S CALE_IMAGE )74 {75 CvSize winSize0 = cascade->orig_window_size;76 #ifdef HA VE_IP P77 int use_ipp = cascade->hid_cascade->ipp_stages != 0;7879 if( use_ipp )80 normImg = cvCreateMat( img->rows, img->cols, CV_32FC1 );81 #endif82 imgSmall = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 );8384 for( factor = 1; ; factor *= scaleFactor )85 {86 CvSize winSize = { cvRound(winSize0.width*factor),87 cvRound(winSize0.height*factor) };88 CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };89 CvSize sz1 = { sz.width - winSize0.width + 1, sz.height - winSize0.height + 1 };9091 CvRect equRect = { icv_object_win_border, icv_object_win_border,92 winSize0.width - icv_object_win_border*2,93 winSize0.height - icv_object_win_border*2 };9495 CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;96 CvMat* _tilted = 0;9798 if( sz1.width <= 0 || sz1.height <= 0 )99 break;100 if( winSize.width > maxSize.width || winSize.height > maxSize.height )101 break;102 if( winSize.width < minSize.width || winSize.height < minSize.height )103 continue;104105 img1 = cvMat( sz.height, sz.width, CV_8UC1, imgSmall->data.ptr );106 sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );107 sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );108 if( tilted )109 {110 tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );111 _tilted = &tilted1;112 }113 norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, normImg ? normImg->data.ptr : 0 );114 mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );115116 cvResize( img, &img1, CV_INTER_LINEAR );117 cvIntegral( &img1, &sum1, &sqsum1, _tilted );118119 int ystep = factor > 2 ? 1 : 2;120 #ifdef HA VE_TBB121 const int LOCS_PER_THREAD = 1000;122 int stripCount = ((sz1.width/ystep)*(sz1.height + ystep-1)/ystep + LOCS_PER_T HREAD/2)/LOCS_P ER_T HREAD;123 stripCount = std::min(std::max(stripCount, 1), 100);124 #else125 const int stripCount = 1;126 #endif127128 #ifdef HA VE_IPP129 if( use_ipp )130 {131 cv::Mat fsum(sum1.rows, sum1.cols, CV_32F, sum1.data.ptr, sum1.step);132 cv::Mat(&sum1).convertTo(fsum, CV_32F, 1, -(1<<24));133 }134 else135 #endif136 cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. );137138 cv::Mat _norm1(&norm1), _mask1(&mask1);139 cv::parallel_for(cv::BlockedRange(0, stripCount),140 cv::HaarDetectObjects_ScaleImage_Invoker(cascade,141 (((sz1.height + stripCount - 1)/stripCount + ystep-1)/ystep)*ystep,142 factor, cv::Mat(&sum1), cv::Mat(&sqsum1), &_norm1, &_mask1,143 cv::Rect(equRect), allCandidates, rejectLevels, levelWeight s, outputRejectLevels)); 144 }145 }146 else */147 {148 int n_factors = 0;//代表检测窗口有多少种尺寸149 cv::Rect scanROI;//感兴趣区域150151 cvIntegral( img, sum, sqsum, tilted );//积分图计算152153 //存在平滑过滤属性154 if( doCannyPruning )155 {156 sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );157 cvCanny( img, temp, 0, 50, 3 );158 cvIntegral( temp, sumcanny );159 }160161 //得到检测窗口有多少种尺寸,即n_factors值162 for( n_factors = 0, factor = 1;163 factor*cascade->orig_window_size.width < img->cols - 10 &&164 factor*cascade->orig_window_size.height < img->rows - 10;165 n_factors++, factor *= scaleFactor )166 ;167 //初始化检测窗口的比例168 if( findBiggestObject )169 {170 scaleFactor = 1./scaleFactor;171 factor *= scaleFactor;172 }173 else174 factor = 1;175176 for( ; n_factors-- > 0; factor *= scaleFactor )177 {178 const double ystep = std::max( 2., factor );179 //得到新的检测窗口size180 CvSize winSize = { cvRound( cascade->orig_window_size.width * factor ),181 cvRound( cascade->orig_window_size.height * factor )};182 CvRect equRect = { 0, 0, 0, 0 };183 int *p[4] = {0,0,0,0};184 int *pq[4] = {0,0,0,0};185 int startX = 0, startY = 0;186 int endX = cvRound((img->cols - winSize.width) / ystep);187 int endY = cvRound((img->rows - winSize.height) / ystep);188189 //忽略小于最小窗口限制的检测窗口size190 if( winSize.width < minSize.width || winSize.height < minSize.height )191 {192 if( findBiggestObject )193 break;194 continue;195 }196197 //为分类器设置积分图及检测窗口比例198 cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );199 cvZero( temp );200201 if( doCannyPruning )202 {203 equRect.x = cvRound(winSize.width*0.15);204 equRect.y = cvRound(winSize.height*0.15);205 equRect.width = cvRound(winSize.width*0.7);206 equRect.height = cvRound(winSize.height*0.7);207208 p[0] = (int*)(sumcanny->data.ptr + equRect.y*sumcanny->step) + equRect.x;209 p[1] = (int*)(sumcanny->data.ptr + equRect.y*sumcanny->step)210 + equRect.x + equRect.width;211 p[2] = (int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step) + equRect.x; 212 p[3] = (int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step)213 + equRect.x + equRect.width;214215 pq[0] = (int*)(sum->data.ptr + equRect.y*sum->step) + equRect.x;216 pq[1] = (int*)(sum->data.ptr + equRect.y*sum->step)217 + equRect.x + equRect.width;218 pq[2] = (int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step) + equRect.x; 219 pq[3] = (int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step)220 + equRect.x + equRect.width;221 }222223 //根据ROI重置224 if( scanROI.area() > 0 )225 {226 //adjust start_height and stop_height227 startY = cvRound(scanROI.y / ystep);228 endY = cvRound((scanROI.y + scanROI.height - winSize.height) / ystep);229230 startX = cvRound(scanROI.x / ystep);231 endX = cvRound((scanROI.x + scanROI.width - winSize.width) / ystep);232 }233 //parallel_for?并行运算?234 //在当前尺寸下对每一个位置进行分类器的检测235 cv::parallel_for(cv::BlockedRange(startY, endY),236 cv::HaarDetectObjects_ScaleCascade_Invoker(cascade, winSize, cv::Range(startX, endX), 237 ystep, sum->step, (const int**)p,238 (const int**)pq, allCandidates ));239240 if( findBiggestObject && !allCandidates.empty() && scanROI.area() == 0 )241 {242 rectList.resize(allCandidates.size());243 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());244245 groupRectangles(rectList, std::max(minNeighbors, 1), GROUP_EPS);246247 if( !rectList.empty() )248 {249 size_t i, sz = rectList.size();250 cv::Rect maxRect;251252 for( i = 0; i < sz; i++ )253 {254 if( rectList[i].area() > maxRect.area() )255 maxRect = rectList[i];256 }257258 allCandidates.push_back(maxRect);259260 scanROI = maxRect;261 int dx = cvRound(maxRect.width*GROUP_EPS);262 int dy = cvRound(maxRect.height*GROUP_EPS);263 scanROI.x = std::max(scanROI.x - dx, 0);264 scanROI.y = std::max(scanROI.y - dy, 0);265 scanROI.width = std::min(scanROI.width + dx*2, img->cols-1-scanROI.x); 266 scanROI.height = std::min(scanROI.height + dy*2, img->rows-1-scanROI.y); 267268 double minScale = roughSearch ? 0.6 : 0.4;269 minSize.width = cvRound(maxRect.width*minScale);270 minSize.height = cvRound(maxRect.height*minScale);271 }272 }273 }274 }275276 rectList.resize(allCandidates.size());277 if(!allCandidates.empty())278 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());279280 //相邻重复检测区域进行组合281 if( minNeighbors != 0 || findBiggestObject )282 {283 if( outputRejectLevels )284 {285 groupRectangles(rectList, rejectLevels, leve lWeight s, minNeighbors, GROUP_EPS ); 286 }287 else288 {289 groupRectangles(rectList, rweights, std::max(minNeighbors, 1), GROUP_EPS);290 }291 }292 else293 rweights.resize(rectList.size(),0);294295 //获得检测结果296 if( findBiggestObject && rectList.size() )297 {298 CvA vgComp result_comp = {{0,0,0,0},0};299300 for( size_t i = 0; i < rectList.size(); i++ )301 {302 cv::Rect r = rectList[i];303 if( r.area() > cv::Rect(result_comp.rect).area() )304 {305 result_comp.rect = r;306 result_comp.neighbors = rweight s[i];307 }308 }309 cvSeqPush( result_seq, &result_comp );310 }311 else312 {313 for( size_t i = 0; i < rectList.size(); i++ )314 {315 CvA vgComp c;316 c.rect = rectList[i];317 c.neighbors = !rweights.empty() ? rweight s[i] : 0; 318 cvSeqPush( result_seq, &c );319 }320 }321322 return result_seq;。

android java opencv facedetectyn 用法

android java opencv facedetectyn 用法

android java opencv facedetectyn用法在Android平台上使用OpenCV库进行人脸识别是一项涉及多个步骤的任务。

以下是一个关于如何使用OpenCV的Java接口进行人脸检测的基本指南。

1. 导入OpenCV库首先,你需要在你的Android项目中导入OpenCV库。

这通常通过在你的build.gradle 文件中添加依赖来完成。

确保你已经下载并安装了OpenCV的Android SDK。

2. 初始化OpenCV在你的应用程序中,你需要初始化OpenCV库。

这通常在主活动(MainActivity)的onCreate方法中完成。

你可以调用OpenCVLoader.initDebug()来初始化OpenCV库。

3. 加载人脸检测器OpenCV提供了多种人脸检测方法,其中最常见的是Haar特征级联分类器。

你需要加载一个预训练的XML文件,该文件包含了用于人脸检测的特征和参数。

javaCascadeClassifier faceDetector = new CascadeClassifier(getContext().getResources().getIdentifier("lbpcascade_frontal face", "raw", getContext().getPackageName()));if (faceDetector.empty()) {Log.e(TAG, "Failed to load cascade classifier");// 处理加载失败的情况}4. 处理图像接下来,你需要从摄像头或图像库获取图像,并将其转换为OpenCV可以处理的格式(通常是Mat对象)。

5. 进行人脸检测使用加载的人脸检测器在图像上检测人脸。

这通常通过调用detectMultiScale方法完成。

javaMatOfRect faceDetections = new MatOfRect();faceDetector.detectMultiScale(grayImage, faceDetections);其中grayImage是一个灰度图像,因为Haar特征级联分类器通常在灰度图像上运行得更快。

Python+OpenCV人脸检测原理及示例详解

Python+OpenCV人脸检测原理及示例详解

Python+OpenCV⼈脸检测原理及⽰例详解关于opencvOpenCV 是 Intel 开源计算机视觉库 (Computer Version) 。

它由⼀系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉⽅⾯的很多通⽤算法。

OpenCV 拥有包括 300 多个 C 函数的跨平台的中、⾼层 API 。

它不依赖于其它的外部库 —— 尽管也可以使⽤某些外部库。

OpenCV 对⾮商业应⽤和商业应⽤都是免费的。

同时 OpenCV 提供了对硬件的访问,可以直接访问摄像头,并且 opencv 还提供了⼀个简单的 GUI(graphics user interface) 系统 :highgui 。

我们就通过 OpenCV 提供的⼀些⽅法来构造出这个⼈脸检测(face detection)程序来。

opencv的python包装OpenCV 本⾝是有 C/C++ 编写的,如果要在其他语⾔中使⽤,我们可以通过对其动态链接库⽂件进⾏包装即可,幸运的是,Python 下有很多个这样的包装,本⽂中使⽤的是 Cvtypes 。

事实上,在 Python 中很多的包都是来⾃第三⽅的,⽐如 PIL(Python Image Library) 即为 C 语⾔实现的⼀个图形处理包,被包装到了 Python 中,这些包装可以让你像使⽤ Python 的内建函数⼀样的使⽤这些 API 。

⼈脸检测原理⼈脸检测属于⽬标检测(object detection) 的⼀部分,主要涉及两个⽅⾯1.先对要检测的⽬标对象进⾏概率统计,从⽽知道待检测对象的⼀些特征,建⽴起⽬标检测模型。

2.⽤得到的模型来匹配输⼊的图像,如果有匹配则输出匹配的区域,否则什么也不做。

计算机视觉计算机的视觉系统,跟⼈的眼睛是⼤不相同的,但是其中也有类似之处。

⼈眼之能够看到物体,是通过物体上反射出来的光线刺激⼈眼的感光细胞,然后视觉神经在⼤脑中形成物体的像。

计算机通过摄像头看到的东西要简单的多,简单来说,就是⼀堆由数字组成的矩阵。

肤色检测算法

肤色检测算法

肤色检测算法肤色Gaussian模型//rgbImg:输入RGB图像//value:输入阈值(value>0&&value<1)//value描述了某一像素值为肤色的概率//value推荐值使用0.2~0.5//mask:输出二值化图像//涉及矩阵、指数计算,运算量比较大void skinGaussian(Mat& rgbImg,double value,Mat& mask){mask = Mat::zeros(rgbImg.size(), CV_8UC1);Mat imageYcrcb;cvtColor(rgbImg, imageYcrcb, COLOR_BGR2YCrCb);Mat x(2, 1, CV_32FC1);//肤色统计数据Mat u = (Mat_<float>(2, 1) << 117.4361, 156.5599);Mat s = (Mat_<float>(2, 2) << 160.1301, 12.1430,12.1430, 299.4574);//肤色检测for (int i = 0; i < imageYcrcb.rows; i++){for (int j = 0; j < imageYcrcb.cols; j++){Vec3b temp = imageYcrcb.at<Vec3b>(i, j);//读取Cr,Cb值x.at<float>(0, 0) = temp[2];x.at<float>(1, 0) = temp[1];//矩阵运算Mat temp2 = (x - u).t()*s.inv()*(x - u);double samility = exp(temp2.at<float>(0, 0)*(-0.5));if (samility>value){mask.at<uchar>(i, j) = 255;}}}//闭运算,消除二值图像的孔洞Mat kernel = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));morphologyEx(mask, mask, MorphTypes::MORPH_CLOSE, kernel);}肤色椭圆模型//rgbImg:输入的RGB图像//mask:输出的二值化图像,非0区域为检测结果void skinEllipse(Mat& rgbImg,Mat& mask){//初始化掩膜//掩膜:二值化图像,非0区域为保留的感兴趣区域mask = Mat::zeros(rgbImg.size(), CV_8UC1);//RGB->YCrCb,opencv中默认将RGB图像存储为BGRMat YcrcbImg;cvtColor(rgbImg, YcrcbImg, COLOR_BGR2YCrCb);//椭圆肤色模型Mat skinCrCb = Mat::zeros(256, 256, CV_8UC1);ellipse(skinCrCb, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255), -1);//利用椭圆模型进行肤色检测for (int i = 0; i < rgbImg.rows; i++){uchar* p = (uchar*)mask.ptr<uchar>(i);Vec3b* ycrcb = (Vec3b*)YcrcbImg.ptr<Vec3b>(i);for (int j = 0; j < rgbImg.cols; j++){if (skinCrCb.at<uchar>(ycrcb[j][1],ycrcb[j][2])>0){p[j] = 255;}}}//闭运算,消除二值图像的孔洞Mat kernel = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));morphologyEx(mask, mask, MorphTypes::MORPH_CLOSE, kernel);}基于HSV颜色空间的肤色检测//rgbImg:输入的RGB图像//mask:输出的二值化图像,非0区域为检测结果void skinBasedOnHSV(Mat& rgbImg, Mat& mask){//初始化掩膜mask = Mat::zeros(rgbImg.size(), CV_8UC1);//RGB->HSVMat hsvImg;cvtColor(rgbImg, hsvImg, COLOR_BGR2HSV);//HSV分割经验阈值①Scalar hsv_min1(0, 30, 80);Scalar hsv_max1(20, 150, 255);//HSV分割经验阈值②Scalar hsv_min2(0, 10, 60);Scalar hsv_max2(20, 150, 255);//HSV值处于阈值之间的区域保留inRange(hsvImg, hsv_min2, hsv_max2, mask);Mat skinImg;//闭运算,消除二值图像的孔洞Mat kernel = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));morphologyEx(mask, mask, MorphTypes::MORPH_CLOSE, kernel);rgbImg.copyTo(skinImg, mask);}。

OpenCV+python实现人脸检测(基于照片和视频进行检测)

OpenCV+python实现人脸检测(基于照片和视频进行检测)

OpenCV+python实现⼈脸检测(基于照⽚和视频进⾏检测)OpenCV + python 实现⼈脸检测(基于照⽚和视频进⾏检测)Haar-like通俗的来讲,就是作为⼈脸特征即可。

Haar特征值反映了图像的灰度变化情况。

例如:脸部的⼀些特征能由矩形特征简单的描述,如:眼睛要⽐脸颊颜⾊要深,⿐梁两侧⽐⿐梁颜⾊要深,嘴巴⽐周围颜⾊要深等。

opencv api要想使⽤opencv,就必须先知道其能⼲什么,怎么做。

于是API的重要性便体现出来了。

就本例⽽⾔,使⽤到的函数很少,也就普通的读取图⽚,灰度转换,显⽰图像,简单的编辑图像罢了。

如下:读取图⽚只需要给出待操作的图⽚的路径即可。

import cv2image = cv2.imread(imagepath)灰度转换灰度转换的作⽤就是:转换成灰度的图⽚的计算强度得以降低。

import cv2gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)画图opencv 的强⼤之处的⼀个体现就是其可以对图⽚进⾏任意编辑,处理。

下⾯的这个函数最后⼀个参数指定的就是画笔的⼤⼩。

import cv2cv2.rectangle(image,(x,y),(x+w,y+w),(0,255,0),2)显⽰图像编辑完的图像要么直接的被显⽰出来,要么就保存到物理的存储介质。

import cv2cv2.imshow("Image Title",image)获取⼈脸识别训练数据看似复杂,其实就是对于⼈脸特征的⼀些描述,这样opencv在读取完数据后很据训练中的样品数据,就可以感知读取到的图⽚上的特征,进⽽对图⽚进⾏⼈脸识别。

import cv2face_cascade = cv2.CascadeClassifier(r'./haarcascade_frontalface_default.xml')⾥卖弄的这个xml⽂件,就是opencv在GitHub上共享出来的具有普适的训练好的数据。

手把手:用OpenCV亲手给小扎、Musk等科技大佬们做一张“平均脸”(附Python代码)

手把手:用OpenCV亲手给小扎、Musk等科技大佬们做一张“平均脸”(附Python代码)

作者:SAT Y A M AL L IC K编译:HAP P EN、C hl o e、钱天培请紧盯这张照片5秒钟,你能否看出任何异样呢?照片中的女性同时拥有白人血统、西班牙人血统、亚洲人血统以及印度人血统。

她皮肤光彩无暇,眼神扑朔迷离,似乎美得不真实。

她并不真实存在,但她也并非完全虚构。

创造她的正是文摘菌今天要介绍的一项黑科技——“平(d a)均(zho ng)脸”。

文摘菌今天的手把手专栏将为大家介绍,如何用O p e n CV随心所欲帮各种人组合“平均脸”。

完整的p yt ho n代码可在后台回复“平均脸”获取。

让我们先来看两张文摘菌好奇的平均脸。

成功男性科技界企业家平均脸长什么样?下图是小扎,马斯克,拉里·佩奇,和杰夫·贝索斯的平均脸。

杰夫·贝索斯似乎拉低了发量平均值,不过幸好这张平均脸并没有全秃。

小扎,马斯克,拉里·佩奇,和杰夫·贝索斯的平均脸奥斯卡最佳女主角平均脸又长什么样呢?下图为布丽·拉尔森,朱丽安·摩尔,凯特·布兰切特,詹妮弗·劳伦斯的平均脸。

这张平均脸真是非常迷人了!她的牙齿比企业家平均脸洁白整齐得多。

一点也不意外!近四届奥斯卡最佳女主角:布丽·拉尔森,朱丽安·摩尔,凯特·布兰切特,詹妮弗·劳伦斯的平均脸最后,文摘菌还用平均脸生成了一张文摘家主编大大们的平均脸,翻到文末看大大们的颜值哦~“平均脸”的历史为何平均脸的颜值看起来如此之高?在进入代码实操之前,让我们先来简单了解一下平均脸的历史。

“平均脸”源于达尔文的堂兄F ra nc i s G a l t o n在1878年提出的一种新的摄影技术——通过对准眼睛来合成人脸。

他认为,通过生成罪犯的平均脸,人们就可以根据面部特征来预测一个人是否是罪犯。

很显然,他的假设是错误的——你不能通过照片来预测一个人是否是罪犯。

pythonopencv肤色检测的实现示例

pythonopencv肤色检测的实现示例
效果
2 YCrCb颜 色 空 间 的 Cr分 量 +Otsu法 阈 值 分 割 算 法
原理 针对YCRCB中CR分量的处ቤተ መጻሕፍቲ ባይዱ,将RGB转换为YCRCB,对CR通道单独进行otsu处理,otsu方法opencv里用threshold 代码
def cr_otsu(image): """YCrCb颜色空间的Cr分量+Otsu阈值分割 :param image: 图片路径 :return: None """ img = cv2.imread(image, cv2.IMREAD_COLOR) ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB) (y, cr, cb) = cv2.split(ycrcb) cr1 = cv2.GaussianBlur(cr, (5, 5), 0) _, skin = cv2.threshold(cr1,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) dWindow("image raw", cv2.WINDOW_NORMAL) cv2.imshow("image raw", img) dWindow("image CR", cv2.WINDOW_NORMAL) cv2.imshow("image CR", cr1) dWindow("Skin Cr+OTSU", cv2.WINDOW_NORMAL) cv2.imshow("Skin Cr+OTSU", skin) dst = cv2.bitwise_and(img, img, mask=skin) dWindow("seperate", cv2.WINDOW_NORMAL) cv2.imshow("seperate", dst) cv2.waitKey()

MATLAB人脸识别源代码

MATLAB人脸识别源代码

MATLAB人脸识别源代码% FaceRec.m %CQUPT% PCA 识别率88%% calc xmean,sigma and its eigen decompositionallsamples=[];%所有训练图片for i=1:40for j=1:5a=imread(strcat('e:\ORL\s',num2str(i),'\',num2str(j),'.pgm'));b=a(1:112*92); %b是行矢量1*N,N=10304,提取顺序是先列后行,%即从上到下,从左到右b=double(b);allsamples=[allsamples;b]; %allsamples是一个M*N矩阵,allsamples中每一行数据代%表一张图片,其中M=200endendsamplemean=mean(allsamples); %平均图片,1*N for i=1:200xmean(i,:)=allsamples(i,:)-samplemean; %allsamples是一个M*N矩阵,allsamples中每一行保存的数据是“每个图片数据—平均图片”end;%获取特征植及特征向量sigma=xmean*xmean'; % M* M矩阵[v d]=eig(sigma);d1=diag(d);%按特征值大小以降序排列dsort=flipud(d1);vsort=fliplr(v);%以下选择90%的能量dsum=sum(dsort);dsum_extract=0;p=0;while(dsum_extract/dsum<0.9) p=p+1;dsum_extract=sum(dsort(1:p)); endi=1;% (训练阶段)计算特征脸形成的坐标系base = xmean' * vsort(:,1:p) * diag(dsort(1:p).^(-1/2));%base是N*p阶矩阵,除以dsort(i) ^(-1/2))是对人脸图象的标准化(是其方差为1)% xmean' * vsort(:,1:p)是小矩阵的特征向量向大矩阵特征向量转换的过程%以下两行将训练样本对坐标系上进行投影,得到一个M*p子空间中的一个点,%即在子空间中的组合系数allcoor=allsamples*base;accu = 0; %下面的人脸识别过程中就是利用这些组合系数来进行识别%测试过程for i=1:40for j=6:10 %读入40 x 5 副测试图像a=imread(strcat('e:\ORL\s',num2str(i),'\',num2str(j),'.pgm'));b=a(1:10304);b=double(b);tcoor=b*base; %计算坐标,是1*p阶矩阵for k=1:200mdist(k)=norm(tcoor-allcoor(k,:)); end;%三阶近邻[dist,index2]=sort(mdist); class1=floor( (index2(1)-1)/5 )+1;class2=floor((index2(2)-1)/5)+1;class3=floor((index2(3)-1)/5)+1; if class1~=class2 && class2~=class3 class=class1;elseif class1==class2class=class1;elseif class2==class3class=class2;end;if class==iaccu=accu+1;end;end;end;accuracy=accu/200 % 输出识别率% FaceRec.m %CQUPT% PCA 识别率88%% calc xmean,sigma and its eigen decompositionallsamples=[]; %所有训练图片for i=1:40for j=1:5a=imread(strcat('e:\ORL\s',num2str(i),'\',num2str(j),'.pgm'));b=a(1:112*92); %b是行矢量1*N,N=10304,提取顺序是先列后行,%即从上到下,从左到右b=double(b);allsamples=[allsamples;b]; %allsamples是一个M*N矩阵,allsamples中每一行数据代%表一张图片,其中M=200endendsamplemean=mean(allsamples); %平均图片,1*Nfor i=1:200 xmean(i,:)=allsamples(i,:)-samplemean; %allsamples是一个M*N矩阵,allsamples中每一行保存 %的数据是“每个图片数据—平均图片” end;%获取特征植及特征向量sigma=xmean*xmean'; % M* M矩阵 [v d]=eig(sigma); d1=diag(d);%按特征值大小以降序排列dsort=flipud(d1); vsort=fliplr(v); %以下选择90%的能量dsum=sum(dsort);dsum_extract=0;p=0;while(dsum_extract/dsum<0.9) p=p+1;dsum_extract=sum(dsort(1:p)); endp=199;% (训练阶段)计算特征脸形成的坐标系base = xmean' * vsort(:,1:p) * diag(dsort(1:p).^(-1/2));%生成特征脸for(k=1:p)temp=reshape(base(:,k),112,92); newpath=[…e:\test\? int2str(k)….jpg?];imwrite(mat2gray(temp), newpath); end%将模型保存Save(…e:\ORL\model.mat? ,?base?, …samplemean?);%Reconstruct.m % CQUPTFunction[]=reconstruct() Load e:\ORL\model.mat;%计算新图片在特征子空间中的系数Img=?D:\test2\10.jpg?A=imread(img);b=a(1:112*92); % b是行矢量 1*N,其中N =10304 b=double(b);b=b-samplemean;c = b * base; % c 是图片 a在子空间中的系数, 是 1*p 行矢量 % 根据特征系数及特征脸重建图% 前15 个t = 15;temp = base(:,1:t) * c(1:t)'; temp = temp + samplemean';imwrite(mat2gray(reshape(temp, 112,92)),'d:\test2\t1.jpg');% 前50个t = 50;temp = base(:,1:t) * c(1:t)'; temp = temp + samplemean';imwrite(mat2gray(reshape(temp, 112,92)),'d:\test2\t2.jpg');% 前 100个t = 100;temp = base(:,1:t) * c(1:t)'; temp = temp + samplemean';imwrite(mat2gray(reshape(temp, 112,92)),'d:\test2\t3.jpg');% 前150个t = 150;temp = base(:,1:t) * c(1:t)'; temp = temp + samplemean';imwrite(mat2gray(reshape(temp, 112,92)),'d:\test2\t4.jpg');% 前199 个t = 199;temp = base(:,1:t) * c(1:t)'; temp = temp + samplemean';imwrite(mat2gray(reshape(temp, 112,92)),'d:\test2\t5.jpg');图片标准化通常是一个整体概念,要求把图片归一到均值为0,方差为1的情况下。

图像用opencv的肤色区域提取

图像用opencv的肤色区域提取

图像用opencv的肤色区域提取#include#include#include#include#include#includeIplImage secaipingheng(IplImage* seping);//色彩平衡IplImage fusesiran(IplImage* fusi);//肤色似然int main(int argc, char *argv[]){IplImage* img = 0; // 原图IplImage* seping = 0;//色彩平衡IplImage* ycbcr = 0;//ycbcrIplImage* fusi = 0;//肤色似然CvCapture * pCapture =NULL;IplImage* fu = 0;//肤色cvNamedWindow("原图", 0);cvResizeWindow("原图",200,200);cvMoveWindow("原图",400,400);cvNamedWindow("肤色图", 0);cvResizeWindow("肤色图",200,200); cvMoveWindow("肤色图",615,400); cvNamedWindow("色彩平衡", CV_WINDOW_AUTOSIZE);cvNamedWindow("肤色6", 0);//cvWaitKey(0);if (argc ==1){ if( !(pCapture = cvCaptureFromCAM(-1))){fprintf(stderr, "Can not open camera.\n");return -2;}}//打开视频文件if(argc == 2){if( !(pCapture = cvCaptureFromFile(argv[1]))){fprintf(stderr, "Can not open video file %s\n", argv[1]); return -2;}}int nFrmNum=0;//逐帧读取视频while(img = cvQueryFrame( pCapture )){nFrmNum++;if(nFrmNum==1){seping=cvCreateImage(cvSize(img->width,img->height),IPL _DEPTH_8U,3);ycbcr=cvCreateImage(cvSize(img->width,img->height),IPL_ DEPTH_8U,3);fusi=cvCreateImage(cvSize(img->width,img->height),IPL_D EPTH_8U,1);}cvShowImage("原图", img );fu=cvCreateImage(cvSize(img->width,img->height),IPL_DE PTH_8U,3);*seping=secaipingheng(img);cvShowImage("色彩平衡",seping);cvSmooth(seping, seping,CV_MEDIAN ,3,0,0,0 );cvCvtColor(seping, ycbcr, CV_RGB2YCrCb);// rgb->ycrcb*fusi=fusesiran(ycbcr);cvShowImage("肤色6",fusi );/* int height,width,step,channels;uchar *data;height = img->height;width = img->width;step = img->widthStep;channels = img->nChannels;data = (uchar *)img->imageData;int i,j;for(i=0;i{if(((fusi->imageData + fusi->widthStep*i))[j]==0) {data[i*step+j*channels+0]=0;data[i*step+j*channels+1]=0;data[i*step+j*channels+2]=0;}}cvShowImage("肤色图", img );*///cvSaveImage("haha.jpg", img);//if(cvWaitKey(2)>=0){break;}}cvDestroyWindow( "原图" );//销毁窗口cvDestroyWindow( "肤色图" );//销毁窗口cvDestroyWindow( "色彩平衡" );//销毁窗口cvReleaseImage( &seping ); //释放图像cvDestroyWindow( "肤色似然" );//销毁窗口cvReleaseImage( &fusi ); //释放图像cvDestroyWindow( "肤色6" );//销毁窗口return 1;}///////////////////////////////////色彩平衡//////////////////////////////////////////////////////IplImage secaipingheng( IplImage* seping){IplImage* dst;//色彩平衡IplImage* gray;//gray图dst=cvCreateImage(cvSize(seping->width,seping->height),IPL_DEPTH_8U,3);gray=cvCreateImage(cvSize(seping->width,seping->height) ,IPL_DEPTH_8U,1);int height,width,step,channels;uchar *data,*data1;height = seping->height;width = seping->width;step = seping->widthStep;channels = seping->nChannels;data = (uchar *)seping->imageData;data1 = (uchar *)dst->imageData;int i,j;double R,G,B,Gy,aR,aG,aB;cvZero(dst);CvMat* MR=cvCreateMat(height,width,CV_64FC1);CvMat* MG=cvCreateMat(height,width,CV_64FC1);CvMat* MB=cvCreateMat(height,width,CV_64FC1);for(i=0;i{R=data[i*step+j*channels+0];G=data[i*step+j*channels+1];B=data[i*step+j*channels+2];Gy=((gray->imageData + gray->widthStep*i))[j]; cvmSet(MR,i,j,R);cvmSet(MG,i,j,G);cvmSet(MB,i,j,B);((gray->imageData + gray->widthStep*i))[j]=(R+G+B)/3; }CvScalar argR,argG,argB;double argI;argR=cvAvg(MR,0);argG=cvAvg(MG,0);argB=cvAvg(MB,0);argI=(argR.val[0]+argG.val[0]+argB.val[0])/3;aR=argI/argR.val[0];aG=argI/argG.val[0];aB=argI/argB.val[0];for(i=0;i{R=CV_MAT_ELEM(*MR,double,i,j)*aR;G=CV_MAT_ELEM(*MG,double,i,j)*aG;B=CV_MAT_ELEM(*MB,double,i,j)*aB;if(R>255)data1[i*step+j*channels+0]=255;else data1[i*step+j*channels+0]=R;if(G>255)data1[i*step+j*channels+1]=255;else data1[i*step+j*channels+1]=G;if(B>255)data1[i*step+j*channels+2]=255;else data1[i*step+j*channels+2]=B;}return *dst;}//////////////////////////////////肤色似然////////////////////////////////////////////////IplImage fusesiran(IplImage* fusi){IplImage* dst;//肤色图dst=cvCreateImage(cvSize(fusi->width,fusi->height),IPL_DE PTH_8U,1);int height,width,step,channels;uchar *data;height = fusi->height;width = fusi->width;step = fusi->widthStep;channels = fusi->nChannels;data = (uchar *)fusi->imageData;double c[4]={0.0077 ,-0.0041,-0.0041 ,0.0047};CvMat* max=cvCreateMat(height,width,CV_64FC1);//存储肤色概率密度矩阵(数组)CvMat* mat=cvCreateMat(2,2,CV_64FC1);//存储协方差矩阵(逆)CvMat* a=cvCreateMat(1,2,CV_64FC1);//{cb,cr}CvMat* a1=cvCreateMat(2,1,CV_64FC1);//{cb,cr}转至CvMat* res=cvCreateMat(1,1,CV_64FC1);cvInitMatHeader(mat,2,2,CV_64FC1,c);double res1[1]={0};cvInitMatHeader(res,1,1,CV_64FC1,res1);int i,j;double b,r,cb,cr,u;//按照上面的公式进行肤色似然度计算for(i=0;i<height;i++)for(j=0;j<width;j++){b=data[i*step+j*channels+1];//cb 分量r=data[i*step+j*channels+2];//cr 分量cb=b-103.0056;////117.4361cr=r-140.1309;////156.5599double p1[2]={cb,cr};cvInitMatHeader(a,1,2,CV_64FC1,p1);cvMatMulAdd(a,mat,0,a);double p2[2]={cb,cr};/////////////////////////////////////// cvInitMatHeader(a1,2,1,CV_64FC1,p2); cvMatMulAdd(a,a1,0,res);u=CV_MAT_ELEM(*res,double,0,0);u=exp(-0.5*u);cvmSet(max,i,j,u)</width;j++)</height;i++);}double max1=0; //初始化最大值double mm=0;cvMinMaxLoc(max,NULL,&max1,NULL,NULL);//肤色似然度for(i=0;i{mm=CV_MAT_ELEM(*max,double,i,j)/max1;cvmSet(max,i,j,255*mm);((dst->imageData + dst->widthStep*i))[j]=255*mm;}//cvNamedWindow("肤色6", CV_WINDOW_AUTOSIZE); //cvShowImage("肤色6", dst );double n[256],p[256];for(i=0;i<256;i++){n[i]=0;p[i]=0;}int nn;for(i=0;i{nn=int(CV_MAT_ELEM(*max,double,i,j));n[nn]++;}for(i=0;i<256;i++)p[i]=n[i]/(height*width);double q,w0,w1,u0,u1,ut,Q[]={0,0,0,0,0,0,0,0,0,0};int flag=0;for(int m=10;m<=190;m+=20){q=0;w0=0;w1=0;u0=0;u1=0;ut=0;for(i=0;i<=m;i++) w0+=p[i];for(i=m+1;i<=255;i++) w1+=p[i];for(i=0;i<=m;i++) u0+=i*p[i]/w0;for(i=m+1;i<=255;i++) u1+=i*p[i]/w1;for(i=0;i<=255;i++) ut+=i*p[i];q=w0*(u0-ut)*(u0-ut)+w1*(u1-ut)*(u1-ut);if (q<1)q=0;Q[flag]=q;flag++;}double max2=Q[0];j=0;for(i=1;i<=9;i++)if(max2<q[i]){max2=Q[i];j=i;}int yuzhi;yuzhi=20*j;IplImage* dst1;//二值dst1=cvCreateImage(cvSize(fusi->width,fusi->height),IPL_D EPTH_8U,1);IplImage* dst11;//二值dst11=cvCreateImage(cvSize(fusi->width,fusi->height),IPL_ DEPTH_8U,1);cvZero(dst11);cvZero(dst1);for(i=0;i{nn=int(CV_MAT_ELEM(*max,double,i,j));if(nn>yuzhi)((dst1->imageData + dst1->widthStep*i))[j]=255;}CvMemStorage* storage = cvCreateMemStorage(0);CvSeq* contour = 0;cvThreshold( dst1, dst1, 128, 255, CV_THRESH_BINARY );cvDilate( dst1, dst1, NULL, 1 );cvFindContours( dst1, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );double contour_area = 0;for( ; contour != 0; contour = contour->h_next ){contour_area=100*fabs(cvContourArea( contour, CV_WHOLE_SEQ )); //if(contour_area>height*width)//((contour->v_next!=0)&&(contour_area>height*width))//cvDrawContours( dst11, contour, CV_RGB(255,255,255), CV_RGB(255,255,255), 0, CV_FILLED, 8 );}return *dst11;}</q[i])。

OpenCV-Python实现人脸磨皮算法

OpenCV-Python实现人脸磨皮算法

OpenCV-Python实现⼈脸磨⽪算法⼈脸磨⽪是最基础的⼈脸美颜效果。

主要分为祛斑,祛痘,淡化⿊眼圈等步骤。

通过前⾯的学习相信⼤家⼀眼都看得出来我们需要⼲什么才能识别⼈脸磨⽪效果。

因为磨⽪之后,脸部的杂质基本上就没有了,也可以说丢失了细节。

那么肯定需要⽤到滤波函数。

滤波的过程就是把图像的每⼀个像素值输⼊过滤器,得到平滑的图像。

⽽我们常⽤的滤波有均值滤波,⾼斯滤波以及双边滤波三种,到底选⽤那种滤波呢?⾸先,均值滤波会因为是⽤周围像素的平均值代替原像素值,肯定会导致图像过于模糊,所以排除掉。

其次,⾼斯滤波与均值滤波原理类似,只是⾼斯滤波器的模板系数会随着距离模板中⼼的增⼤⽽减⼩,虽然可以减弱图像的模糊程度,但是图像边缘信息会丢失。

那么,只剩⼀个滤波了,也就是双边滤波器。

因为它同时综合了⾼通滤波器和a-截尾均值过滤器的叠加效果,即可以保证图像不是⾮常模糊,也可以保留图像边缘信息。

⽽⼈脸磨⽪原理的步骤分为如下3个步骤:图像滤波图像融合图像锐化因为,不管上⾯3种滤波如何,都会导致⼀定的模糊(只是相对来说谁更优⽽已),所以需要对图像进⾏融合与锐化的操作。

这样,可以保留⼀些图像的细节,以增强图像的真实感。

其中,图像融合使⽤的函数就是cv2.addWeighted()图像加权函数。

融合的是原图与双通滤波后的图像。

最后,图像锐化使⽤的PIL库进⾏操作,使⽤它的ImageEnhance.Sharpness()函数⾃动调节图像的锐度与对⽐度。

实现⼈脸磨⽪效果既然我们已经完全掌握了⼈脸磨⽪的原理。

下⾯,我们来直接实现⼈脸的磨⽪效果,具体的代码如下所⽰:# ⼈脸磨⽪def facial_dermabrasion_effect(fileName):img = cv2.imread(fileName)blur_img = cv2.bilateralFilter(img, 31, 75, 75)#图像融合result_img = cv2.addWeighted(img, 0.3, blur_img, 0.7, 0)cv2.imwrite("58_1.jpg", result_img)image = Image.open("58_1.jpg")# 锐度调节enh_img = ImageEnhance.Sharpness(image)image_sharped = enh_img.enhance(1.5)# 对⽐度调节con_img = ImageEnhance.Contrast(image_sharped)image_con = con_img.enhance(1.15)image_con.save("58_2.jpg")img1 = cv2.imread("58.jpg")img2 = cv2.imread("58_2.jpg")cv2.imshow("1", img1)cv2.imshow("2", img2)cv2.waitKey()cv2.destroyAllWindows()if __name__ == "__main__":facial_dermabrasion_effect("58.jpg")运⾏之后,效果如下:这段代码的参数都是可以调整的,并不是⼀层不变的,感兴趣的读者可以⾃⼰调节参数试试效果,当然⼈脸磨⽪只是看起来⽪肤光滑了。

OpenCV——肤色检测

OpenCV——肤色检测

OpenCV——肤⾊检测⼀、RGB color space检测代码如下:void SkinRGB(IplImage* src,IplImage* dst){//RGB颜⾊空间//均匀照明:R>95,G>40,B>20,R-B>15,R-G>15,R>B%R//侧向照明:R>200,G>210,B>170,R-B<=15,R>B,G>Bint height = src->height, width = src->width, channel = src->nChannels, step = src->widthStep;int b = 0, g = 1, r = 2;cvZero(dst);unsigned char* p_src = (unsigned char*)src->imageData;unsigned char* p_dst = (unsigned char*)dst->imageData;for(int j = 0; j < height; j++){for(int i = 0; i < width; i++){if((p_src[j*step+i*channel+r] > 95 && p_src[j*step+i*channel+g] > 40 && p_src[j*step+i*channel+b] > 20 &&(p_src[j*step+i*channel+r] - p_src[j*step+i*channel+b]) > 15 && (p_src[j*step+i*channel+r] - p_src[j*step+i*channel+g]) > 15) || (p_src[j*step+i*channel+r] > 200 && p_src[j*step+i*channel+g] > 210 && p_src[j*step+i*channel+b] > 170 &&(p_src[j*step+i*channel+r] - p_src[j*step+i*channel+b]) <= 15 && p_src[j*step+i*channel+r] > p_src[j*step+i*channel+b] && p_src[j*step+i*channel+g] > p_src[j*step+i*channel+b]))p_dst[j*width+i]=255;}}}⼆、⼆次多项式模式检测(RG color space)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;}}}三、Ycrcb之cr分量+otsu阈值化原理: a.将RGB图像转换到YCrCb颜⾊空间,提取Cr分量图像b.对Cr做⾃适应⼆值化处理(Ostu法)void cvSkinOtsu(IplImage* src, IplImage* dst){//Cr⾃适应阈值法//IplImage* img_ycrcb=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,3);IplImage* img_cr=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);cvCvtColor(src,img_ycrcb,CV_BGR2YCrCb);cvSplit(img_ycrcb,0,img_cr,0,0);cvThresholdOtsu(img_cr,img_cr);cvCopy(img_cr,dst);cvReleaseImage(&img_ycrcb);cvReleaseImage(&img_cr);}void cvThresholdOtsu(IplImage* src, IplImage* dst){int height=src->height,width=src->width,threshold=0;double histogram[256]={0};double average=0.0,max_variance=0.0,w=0.0,u=0.0;IplImage* temp=cvCreateImage(cvGetSize(src),src->depth,1);if(src->nChannels!=1)cvCvtColor(src,temp,CV_BGR2GRAY);else cvCopy(src,temp);unsigned char* p_temp=(unsigned char*)temp->imageData;//计算灰度直⽅图//for(int j=0;j<height;j++) {for(int i=0;i<width;i++) {histogram[p_temp[j*width+i]]++;}}for(int i=0;i<256;i++)histogram[i]=histogram[i]/(double)(height*width);//计算平局值for(int i=0;i<256;i++)average+=i*histogram[i];for(int i=0;i<256;i++) {w+=histogram[i];u+=i*histogram[i];double t=average*w-u;double variance=t*t/(w*(1-w));if(variance>max_variance) {max_variance=variance;threshold=i;}}cvThreshold(temp,dst,threshold,255,CV_THRESH_BINARY);cvReleaseImage(&temp);}四、OpenCV⾃带肤⾊检测类——CvAdaptiveSkinDetector通过颜⾊阈值分割肤⾊部分,⽪肤检测算法是在HSV空间进⾏。

人脸识别MATLAB代码44267

人脸识别MATLAB代码44267

1、色彩空间转换function [r,g]=rgb_RGB(Ori_Face)R=Ori_Face(:,:,1);G=Ori_Face(:,:,2);B=Ori_Face(:,:,3);R1=im2double(R); % 将uint8型转换成double型G1=im2double(G);B1=im2double(B);RGB=R1+G1+B1;row=size(Ori_Face,1); % 行像素column=size(Ori_Face,2); % 列像素for i=1:rowfor j=1:columnrr(i,j)=R1(i,j)/RGB(i,j);gg(i,j)=G1(i,j)/RGB(i,j);endendrrr=mean(rr);r=mean(rrr);ggg=mean(gg);g=mean(ggg);2、均值与协方差t1=imread('D:\matlab\皮肤库\1、jpg');[r1,g1]=rgb_RGB(t1); t2=imread('D:\matlab\皮肤库\2、jpg');[r2,g2]=rgb_RGB(t2); t3=imread('D:\matlab\皮肤库\3、jpg');[r3,g3]=rgb_RGB(t3); t4=imread('D:\matlab\皮肤库\4、jpg');[r4,g4]=rgb_RGB(t4); t5=imread('D:\matlab\皮肤库\5、jpg');[r5,g5]=rgb_RGB(t5); t6=imread('D:\matlab\皮肤库\6、jpg');[r6,g6]=rgb_RGB(t6); t7=imread('D:\matlab\皮肤库\7、jpg');[r7,g7]=rgb_RGB(t7); t8=imread('D:\matlab\皮肤库\8、jpg');[r8,g8]=rgb_RGB(t8);t9=imread('D:\matlab\皮肤库\9、jpg');[r9,g9]=rgb_RGB(t9);t10=imread('D:\matlab\皮肤库\10、jpg');[r10,g10]=rgb_RGB(t10);t11=imread('D:\matlab\皮肤库\11、jpg');[r11,g11]=rgb_RGB(t11);t12=imread('D:\matlab\皮肤库\12、jpg');[r12,g12]=rgb_RGB(t12);t13=imread('D:\matlab\皮肤库\13、jpg');[r13,g13]=rgb_RGB(t13);t14=imread('D:\matlab\皮肤库\14、jpg');[r14,g14]=rgb_RGB(t14);t15=imread('D:\matlab\皮肤库\15、jpg');[r15,g15]=rgb_RGB(t15);t16=imread('D:\matlab\皮肤库\16、jpg');[r16,g16]=rgb_RGB(t16);t17=imread('D:\matlab\皮肤库\17、jpg');[r17,g17]=rgb_RGB(t17);t18=imread('D:\matlab\皮肤库\18、jpg');[r18,g18]=rgb_RGB(t18);t19=imread('D:\matlab\皮肤库\19、jpg');[r19,g19]=rgb_RGB(t19);t20=imread('D:\matlab\皮肤库\20、jpg');[r20,g20]=rgb_RGB(t20);t21=imread('D:\matlab\皮肤库\21、jpg');[r21,g21]=rgb_RGB(t21);t22=imread('D:\matlab\皮肤库\22、jpg');[r22,g22]=rgb_RGB(t22);t23=imread('D:\matlab\皮肤库\23、jpg');[r23,g23]=rgb_RGB(t23);t24=imread('D:\matlab\皮肤库\24、jpg');[r24,g24]=rgb_RGB(t24);t25=imread('D:\matlab\皮肤库\25、jpg');[r25,g25]=rgb_RGB(t25);t26=imread('D:\matlab\皮肤库\26、jpg');[r26,g26]=rgb_RGB(t26);t27=imread('D:\matlab\皮肤库\27、jpg');[r27,g27]=rgb_RGB(t27);r=cat(1,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18,r19,r20,r21,r22, r23,r24,r25,r26,r27);g=cat(1,g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11,g12,g13,g14,g15,g16,g17,g18,g19,g20 ,g21,g22,g23,g24,g25,g26,g27);m=mean([r,g])n=cov([r,g])3、求质心function [xmean, ymean] = center(bw)bw=bwfill(bw,'holes');area = bwarea(bw);[m n] =size(bw);bw=double(bw);xmean =0; ymean = 0;for i=1:m,for j=1:n,xmean = xmean + j*bw(i,j);ymean = ymean + i*bw(i,j);end;end;if(area==0)xmean=0;ymean=0;elsexmean = xmean/area;ymean = ymean/area;xmean = round(xmean);ymean = round(ymean);end4、求偏转角度function [theta] = orient(bw,xmean,ymean) [m n] =size(bw);bw=double(bw);a = 0;b = 0;c = 0;for i=1:m,for j=1:n,a = a + (j - xmean)^2 * bw(i,j);b = b + (j - xmean) * (i - ymean) * bw(i,j);c = c + (i - ymean)^2 * bw(i,j);end;b = 2 * b;theta = atan(b/(a-c))/2;theta = theta*(180/pi); % 从幅度转换到角度5、找区域边界function [left, right, up, down] = bianjie(A)[m n] = size(A);left = -1;right = -1;up = -1;down = -1;for j=1:n,for i=1:m,if (A(i,j) ~= 0)left = j;break;end;end;if (left ~= -1) break;end;end;for j=n:-1:1,for i=1:m,if (A(i,j) ~= 0)right = j;break;end;end;if (right ~= -1) break;end;for i=1:m,for j=1:n,if (A(i,j) ~= 0)up = i;break;end;end;if (up ~= -1)break;end;end;for i=m:-1:1,for j=1:n,if (A(i,j) ~= 0)down = i;break;end;end;if (down ~= -1)break;end;end;6、求起始坐标function newcoord = checklimit(coord,maxval) newcoord = coord;if (newcoord<1)newcoord=1;end;if (newcoord>maxval)newcoord=maxval;end;7、模板匹配function [ccorr, mfit, RectCoord] = mobanpipei(mult, frontalmodel,ly,wx,cx, cy, angle)frontalmodel=rgb2gray(frontalmodel);model_rot = imresize(frontalmodel,[ly wx],'bilinear'); % 调整模板大小model_rot = imrotate(model_rot,angle,'bilinear'); % 旋转模板[l,r,u,d] = bianjie(model_rot); % 求边界坐标bwmodel_rot=imcrop(model_rot,[l u (r-l) (d-u)]); % 选择模板人脸区域[modx,mody] =center(bwmodel_rot); % 求质心[morig, norig] = size(bwmodel_rot);% 产生一个覆盖了人脸模板的灰度图像mfit = zeros(size(mult));mfitbw = zeros(size(mult));[limy, limx] = size(mfit);% 计算原图像中人脸模板的坐标startx = cx-modx;starty = cy-mody;endx = startx + norig-1;endy = starty + morig-1;startx = checklimit(startx,limx);starty = checklimit(starty,limy);endx = checklimit(endx,limx);endy = checklimit(endy,limy);for i=starty:endy,for j=startx:endx,mfit(i,j) = model_rot(i-starty+1,j-startx+1);end;end;ccorr = corr2(mfit,mult) % 计算相关度[l,r,u,d] = bianjie(bwmodel_rot);sx = startx+l;sy = starty+u;RectCoord = [sx sy (r-1) (d-u)]; % 产生矩形坐标8、主程序clear;[fname,pname]=uigetfile({'*、jpg';'*、bmp';'*、tif';'*、gif'},'Please choose a color picture、、、'); % 返回打开的图片名与图片路径名[u,v]=size(fname);y=fname(v); % 图片格式代表值switch ycase 0errordlg('You Should Load Image 、、、','Warning、、、');case{'g';'G';'p';'P';'f';'F'}; % 图片格式若就是JPG/jpg、BMP/bmp、TIF/tif 或者GIF/gif,才打开I=cat(2,pname,fname);Ori_Face=imread(I);subplot(2,3,1),imshow(Ori_Face);otherwiseerrordlg('You Should Load Image 、、、','Warning、、、');endR=Ori_Face(:,:,1);G=Ori_Face(:,:,2);B=Ori_Face(:,:,3);R1=im2double(R); % 将uint8型转换成double型处理G1=im2double(G);B1=im2double(B);RGB=R1+G1+B1;m=[ 0、4144,0、3174]; % 均值n=[0、0031,-0、0004;-0、0004,0、0003]; % 方差row=size(Ori_Face,1); % 行像素数column=size(Ori_Face,2); % 列像素数for i=1:rowfor j=1:columnif RGB(i,j)==0rr(i,j)=0;gg(i,j)=0;elserr(i,j)=R1(i,j)/RGB(i,j); % rgb归一化gg(i,j)=G1(i,j)/RGB(i,j);x=[rr(i,j),gg(i,j)];p(i,j)=exp((-0、5)*(x-m)*inv(n)*(x-m)'); % 皮肤概率服从高斯分布endendendsubplot(2,3,2);imshow(p); % 显示皮肤灰度图像low_pass=1/9*ones(3);image_low=filter2(low_pass, p); % 低通滤波去噪声subplot(2,3,3);imshow(image_low);% 自适应阀值程序previousSkin2 = zeros(i,j);changelist = [];for threshold = 0、55:-0、1:0、05two_value = zeros(i,j);two_value(find(image_low>threshold)) = 1;change = sum(sum(two_value - previousSkin2));changelist = [changelist change];previousSkin2 = two_value;end[C, I] = min(changelist);optimalThreshold = (7-I)*0、1two_value = zeros(i,j);two_value(find(image_low>optimalThreshold)) = 1; % 二值化subplot(2,3,4);imshow(two_value); % 显示二值图像frontalmodel=imread('E:\我的照片\人脸模板、jpg'); % 读入人脸模板照片FaceCoord=[];imsourcegray=rgb2gray(Ori_Face); % 将原照片转换为灰度图像[L,N]=bwlabel(two_value,8); % 标注二值图像中连接的部分,L为数据矩阵,N为颗粒的个数for i=1:N,[x,y]=find(bwlabel(two_value)==i); % 寻找矩阵中标号为i的行与列的下标bwsegment = bwselect(two_value,y,x,8); % 选择出第i个颗粒numholes = 1-bweuler(bwsegment,4); % 计算此区域的空洞数if (numholes >= 1) % 若此区域至少包含一个洞,则将其选出进行下一步运算RectCoord = -1;[m n] = size(bwsegment);[cx,cy]=center(bwsegment); % 求此区域的质心bwnohole=bwfill(bwsegment,'holes'); % 将洞封住(将灰度值赋为1) justface = uint8(double(bwnohole) 、* double(imsourcegray));% 只在原照片的灰度图像中保留该候选区域angle = orient(bwsegment,cx,cy); % 求此区域的偏转角度bw = imrotate(bwsegment, angle, 'bilinear');bw = bwfill(bw,'holes');[l,r,u,d] =bianjie(bw);wx = (r - l +1); % 宽度ly = (d - u + 1); % 高度wratio = ly/wx % 高宽比if ((0、8<=wratio)&(wratio<=2))% 如果目标区域的高度/宽度比例大于0、8且小于2、0,则将其选出进行下一步运算S=ly*wx; % 计算包含此区域矩形的面积A=bwarea(bwsegment); % 计算此区域面积if (A/S>0、35)[ccorr,mfit, RectCoord] = mobanpipei(justface,frontalmodel,ly,wx, cx,cy, angle);endif (ccorr>=0、6)mfitbw=(mfit>=1);invbw = xor(mfitbw,ones(size(mfitbw)));source_with_hole = uint8(double(invbw) 、* double(imsourcegray));final_image = uint8(double(source_with_hole) + double(mfit));subplot(2,3,5);imshow(final_image); % 显示覆盖了模板脸的灰度图像imsourcegray = final_image;subplot(2,3,6);imshow(Ori_Face); % 显示检测效果图end;if (RectCoord ~= -1)FaceCoord = [FaceCoord; RectCoord];endendendend% 在认为就是人脸的区域画矩形[numfaces x] = size(FaceCoord);for i=1:numfaces,hd = rectangle('Position',FaceCoord(i,:));set(hd, 'edgecolor', 'y');end人脸检测就是人脸识别、人机交互、智能视觉监控等工作的前提。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1.void cvSkinSegment(IplImage* img, IplImage* mask){
2. CvSize imageSize = cvSize(img->width, img->height);
3. IplImage *imgY = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
4. IplImage *imgCr = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
5. IplImage *imgCb = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
6.
7.
8. IplImage *imgYCrCb = cvCreateImage(imageSize, img->depth, img->nChannels
);
9. cvCvtColor(img,imgYCrCb,CV_BGR2YCrCb);
10. cvSplit(imgYCrCb, imgY, imgCr, imgCb, 0);
11.int y, cr, cb, l, x1, y1, value;
12. unsigned char *pY, *pCr, *pCb, *pMask;
13.
14. pY = (unsigned char *)imgY->imageData;
15. pCr = (unsigned char *)imgCr->imageData;
16. pCb = (unsigned char *)imgCb->imageData;
17. pMask = (unsigned char *)mask->imageData;
18. cvSetZero(mask);
19. l = img->height * img->width;
20.for (int i = 0; i < l; i++){
21. y = *pY;
22. cr = *pCr;
23. cb = *pCb;
24. cb -= 109;
25. cr -= 152
26. ;
27. x1 = (819*cr-614*cb)/32 + 51;
28. y1 = (819*cr+614*cb)/32 + 77;
29. x1 = x1*41/1024;
30. y1 = y1*73/1024;
31. value = x1*x1+y1*y1;
32.if(y<100) (*pMask)=(value<700) ? 255:0;
33.else (*pMask)=(value<850)? 255:0;
34. pY++;
35. pCr++;
36. pCb++;
37. pMask++;
38. }
39. cvReleaseImage(&imgY);
40. cvReleaseImage(&imgCr);
41. cvReleaseImage(&imgCb);
42. cvReleaseImage(&imgYCrCb);
43.}
主要原理就是通过在Cb Cr空间上找到一个可以拟合常规肤色分布的椭圆形,然后把在椭圆形区域内的像素点标记为肤色
图1.1 椭圆模板示例
以上插图来源于《一种基于KL变换的椭圆模型肤色检测方法》,具体参数参考的那篇文献时间久远找不到了
以下是代码运行后的效果图
图1.2 运行效果1
图1.3 运行效果2
从上面两图可以看出,在光线条件比较理想的情况下,肤色检测的效果还是不错的(1.2就比1.3效果好),但是对于一些似肤色区域(比如图1.3后面的木质门),还是会被误检,但这是肤色检测无法解决的问题。

关于效果图里面一些类似噪点的部分,可以通过膨胀腐蚀模糊再二值化的方法取得比较圆润的肤色图(就是可以做mask的)
1.cvErode(pSkin, pSkin, NULL, 1);
2.cvDilate(pSkin, pSkin, NULL, 1);
3.cvSmooth(pSkin, pSkin, CV_GAUSSIAN, 21, 0, 0);
4.cvThreshold(pSkin, pSkin,130, 255, CV_THRESH_BINARY);
当然有时候效果也不是特别好,这个要靠自己调参数的。

总体而言,与OpenCV2.0的adapativeskindetector.cpp相比的话,效果要好(其实我改进的代码就是参照里面CvAdaptiveSkinDetector类里的process函数的),当然也有可能是因为我的肤色检测是根据我所处环境的光照条件和摄像头特性调节的缘故。

最后,小小地对代码作一个说明。

其实代码很简单,就是把Y Cb Cr三个通道分开,然后用指针分别对这三个通道的每一个像素进行处理。

需要作修改的就是if(y<100) (*pMask)=(value<700) ? 255:0; else (*pMask)=(value<850)? 255:0; 这条做阈值判断的命令
由于光照和摄像头性能的不同,这里的阈值需要根据自己的摄像头调节出最合适的效果才可以
另外的话,对于质量不是很好的WebCam 建议在输入图像上加一个小点的高斯模糊以去除噪点
以上算法还曾经作为我的大作业在Matlab和Xilinx FPGA上实现,具体可以参考我的答辩PPT:Skin Segmentation on FPGA。

相关文档
最新文档