Reputation: 3
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
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