bool FaceDetector::DetectFaces(const cv::Mat& cropped_img, std::vector<cv::Rect>& faces_front, std::vector<cv::Rect>& faces_profile) const{ cv::Mat cascade_img; std::vector<cv::Rect>::iterator face_it; // create a copy of the image cropped_img.copyTo(cascade_img); // increase contrast of the image normalize(cascade_img, cascade_img, 0, 255, cv::NORM_MINMAX, CV_8UC1); // detect frontal faces classifier_front_.detectMultiScale(cascade_img, faces_front, classifier_front_scale_factor_, classifier_front_min_neighbours_, 0|CV_HAAR_SCALE_IMAGE, classif_front_min_size_); // discard face if its not close to the top of the region, false positive face_it = faces_front.begin(); for ( ; face_it != faces_front.end(); ) { // allowed area is the full width and three times the size of the detected face cv::Rect allowed_area (0, 0, cropped_img.cols, face_it->height * 3); // test if the rectangles intersect if ( !(allowed_area & *face_it).area()) { face_it = faces_front.erase(face_it); }else ++face_it; } // only search profile faces if the frontal face detection failed if (faces_front.empty()) { classifier_profile_.detectMultiScale(cascade_img, faces_profile, classifier_profile_scale_factor_, classifier_profile_min_neighbours_, 0|CV_HAAR_SCALE_IMAGE, classif_profile_min_size_); // discard face if its not close to the top of the region, false positive face_it = faces_profile.begin(); for ( ; face_it != faces_profile.end(); ) { // allowed area is the full width and three times the size of the detected face cv::Rect allowed_area (0, 0, cropped_img.cols, face_it->height * 3); // test if the rectangles intersect if ( !(allowed_area & *face_it).area()) { face_it = faces_profile.erase(face_it); }else ++face_it; } } // if debug mode is active and faces were found if (debug_mode_) { cv::Mat debugImg(cropped_img); for (uint j = 0; j < faces_front.size(); j++) cv::rectangle(debugImg, faces_front[j], cv::Scalar(0, 255, 0), 2, CV_AA); for (uint j = 0; j < faces_profile.size(); j++) cv::rectangle(debugImg, faces_profile[j], cv::Scalar(0, 0, 255), 2, CV_AA); cv::imwrite(debug_folder_ + ed::Entity::generateID().c_str() + "_face_detector.png", debugImg); cv::imshow("Face Detector Output", debugImg); } // return true if a face was found return (!faces_front.empty() || !faces_profile.empty()); }
static bool triangleFits(Triangle2i& triangle,SmartPointer<Texture> rgb,SmartPointer<Texture> alpha,std::set<Box2i>& queue,Color4f color) { XgeDebugAssert(rgb->width==rgb->height); int texturedim=rgb->width; int w=triangle.right(); //width of the triangle (after the projection) int h=triangle.top(); //height of the triangle (after the projection) Box2i allowed_area(Vec2i(1,1),Vec2i(texturedim-2,texturedim-2),0); //try to fitTriangle2i for (std::set<Box2i>::iterator jt=queue.begin();jt!=queue.end() ;jt++) { Box2i box=*jt; Triangle2i candidates[4]= { triangle.scale(+1,+1).translate( box.left(), box.bottom()), //no mirroring triangle.scale(-1,+1).translate(w+box.left(), box.bottom()), //mirror x triangle.scale(+1,-1).translate( box.left(),h+box.bottom()), //mirror y triangle.scale(-1,-1).translate(w+box.left(),h+box.bottom()) //mirror x And mirrory }; if (box.align) { //must start from the top of the area candidates[0]=candidates[0].translate(0,box.top()-candidates[0].top()); candidates[1]=candidates[1].translate(0,box.top()-candidates[1].top()); candidates[2]=candidates[2].translate(0,box.top()-candidates[2].top()); candidates[3]=candidates[3].translate(0,box.top()-candidates[3].top()); } while (candidates[0].right()<box.right()) { //safety check XgeDebugAssert( candidates[0].right()==candidates[1].right() && candidates[1].right()==candidates[2].right() && candidates[2].right()==candidates[3].right()); for (int n=0;n<4;n++) { //first try to triangleRender if (triangleRender(candidates[n],rgb,alpha,color,box,false)) { //store finally in the texture triangleRender(candidates[n],rgb,alpha,color,box,true); //these are the 2 other areas to find for fitting if (box.align) { Box2i box_right(Vec2i(candidates[n].centerx(),candidates[n].bottom()),Vec2i(box.right(),box.top() ),1); Box2i box_down (Vec2i(box.left(),box.bottom()) ,Vec2i(box.right(),candidates[n].bottom()-3),1); if (box_right.isValid() && allowed_area.contains(box_right)) queue.insert(box_right); if (box_down .isValid() && allowed_area.contains(box_down )) queue.insert(box_down ); } else { Box2i box_right(Vec2i(candidates[n].centerx(),box.bottom() ) , Vec2i(box.right(),candidates[n].top()),0); Box2i box_up (Vec2i(box.left(),candidates[n].top()+3 ) , Vec2i(box.right(),box.top() ),0); if (box_right.isValid() && allowed_area.contains(box_right)) queue.insert(box_right); if (box_up .isValid() && allowed_area.contains(box_up )) queue.insert(box_up ); //special case when I do not want to waste space for the first triangle in row if (box.left()==1) { Box2i box_left (Vec2i(box.left(),box.bottom()),Vec2i(candidates[n].centerx(),candidates[n].top()),1); if (box_left.isValid() && allowed_area.contains(box_left)) queue.insert(box_left); } } queue.erase(jt); //modify the triangle and return ok triangle=candidates[n]; return true; } //try a little more to the right (1 pixel) candidates[n]=candidates[n].translate(1,0); } } } //cannot fitTriangle2i in the texture, return false (the triangle has not been modified) return false; }