void Detection::doFacialComponentsExtractionSide(FaceGeometry& faceGeometry, const std::vector<ContourInfo>& componentContourInfo, const std::vector<ContourInfo>& faceContourInfo) { // we need at least 3 elements (left & right eye, mouth) if (componentContourInfo.size()<1 || faceContourInfo.size()<1) { throw std::exception("we need at least 1 region for classification as eye (side image)"); } const ContourInfo& eye = componentContourInfo[0]; const ContourInfo& face = faceContourInfo[0]; faceGeometry.setDetectedPoint(FaceGeometry::SideEye, cv::Point2d(eye.cogX, eye.cogY)); // find bounding polygon with at least 5 vertices std::vector<cv::Point> polygonPoints; double precission = 50.0; while (polygonPoints.size() < 5) { cv::approxPolyDP(face.contour, polygonPoints, precission, true); precission = precission / 2; } // nose tip is rightmost point (of this polygon) size_t noseIdx = 0; faceGeometry.setDetectedPoint(FaceGeometry::SideNoseTip, cv::Point2d(0, 0)); for (size_t i = 0; i < polygonPoints.size(); ++i) { if (polygonPoints[i].x > faceGeometry.getDetectedPoint(FaceGeometry::SideNoseTip).x) { faceGeometry.setDetectedPoint(FaceGeometry::SideNoseTip, polygonPoints[i]); noseIdx = i; } } // find chin: which direction must be searched for in the polygon? bool incIdx = false; const size_t numPolygonPoints = polygonPoints.size(); if (polygonPoints[(noseIdx + 1) % numPolygonPoints].y > faceGeometry.getDetectedPoint(FaceGeometry::SideNoseTip).y) { incIdx = true; } // search for the following pattern: find a convex and a neighboured concave polygon part under the nose faceGeometry.setDetectedPoint(FaceGeometry::SideChin, cv::Point2d(0, 0)); for (size_t i = noseIdx, j = 0; j<numPolygonPoints; incIdx ? ++i : --i, ++j) { // don't check the nose itself if (j==0) { continue; } // get prev, curr and next point cv::Point prevprev = polygonPoints[(incIdx ? (i - 2) : (i + 2)) % numPolygonPoints]; cv::Point prev = polygonPoints[(incIdx ? (i - 1) : (i + 1)) % numPolygonPoints]; cv::Point curr = polygonPoints[i % numPolygonPoints]; cv::Point next = polygonPoints[(incIdx ? (i + 1) : (i - 1)) % numPolygonPoints]; if (isConcave(prev, curr, next) && !isConcave(prevprev, prev, curr)) { faceGeometry.setDetectedPoint(FaceGeometry::SideChin, prev); break; } } // find back side of head const cv::Point chinPoint = faceGeometry.getDetectedPoint(FaceGeometry::SideChin); cv::Point backPoint; for (int x = 0; x<m_FaceExtracted[sideImgNr].cols; ++x) { if (m_FaceExtracted[sideImgNr].at<unsigned char>(cv::Point(x, chinPoint.y))!=0) { backPoint.x = x; backPoint.y = chinPoint.y; break; } } faceGeometry.setDetectedPoint(FaceGeometry::SideBack, backPoint); // create face mask cv::Mat mask(imgSize, imgSize, CV_8U); mask.setTo(0); cv::drawContours(mask, std::vector<std::vector<cv::Point> > {face.contour}, 0, 255, -1); m_FaceMask.push_back(mask); // show debug info cv::Mat tmp = getCopyOfOriginal(sideImgNr); cv::drawContours(tmp, std::vector<std::vector<cv::Point> > {eye.contour}, 0, cv::Scalar(255, 0, 0), -1); dbgShow(tmp, "doFacialComponentsExtractionSide"); // and the polygon cv::Mat tmpChin = cv::Mat::zeros(imgSize, imgSize, CV_8UC3); cv::drawContours(tmpChin, std::vector<std::vector<cv::Point> > {face.contour}, 0, cv::Scalar(100, 100, 100), -1); cv::RNG rng(0); for (size_t i = 0; i < numPolygonPoints; ++i) { std::cout << "Point: " << polygonPoints[i] << "\n"; cv::line(tmpChin, polygonPoints[i], polygonPoints[(i + 1) % numPolygonPoints], cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 5); } dbgShow(tmpChin, "doFacialComponentsExtractionSide"); }
void Detection::doFacialComponentsExtractionFront(FaceGeometry& faceGeometry, const std::vector<ContourInfo>& componentContourInfo, const std::vector<ContourInfo>& faceContourInfo) { // we need at least 3 elements (left & right eye, mouth) if (componentContourInfo.size()<3 || faceContourInfo.size()<1) { throw std::exception("we need at least 3 regions for classification as left & right eye, mouth (front image)"); } std::vector<ContourInfo> biggestThree(componentContourInfo.begin(), componentContourInfo.begin() + 3); ContourInfo mouth; std::vector<ContourInfo> eyes; for (size_t i = 0; i < biggestThree.size(); ++i) { if (biggestThree[i].cogY > faceContourInfo[0].cogY) { mouth = biggestThree[i]; } else { eyes.push_back(biggestThree[i]); } } // we need at least 3 elements (left & right eye, mouth) if (eyes.size()!=2) { throw std::exception("couldn't identify both eyes"); } // left / right eye ContourInfo leftEye = eyes[0].cogX < eyes[1].cogX ? eyes[0] : eyes[1]; ContourInfo rightEye = eyes[0].cogX > eyes[1].cogX ? eyes[0] : eyes[1]; faceGeometry.setDetectedPoint(FaceGeometry::FrontLeftEye, cv::Point2d(leftEye.cogX, leftEye.cogY)); faceGeometry.setDetectedPoint(FaceGeometry::FrontRightEye, cv::Point2d(rightEye.cogX, rightEye.cogY)); faceGeometry.setDetectedPoint(FaceGeometry::FrontMouth, cv::Point2d(mouth.cogX, mouth.cogY)); // find sides of face (xmin, xmax) const cv::Point eyePos = faceGeometry.getDetectedPoint(FaceGeometry::FrontLeftEye); cv::Point leftCheek, rightCheek; // left for (int x = 0; x<m_FaceExtracted[sideImgNr].cols; ++x) { if (m_FaceExtracted[frontImgNr].at<unsigned char>(cv::Point(x, eyePos.y)) != 0) { leftCheek.x = x; leftCheek.y = eyePos.y; break; } } // right for (int x = m_FaceExtracted[sideImgNr].cols-1; x>=0; --x) { if (m_FaceExtracted[frontImgNr].at<unsigned char>(cv::Point(x, eyePos.y)) != 0) { rightCheek.x = x; rightCheek.y = eyePos.y; break; } } faceGeometry.setDetectedPoint(FaceGeometry::FrontLeftCheek, leftCheek); faceGeometry.setDetectedPoint(FaceGeometry::FrontRightCheek, rightCheek); // create face mask cv::Mat mask(imgSize,imgSize,CV_8U); mask.setTo(0); cv::drawContours(mask, std::vector<std::vector<cv::Point> > {faceContourInfo[0].contour}, 0, 255, -1); m_FaceMask.push_back(mask); // show debug info cv::Mat tmp=getCopyOfOriginal(frontImgNr); cv::drawContours(tmp, std::vector<std::vector<cv::Point> > {leftEye.contour}, 0, cv::Scalar(255, 0, 0), -1); cv::drawContours(tmp, std::vector<std::vector<cv::Point> > {rightEye.contour}, 0, cv::Scalar(0, 255, 0), -1); cv::drawContours(tmp, std::vector<std::vector<cv::Point> > {mouth.contour}, 0, cv::Scalar(0, 0, 255), -1); dbgShow(tmp, "doFacialComponentsExtractionFront"); }