Lily
Lily

Reputation: 3

Finding hand as biggest contour in opencv

I am working on a hand recognition system and I am a beginner. I am trying to detect the hand by finding the biggest contour (i.e the hand) but it draws a rectangle on the whole frame instead on the hand. how can I resolve it?

#include "stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv\cv.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>

using namespace cv;
using namespace std;




int main()
{
VideoCapture cap("pathaka.MP4"); // open the default camera
if (!cap.isOpened())  // check if we succeeded
return -1;

Mat edges;
namedWindow("edges", 1);

int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;

for (;;)
{
    Mat frame;
    cap >> frame; // get a new frame from video
    Mat dst(frame.rows, frame.cols, CV_8UC1, Scalar::all(0));
    cvtColor(frame, edges, CV_BGR2GRAY);
    threshold(edges, edges, 22, 44, THRESH_BINARY);
    GaussianBlur(edges, edges, Size(7, 7), 1.5, 1.5);
//  Canny(edges, edges, thresh, thresh*2, 3);
    int erosion_type = MORPH_ELLIPSE;
    int erosion_size = 0;
    Mat element = getStructuringElement(erosion_type, Size(2 * erosion_size + 1, 2 * erosion_size + 1), Point(erosion_size, erosion_size));
    erode(edges, edges, element);
    dilate(edges, edges, element);

    vector<vector<Point>>contours; //Vector for storing contour
    vector<Vec4i> hierarchy;

    findContours(edges, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); // Find the contours in the image

    for (int i = 0; i< contours.size(); i++) // iterate through each contour. 
    {
        double a = contourArea(contours[i], false);  //  Find the area of contour
        if (a>largest_area){
            largest_area = a;
            largest_contour_index = i;                //Store the index of largest contour
            bounding_rect = boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
        }

    }
    Scalar color(255, 255, 255);
    drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy); // Draw the largest contour using previously stored index.
    rectangle(frame, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);

    imshow("src", frame);
    imshow("largest contour", dst);
    if (waitKey(30) >= 0) break;

}

// the camera will be deinitialized automatically in VideoCapture destructor




return 0;
}

Upvotes: 0

Views: 2422

Answers (1)

Suhyeon Lee
Suhyeon Lee

Reputation: 569

First, cv::findContour() not only fills output contour array but also changes input Mat image. So if you're using findContour() with global source Mat image instance, try findContour(src.clone(), dat, etc..) rather than findContour(src, dat, etc..)

Second, variable 'largest_contour_index' is initialized outside for(;;) loop and set to certain value ONLY IF larger contour appears, so it may cause Array out of bounds error.

So in your code,

largest_contour_index = -1;
largest_area = 0;

findContours(edges.clone(), contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); // Find the contours in the image

for (int i = 0; i< contours.size(); i++) // iterate through each contour. 
{
    double a = contourArea(contours[i], false);  //  Find the area of contour
    if (a>largest_area){
        largest_area = a;
        largest_contour_index = i;                //Store the index of largest contour
        bounding_rect = boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
    }

}

if(largest_contour_index >= 0)
{
    Scalar color(255, 255, 255);
    drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy); // Draw the largest contour using previously stored index.
    rectangle(frame, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);
}


EDITED:
If your image background color is brighter than hand color, cv::findContour() with CV_RETR_CCOMP will detect whole frame first.
Try using CV_RETR_TREE instead.

findContours(edges.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE); // Find the contours in the image

If same thing happens, there are 3 alternatives:

1. Invert the color of your Mat.
Note that this will consume a small amount of time.

cv::cvtColor(edges, edges, CV_BRG2GRAY);   // if your org image is not grayscale
edges = 255-edges;


2. Choose 2nd biggest one.

for (int i = 1; i< contours.size(); i++) // iterate through each contour. 
{...}


3. Ignore if size of a contour is nearly equal to the size of Mat.

int matSize = (edges.rows * edges.cols) * 0.95;  // 95% size of image
.
.
for (int i = 0; i< contours.size(); i++) // iterate through each contour. 
{
    double a = contourArea(contours[i], false);  //  Find the area of contour
    if(a > matSize)    continue;
    .
    .
}

3. Use hierarchy.
I recommend you to use hierarchy, although somewhat complex to use at first.
read this page for using hierarchy

Upvotes: 1

Related Questions