Search code examples
c++opencvdrawingface-detection

How to extend a drawn line in OpenCV?


I have a project to create a face detection program. One of the requirements is for me to draw a line across the center of the face.

Now the way I have done this is by first drawing a line across the two eyes (by getting each eye's coordinates and using them as line points) and then drawing a perpendicular line to that. This way I can account for face rotation aswell.

However this line is the same length as the line across the eyes. I want this perpendicular line to cut across the entire face if possible. Attached is an example of my output for one the rotated face images. I need the green line to be longer.


Solution

  • unfortunately your image is a jpeg so it has compression artifacts.

    I first tried to extract the line, but that didnt give good angle information, so I use cv::minAreaRect after green area segmentation.

    cv::Mat green;
    cv::inRange(input, cv::Scalar(0,100,0), cv::Scalar(100,255,100),green);
    
    
    // instead of this, maybe try to find contours and choose the right one, if there are more green "objects" in the image
    std::vector<cv::Point2i> locations; 
    cv::findNonZero(green, locations);
    
    // find the used color to draw in same color later
    cv::Vec3d averageColorTmp(0,0,0);
    for(unsigned int i=0; i<locations.size(); ++i)
    {
        averageColorTmp += input.at<cv::Vec3b>(locations[i]);
    }
    averageColorTmp *= 1.0/locations.size();
    
    // compute direction of the segmented region
    cv::RotatedRect line = cv::minAreaRect(locations);
    
    // extract directions:
    cv::Point2f start = line.center;
    cv::Point2f rect_points[4];
    line.points(rect_points);
    cv::Point2f direction1 = rect_points[0] - rect_points[1];
    cv::Point2f direction2 = rect_points[0] - rect_points[3];
    
    // use dominant direction
    cv::Point2f lineWidthDirection;
    lineWidthDirection = (cv::norm(direction1) < cv::norm(direction2)) ? direction1 : direction2;
    double lineWidth = cv::norm(lineWidthDirection);
    cv::Point2f lineLengthDirection;
    lineLengthDirection = (cv::norm(direction1) > cv::norm(direction2)) ? direction1 : direction2;
    lineLengthDirection = 0.5*lineLengthDirection; // because we operate from center;
    
    // input parameter:
    // how much do you like to increase the line size?
    // value of 1.0 is original size
    // value of > 1 is increase of line
    double scaleFactor = 3.0;
    
    // draw the line
    cv::line(input, start- scaleFactor*lineLengthDirection, start+ scaleFactor*lineLengthDirection, cv::Scalar(averageColorTmp[0],averageColorTmp[1],averageColorTmp[2]), lineWidth);
    

    giving this result:

    enter image description here

    This method should be quite robust, IF there is no other green in the image but only the green line. If there are other green parts in the image you should extract contours first and choose the right contour to assign the variable locations