Maksim Pekarev
Maksim Pekarev

Reputation: 33

selection of people's contours

I need to select people from an image. I have an image with some amount of people standing in a row (they don't touch each other). For my goal I used imutils (some functions for image proceessing).

Algorithm for which I work:

I binarized the image, then apply a canny filter, and then I used the function cv::findContours to find the outlines, then sort the outlines from left to right and enumerate them, but it doesn't work with people who have white pieces in clothes, and I get something like this:

result image

How can i solve it? Here is my code:

int main() {
std::cout << "Hello, World!" << std::endl;
sorting_contours();
return 0;}
void sorting_contours() {
    Mat image = imread("6.jpg");
    Mat orig = image.clone();
    Mat gray;
    cvtColor(image, gray, CV_BGR2GRAY);
    threshold(gray, gray, 245, 255, CV_THRESH_BINARY);
    Mat edged = imutils::auto_canny(gray);
    vector<Vec4i> hierarchy;
    vector<vector<Point>> contours;
    cv::findContours(edged, contours, hierarchy, CV_RETR_EXTERNAL,
                     CV_CHAIN_APPROX_SIMPLE);
    vector<Rect> boundRect;
    contours = imutils::sort_contours(contours, boundRect, imutils::SortContoursMethods::left_to_right);
    Mat sortedImage = image.clone();
    for (int i = 0; i < contours.size(); i++) {
        sortedImage = imutils::label_contour(sortedImage, vector<vector<Point> >(1, contours[i]), i,
                                             cv::Scalar(240, 0, 159));
    }
    imshow("left_to_right", sortedImage);
    waitKey(0);

}

Original image:

enter image description here

Result with inverted thresholded image and dilate + erode:

enter image description here

Upvotes: 3

Views: 81

Answers (2)

api55
api55

Reputation: 11420

Your initial code had a couple of mistakes. The first one is that the image expects the source to be white objects in black background, but you have the opposite. This is easily solved by doing:

image =  255 - image; // this is the image you already thresholded

Then it has another problem, it gives you a broken line. That is because you are passing a canny image, which not necessarily has a continuous line. Even more, you use the automatic one, which may be good, but not necessarily perfect. The following example worked for me:

  // load data and threshold it
  cv::Mat image = cv::imread(R"(a.jpg)"), gray;
  cv::cvtColor(image, gray, CV_BGR2GRAY);
  cv::threshold(gray, gray, 210, 255, CV_THRESH_BINARY);
  // invert the image
  gray = 255 - gray;
  // close the gaps this is equivalent to dilate+erode
  cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(9, 9), cv::Point(4, 4));
  cv::morphologyEx(gray, gray, cv::MORPH_CLOSE, element);
  // get the contours
  std::vector<cv::Vec4i> hierarchy;
  std::vector<std::vector<cv::Point>> contours;
  cv::findContours(gray, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
  std::cout << "Found " << contours.size() << " contours" << std::endl;

This returns exactly 4 contours. You may try to adapt your code with this example to fit your needs.

Upvotes: 0

user1196549
user1196549

Reputation:

Only take into account the outer contours in the hierarchy returned by findcontours.

Upvotes: 1

Related Questions