6

I'm using OpenCV for image processing. I am looking for a human body, wich I want to isolate (segment).

Currently, I am able to find the contour of the body, and approximate the contour with a Polygon. Next, I would like to use that contour in cvWatershed, to really isolate the body.

Does anyone know how I can draw a contour at an offset towards the center? To illustrate, see the image below.

enter image description here

Blue: the polygon approximation of the contour

Red: the polygon I would like have, but am unable to find. (In the image above, I used photoshop...)

Here's how I find & draw the current contour:

CvContourScanner scanner = cvStartFindContours(mask, pStorage, sizeof(CvContour),    CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
CvSeq* c;
CvSeq* polyContour;
int numCont = 0;
int perimScale = 4;
int contour_approx_level = 6;
while((c = cvFindNextContour(scanner)) != NULL)
{
    CvSeq* c_new;

    // Polygonal approximation
    c_new = cvApproxPoly(c, sizeof(CvContour), pStorage, CV_POLY_APPROX_DP, contour_approx_level, 0);

    // Create the new contour
    cvSubstituteContour(scanner, c_new);
    numCont++;
}

polyContour = cvEndFindContours(&scanner);
int i = 0;
for(i=0, c=polyContour; c!=NULL; c = c->h_next, i++)
{
    cvDrawContours(pOutput, c, cvScalar(255,125,0), cvScalar(255,255,0), -1, 2, 8);
}

/* Draw the contour at an offset towards the center here */
// Based upon the answers, I found 2 solutions

EDIT: I have found two solutions, based upon the answers below:

// 1) Erode - 
// void cvErode( const CvArr* A, CvArr* C, IplConvKernel* B=0, int iterations=1 );
cvErode(pOutput, pOutput, NULL, 3);

// 2) Another option - draw with a black border and thick pencil:
cvDrawContours(pOutput, c, cvScalarAll(0), cvScalarAll(0), 12, 2, 8);
Entreco
  • 12,738
  • 8
  • 75
  • 95

3 Answers3

3

It is probably not the most elegant thing, but it will certainly work:

  1. Draw the original contour in a new array.
  2. Compute its distance transform.
  3. Threshold: if you want an offset of ten pixels, keep pixels in the distance map higher than ten.
  4. Find the contour of the new image.

A similar and probably less non-rigorous thing could be done directly on the contour with the function pointPolygonTest().

Bojangles
  • 99,427
  • 50
  • 170
  • 208
Quentin Geissmann
  • 2,240
  • 1
  • 21
  • 36
  • Thanks for your answer. Also for pointing me to the pointPolygonTest() method. I found @lifesayko's answer easier though. – Entreco May 04 '12 at 17:42
3

Just erode the blue polygon you found before getting the contour. Here for C API (sorry, I'm not very familiar with the C API).

// void cvErode( const CvArr* A, CvArr* C, IplConvKernel* B=0, int iterations=1 );
cvErode(pOutput, pOutput, NULL, 3);
Entreco
  • 12,738
  • 8
  • 75
  • 95
Steve Heim
  • 799
  • 12
  • 25
  • Off course! So simple! In my case, where the background is black, it is also possible to draw the same contour with a line thickness... – Entreco May 04 '12 at 17:37
0

Morphological operations can be computationally expensive. Also, when you have a big dataset where you might have a variety of images then morphological operations might result in unwanted shapes. My suggestion is to use geometrical operations.

from shapely.geometry import Polygon

#Threshholding
threshold = 100
ret,thresh = cv.threshold(img,threshold,1,cv.THRESH_BINARY)

# Finding contours from the thresholded image
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, 
cv.CHAIN_APPROX_SIMPLE)

# Sorting the contours to select the one you need
contours = sorted(contours, key=lambda x: cv.contourArea(x), reverse=True)

contour = contours[0] # Example of selected contour (biggest here)

# Fitting a polygon on a selected contour
polygon = Polygon(contour[:, 0, :])

# Compute offset 
epsilon = 5
offset_polygon = polygon.buffer(-epsilon) #inward 

# Convert offset polygon to numpy array and draw on image
points = np.array(offset_polygon.exterior.coords)
points = np.expand_dims(points.astype(np.int32), axis=1)

mask = np.zeros_like(img)
cv.drawContours(mask, [points], -1, 100, -1 )

#opencv #contour #offset #geometrical