void WBDetectorImpl::train( const string& pos_samples_path, const string& neg_imgs_path) { vector<Mat> pos_imgs = read_imgs(pos_samples_path); vector<Mat> neg_imgs = sample_patches(neg_imgs_path, 24, 24, pos_imgs.size() * 10); assert(pos_imgs.size()); assert(neg_imgs.size()); int n_features; Mat pos_data, neg_data; Ptr<CvFeatureEvaluator> eval = CvFeatureEvaluator::create(); eval->init(CvFeatureParams::create(), 1, Size(24, 24)); n_features = eval->getNumFeatures(); const int stages[] = {64, 128, 256, 512, 1024}; const int stage_count = sizeof(stages) / sizeof(*stages); const int stage_neg = (int)(pos_imgs.size() * 5); const int max_per_image = 100; const float scales_arr[] = {.3f, .4f, .5f, .6f, .7f, .8f, .9f, 1.0f}; const vector<float> scales(scales_arr, scales_arr + sizeof(scales_arr) / sizeof(*scales_arr)); vector<String> neg_filenames; glob(neg_imgs_path, neg_filenames); for (int i = 0; i < stage_count; ++i) { cerr << "compute features" << endl; pos_data = Mat1b(n_features, (int)pos_imgs.size()); neg_data = Mat1b(n_features, (int)neg_imgs.size()); for (size_t k = 0; k < pos_imgs.size(); ++k) { eval->setImage(pos_imgs[k], +1, 0, boost_.get_feature_indices()); for (int j = 0; j < n_features; ++j) { pos_data.at<uchar>(j, (int)k) = (uchar)(*eval)(j); } } for (size_t k = 0; k < neg_imgs.size(); ++k) { eval->setImage(neg_imgs[k], 0, 0, boost_.get_feature_indices()); for (int j = 0; j < n_features; ++j) { neg_data.at<uchar>(j, (int)k) = (uchar)(*eval)(j); } } boost_.reset(stages[i]); boost_.fit(pos_data, neg_data); if (i + 1 == stage_count) { break; } int bootstrap_count = 0; size_t img_i = 0; for (; img_i < neg_filenames.size(); ++img_i) { cerr << "win " << bootstrap_count << "/" << stage_neg << " img " << (img_i + 1) << "/" << neg_filenames.size() << "\r"; Mat img = imread(neg_filenames[img_i], CV_LOAD_IMAGE_GRAYSCALE); vector<Rect> bboxes; Mat1f confidences; boost_.detect(eval, img, scales, bboxes, confidences); if (confidences.rows > 0) { Mat1i indices; sortIdx(confidences, indices, CV_SORT_EVERY_COLUMN + CV_SORT_DESCENDING); int win_count = min(max_per_image, confidences.rows); win_count = min(win_count, stage_neg - bootstrap_count); Mat window; for (int k = 0; k < win_count; ++k) { resize(img(bboxes[indices(k, 0)]), window, Size(24, 24)); neg_imgs.push_back(window.clone()); bootstrap_count += 1; } if (bootstrap_count >= stage_neg) { break; } } } cerr << "bootstrapped " << bootstrap_count << " windows from " << (img_i + 1) << " images" << endl; } }
Mat skinDetector::detect(Mat captureframe, bool verboseSelect, Mat *skinMask) { verboseOutput=verboseSelect; //if (argc>=1) frame = argv[1]); //if (argc>=2) singleRegionChoice = int(argv[2]); int step = 0; Mat3b frame; // Forcing resize to 640x480 -> all thresholds / pixel filters configured for this size..... // Note returned to original size at end... Size s = captureframe.size(); resize(captureframe,captureframe,Size(640,480)); // CHANGED HERE TO BGR //cvtColor(captureframe, captureframe, CV_RGB2BGR); if (verboseOutput) imshow("Raw Image (A)",captureframe); /* THRESHOLD ON HSV*/ // HSV data -> used to find skin cvtColor(captureframe, frame, CV_BGR2HSV); //cvtColor(captureframe, frame, CV_BGR2HLS); GaussianBlur(frame, frame, Size(imgBlurPixels,imgBlurPixels), 1, 1); //medianBlur(frame, frame, 15); for(int r=0; r<frame.rows; ++r){ for(int c=0; c<frame.cols; ++c) // 0<H<0.25 - 0.15<S<0.9 - 0.2<V<0.95 if( (frame(r,c)[0]>5) && (frame(r,c)[0] < 17) && (frame(r,c)[1]>38) && (frame(r,c)[1]<250) && (frame(r,c)[2]>51) && (frame(r,c)[2]<242) ); // do nothing else for(int i=0; i<3; ++i) frame(r,c)[i] = 0; } if (verboseOutput) imshow("Skin HSV (B)",frame); /* BGR CONVERSION AND THRESHOLD */ Mat1b frame_gray; cvtColor(frame, frame, CV_HSV2BGR); cvtColor(frame, frame_gray, CV_BGR2GRAY); // Adaptive thresholding technique // 1. Threshold data to find main areas of skin adaptiveThreshold(frame_gray,frame_gray,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY_INV,9,1); if (verboseOutput) imshow("Adaptive_threshold (D1)",frame_gray); // 2. Fill in thresholded areas morphologyEx(frame_gray, frame_gray, CV_MOP_CLOSE, Mat1b(imgMorphPixels,imgMorphPixels,1), Point(-1, -1), 2); //GaussianBlur(frame_gray, frame_gray, Size((imgBlurPixels*2)+1,(imgBlurPixels*2)+1), 1, 1); GaussianBlur(frame_gray, frame_gray, Size(imgBlurPixels,imgBlurPixels), 1, 1); // Select single largest region from image, if singleRegionChoice is selected (1) if (singleRegionChoice) { *skinMask = cannySegmentation(frame_gray, -1); } else // Detect each separate block and remove blobs smaller than a few pixels { *skinMask = cannySegmentation(frame_gray, minPixelSize); } // Just return skin Mat frame_skin; captureframe.copyTo(frame_skin,*skinMask); // Copy captureframe data to frame_skin, using mask from frame_ttt // Resize image to original before return resize(frame_skin,frame_skin,s); if (verboseOutput) imshow("Skin segmented",frame_skin); return frame_skin; waitKey(1); }
Mat visionUtils::skinDetect(Mat captureframe, Mat3b *skinDetectHSV, Mat *skinMask, std::vector<int> adaptiveHSV, int minPixelSize, int imgBlurPixels, int imgMorphPixels, int singleRegionChoice, bool displayFaces) { if (adaptiveHSV.size()!=6 || adaptiveHSV.empty()) { adaptiveHSV.clear(); adaptiveHSV.push_back(5); adaptiveHSV.push_back(38); adaptiveHSV.push_back(51); adaptiveHSV.push_back(17); adaptiveHSV.push_back(250); adaptiveHSV.push_back(242); } //int step = 0; Mat3b frameTemp; Mat3b frame; // Forcing resize to 640x480 -> all thresholds / pixel filters configured for this size..... // Note returned to original size at end... Size s = captureframe.size(); cv::resize(captureframe,captureframe,Size(640,480)); if (useGPU) { GpuMat imgGPU, imgGPUHSV; imgGPU.upload(captureframe); cv::cvtColor(imgGPU, imgGPUHSV, CV_BGR2HSV); GaussianBlur(imgGPUHSV, imgGPUHSV, Size(imgBlurPixels,imgBlurPixels), 1, 1); imgGPUHSV.download(frameTemp); } else { cv::cvtColor(captureframe, frameTemp, CV_BGR2HSV); GaussianBlur(frameTemp, frameTemp, Size(imgBlurPixels,imgBlurPixels), 1, 1); } // Potential FASTER VERSION using inRange Mat frameThreshold = Mat::zeros(frameTemp.rows,frameTemp.cols, CV_8UC1); Mat hsvMin = (Mat_<int>(1,3) << adaptiveHSV[0], adaptiveHSV[1],adaptiveHSV[2] ); Mat hsvMax = (Mat_<int>(1,3) << adaptiveHSV[3], adaptiveHSV[4],adaptiveHSV[5] ); inRange(frameTemp,hsvMin ,hsvMax, frameThreshold); frameTemp.copyTo(frame,frameThreshold); /* BGR CONVERSION AND THRESHOLD */ Mat1b frame_gray; // send HSV to skinDetectHSV for return *skinDetectHSV=frame.clone(); cv::cvtColor(frame, frame_gray, CV_BGR2GRAY); // Adaptive thresholding technique // 1. Threshold data to find main areas of skin adaptiveThreshold(frame_gray,frame_gray,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY_INV,9,1); if (useGPU) { GpuMat imgGPU; imgGPU.upload(frame_gray); // 2. Fill in thresholded areas #if CV_MAJOR_VERSION == 2 gpu::morphologyEx(imgGPU, imgGPU, CV_MOP_CLOSE, Mat1b(imgMorphPixels,imgMorphPixels,1), Point(-1, -1), 2); gpu::GaussianBlur(imgGPU, imgGPU, Size(imgBlurPixels,imgBlurPixels), 1, 1); #elif CV_MAJOR_VERSION == 3 //TODO: Check if that's correct Mat element = getStructuringElement(MORPH_RECT, Size(imgMorphPixels, imgMorphPixels), Point(-1, -1)); Ptr<cuda::Filter> closeFilter = cuda::createMorphologyFilter(MORPH_CLOSE, imgGPU.type(), element, Point(-1, -1), 2); closeFilter->apply(imgGPU, imgGPU); cv::Ptr<cv::cuda::Filter> gaussianFilter = cv::cuda::createGaussianFilter(imgGPU.type(), imgGPU.type(), Size(imgMorphPixels, imgMorphPixels), 1, 1); gaussianFilter->apply(imgGPU, imgGPU); #endif imgGPU.download(frame_gray); } else { // 2. Fill in thresholded areas morphologyEx(frame_gray, frame_gray, CV_MOP_CLOSE, Mat1b(imgMorphPixels,imgMorphPixels,1), Point(-1, -1), 2); GaussianBlur(frame_gray, frame_gray, Size(imgBlurPixels,imgBlurPixels), 1, 1); // Select single largest region from image, if singleRegionChoice is selected (1) } if (singleRegionChoice) { *skinMask = cannySegmentation(frame_gray, -1, displayFaces); } else // Detect each separate block and remove blobs smaller than a few pixels { *skinMask = cannySegmentation(frame_gray, minPixelSize, displayFaces); } // Just return skin Mat frame_skin; captureframe.copyTo(frame_skin,*skinMask); // Copy captureframe data to frame_skin, using mask from frame_ttt // Resize image to original before return cv::resize(frame_skin,frame_skin,s); if (displayFaces) { imshow("Skin HSV (B)",frame); imshow("Adaptive_threshold (D1)",frame_gray); imshow("Skin segmented",frame_skin); } return frame_skin; waitKey(1); }