OpenCV contourfinder & convex hulls

Hi all!

I’m working on a project where I need to detect a human
body in front of a white/blue/green wall. I want to create a
map of the posture, so I know where the head, hands and
feet are.

I’m using a webcam, background subtraction based on color (for now),
blob detection using the OpenCV addon (ofxContourFinder), and some custom
code to implement the convex-hull method of opencv.

My idea is to create a convex hull and use the points to detect
hands / face / feet.

** Code to implement the convex hull function of opencv (not cleaned up!) **

  
  
#include "BlobberBlobDistance.h"  
  
BlobberBlobDistance::BlobberBlobDistance() {  
}  
  
void BlobberBlobDistance::update(Blobber* pBlobber) {  
	// Loop through each blob and create a list of the distances.  
	int num_blobs = pBlobber->getContour()->blobs.size();  
	ofxCvBlob curr_blob;  
	int dx,dy,dist;  
	int blob_width, blob_height;  
  
	// Get distance to each point in the blob.  
	for (int i = 0; i < num_blobs; i++) {  
		curr_blob = pBlobber->getContour()->blobs[i];  
		blob_width = curr_blob.boundingRect.width / 2.3;  
		blob_height = curr_blob.boundingRect.height / 2.3;  
		for (int j = 0; j < curr_blob.nPts; j++) {  
			dx = curr_blob.centroid.x - curr_blob.pts[j].x;  
			dy = curr_blob.centroid.y - curr_blob.pts[j].y;  
			dist = sqrt(dx*dx + dy*dy);  
  
			if (dist < blob_width || dist < blob_height) {  
				//continue;  
			}  
		//	cout << "dist:" << dist << ", blob width:" << curr_blob.boundingRect.width << ", blob heght:" << curr_blob.boundingRect.height <<  "\n";  
			DistPoint d;  
			d.pt = curr_blob.pts[j];  
			d.dist = dist;  
			m_distances.push_back(d);  
		}  
	}  
  
  
	// Get peaks.  
	int num_distances = m_distances.size();  
	int span = 4;  
	for (int i = 0; i < num_distances; ++i) {  
		int dist_one = m_distances[i].dist;  
		int dist_two = m_distances[i+span].dist;  
		int dist_three = m_distances[i+(2*span)].dist;  
		// cout << "dist 1,2,3:  " << dist_one << ", " << dist_two << ", " << dist_three << "\n";  
		if (dist_two > dist_one && dist_two > dist_three) {  
			m_peaks.push_back(m_distances[i+span]);  
			// cout << "dist: " << m_distances[i+span].dist << "\n";  
			// draw a dot at this distance.  
			ofCircle(m_distances[i+span].pt.x, m_distances[i+span].pt.y, 1);  
		}  
	}  
  
	// Check what peaks are next to eachother.  
	int num_peaks = m_peaks.size();  
	for (int i = 0; i < num_peaks; i++) {  
		//for (int j = i+1; j < num_peaks;j++) {  
		/*  
			dx = m_peaks[i].pt.x - m_peaks[i+1].pt.x;  
			dy = m_peaks[i].pt.y - m_peaks[i+1].pt.y;  
			dist = sqrt(dx*dx + dy*dy);  
		*/  
			//if (dist > 10) {  
				ofCircle(m_peaks[i].pt.x, m_peaks[i].pt.y, 1);  
			//}  
  
		//}  
	}  
  
  
	//--------------------- opencv convex hull test ------------  
	CvMemStorage* storage = cvCreateMemStorage();  
	CvPoint pt;  
	CvSeq* pt_sequence = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage);  
	CvSeq* hull;  
	int hull_count;  
  
	// Copy the peaks into the point sequence  
	for (int i = 0; i < num_peaks; i++) {  
		pt.x = m_peaks[i].pt.x;  
		pt.y = m_peaks[i].pt.y;  
		cvSeqPush(pt_sequence, &pt);  
	}  
	hull = cvConvexHull2(pt_sequence,0, CV_CLOCKWISE, 0);  
	if (hull) {  
		hull_count = hull->total;  
		//cout << "hull count: " << hull_count << "\n";  
		// Create the list with convex hull points.  
		for (int i = 0; i < hull_count; i++) {  
			CvPoint cv_pt = **CV_GET_SEQ_ELEM(CvPoint*, hull, i);  
			ofPoint of_pt;  
			of_pt.x = cv_pt.x;  
			of_pt.y = cv_pt.y;  
			m_convex_hull.push_back(of_pt);  
  
			// draw the convex hull (tmp)  
			ofSetColor(255,0,0,127);  
			ofCircle(of_pt.x, of_pt.y, 2);  
			ofSetColor(255,255,255);  
		}  
	}  
  
  
	// Clear mem.  
	cvClearMemStorage(storage);  
  
	//-------------------- end opencv convex hull test.  
  
  
  
	//cout << "distances: " << num_distances << " peaks:" << m_peaks.size() << "\n";  
	m_distances.clear();  
	m_peaks.clear();  
	m_convex_hull.clear();  
}  
  
void BlobberBlobDistance::init(Blobber *pBlobber) {  
}  
  
void BlobberBlobDistance::draw(int iX, int iY) {  
}  
  

sweet! have you seen this:
http://forum.openframeworks.cc/t/hand-tracking/850/0
it looks similar I don’t know if there is stuff in there you can use.

so you end up with a shape that has roughly 5 sides and then the points where the sides meet correspond to hands head and feet?

huh - thats a pretty nice approach!!

[quote author=“theo”]so you end up with a shape that has roughly 5 sides and then the points where the sides meet correspond to hands head and feet?

huh - thats a pretty nice approach!![/quote]

Thanks Theo!

I’m rougly following this approach:
http://www.cs.iitm.ernet.in/~amittal/bodypose.pdf

When you google on:
silhouette analysis human body

you’ll find some interesting papers.

When I’ve detected a human shape/silhouette and create a convex hull, I want to use
face detection and hand recognition of openCV to detect hands in a ‘small’ area around the points of the hull. (not sure what this will do with performance).

Roxlu

This is great stuff!

I am trying to achieve similar results for a project. Did you ever finish it and did it help for performance to simplify the region for hand detection, etc?

Cheers