我尝试使用反投影从我的网络摄像头检测视频中的人体皮肤。我使用一个OpenCV的haar级联分类器来检测面部,并使用前额区域生成背投影的直方图,以检测皮肤的其他区域。以下是我到目前为止的结果。下面的结果是我迄今为止最好的,它仍然有很多噪音。我想将整个脸部(以及检测到的所有其他皮肤区域)作为一个大型连接组件,这样我就可以在该区域周围绘制轮廓作为检测到的皮肤。我不知道如何继续,如果有人可以提供建议,代码片段等,我将非常感激。
以下是代码:
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
MatND getHistogram(Mat image);
int lowThreshold = 20;
int highThreshold = 20;
int channels[] = {0, 1}; // HUE & SATURATION
float h_range[] = {0, 179};
float s_range[] = {0, 255};
const float *ranges[] = {h_range, s_range};
Mat capturedFrame, flippedFrame, grayScaleFrame, hsvImage, hueImage, mask, backProjectedImage, grayForContour;
std::vector< std::vector<cv::Point> > contours;
int main(int argc, const char **argv){
CascadeClassifier classifier;
classifier.load("haarcascade_frontalface_alt2.xml");
VideoCapture captureDevice;
captureDevice.open(0);
namedWindow("Webcam Feed");
while(true){
captureDevice >> capturedFrame;
flip(capturedFrame, flippedFrame, 1);
// gray scale for face detection
cvtColor(flippedFrame, grayScaleFrame, CV_BGR2GRAY);
equalizeHist(grayScaleFrame, grayScaleFrame);
// hsv image conversion
cvtColor(flippedFrame, hsvImage, CV_BGR2HSV);
// separate only Hue channel to be used for the Histogram in back projection
hueImage.create(hsvImage.size(), hsvImage.depth());
int ch[] = {0,0};
mixChannels(&hsvImage, 1, &hueImage, 1, ch, 1);
std::vector<Rect> faces; // to store the face found
//find faces and store them in the vector array
classifier.detectMultiScale(grayScaleFrame, faces, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
if ( faces.size() > 0 ){
for (int i = 0; i < faces.size(); i++){
// /* BEGINNING BACKPROJECTION WITH FOREHEAD AS REGION OF INTERST */
float topLeft_X = faces[i].x + faces[i].width/ 4;
float topLeft_Y = faces[i].y + faces[i].height / 16;
float bottomRight_X = topLeft_X + faces[i].width / 2;
float bottomRight_Y = topLeft_Y + faces[i].height/6;
Point roiPt1( topLeft_X, topLeft_Y );
Point roiPt2( bottomRight_X, bottomRight_Y );
Mat faceROI = flippedFrame(cv::Rect( topLeft_X , topLeft_Y, bottomRight_X - topLeft_X, bottomRight_Y - topLeft_Y ));
// namedWindow("ROI");
// imshow("ROI", faceROI);
//draw the rectangle of the region of interst
rectangle(flippedFrame, roiPt1, roiPt2, Scalar(0, 0, 255), 1, 8, 0);
//convert the forehead ROI to hsv
Mat roiHSV;
cvtColor(faceROI, roiHSV, CV_BGR2HSV);
// Get a histogram of the HSV of the ROI
MatND roiHist = getHistogram(roiHSV);
normalize(roiHist, roiHist, 0, 255, NORM_MINMAX, -1, Mat());
// now calculate a backprojection of the hue image
calcBackProject(&hsvImage, 1, channels, roiHist, backProjectedImage, ranges, 1, true);
/* ENDING NEW BACKPROJECTION ATTEMPT */
// Threshold the back projected image
Mat final;
/*
APPLY GAUSSIAN FILTER BEFORE THRESHOLDING with OTSU
*/
Mat blur;
GaussianBlur(backProjectedImage, blur, Size(5, 5),0);
threshold(blur, final, 0,255,THRESH_BINARY+THRESH_OTSU);
// opening
// erode(final, final, MORPH_RECT);
// dilate(final, final, MORPH_RECT);
//show the backprojected image
// namedWindow("Back Projection");
// imshow("Back Projection", backProjectedImage);
namedWindow("Threshold Image after Back Projection");
imshow("Threshold Image after Back Projection", final);
//Drawing the rectangle around the found face
Point facePt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
Point facePt2( faces[i].x, faces[i].y );
rectangle(flippedFrame, facePt1, facePt2, cvScalar(0, 255, 0), 1, 8, 0);
}
}
imshow("Webcam Feed", flippedFrame);
if (waitKey(10) == 27){
break;
}
}
return 0;
}
// Get a histogram of the forehead ROI using the hue and saturation only
MatND getHistogram(Mat image){
MatND hist;
int h_bins = 30;
int s_bins = 32;
int histSize[] = {h_bins, s_bins};
cv::calcHist(&image, 1, channels, Mat(), hist, 2, histSize, ranges);
return hist;
}
以下是我现在的结果: