Contour calculation and analysis

Contours of shapes and objects in an image are an important visual property that can be used to describe and analyze them. Computer vision is no exception, so there are quite a few algorithms in computer vision that can be used to calculate the contours of objects in an image or calculate their area and so on.

The following image depicts two contours that are extracted from two 3D objects:

OpenCV includes a function, called findContours, that can be used to extract contours from an image. This function must be provided with a proper binary image that contains the best candidate pixels for contours; for instance, the result of the Canny function is a good choice. The following example demonstrates the steps required to calculate the contours of an image:

  1. Find the edges using the Canny function, as seen here:
Mat image = imread("Test.png"); 
Mat imgGray; 
cvtColor(image, imgGray, COLOR_BGR2GRAY); 
 
double threshold1 = 100.0; 
double threshold2 = 200.0; 
int apertureSize = 3; 
bool L2gradient = false; 
Mat edges; 
Canny(image, 
      edges, 
      threshold1, 
      threshold2, 
      apertureSize, 
      L2gradient); 
  1. Use the findContours function to calculate the contours using the detected edges. It's worth noting that each contour is a vector of Point objects, making all contours a vector of vector of Point objects, as seen here:
vector<vector<Point> > contours; 
int mode = CV_RETR_TREE; 
int method = CV_CHAIN_APPROX_TC89_KCOS; 
findContours(edges, 
             contours, 
             mode, 
             method);

In the preceding example, the contour-retrieval mode is set to CV_RETR_TREE and the contour-approximation method is set to CV_CHAIN_APPROX_TC89_KCOS. Make sure to go through the list of possible modes and methods by yourself, and compare the results to find the best parameters for your use case.

  1. A common method of visualizing detected contours is by using the RNG class, or the Random Number Generator class, to generate random colors for each detected contour. The following example demonstrates how you can use the RNG class in combination with the drawContours function to properly visualize the result of the findContours function:
RNG rng(12345); // any random number 
 
Mat result(edges.size(), CV_8UC3, Scalar(0)); 
int thickness = 2; 
for( int i = 0; i< contours.size(); i++ ) 
{ 
    Scalar color = Scalar(rng.uniform(0, 255), 
                          rng.uniform(0,255), 
                          rng.uniform(0,255) ); 
 
    drawContours(result, 
                 contours, 
                 i, 
                 color, 
                 thickness); 
} 

The following image demonstrates the result of the Canny and findContours functions:

Note the different colors in the image on the right-hand side, which correspond to one complete contour detected by using the findContours function.

After calculating the contours, we can use contour-analysis functions to further modify them or analyze the shape of the object in an image. Let's start with the contourArea function, which can be used to calculate the area of a given contour. Here is how this function is used:

double area = contourArea(contour); 

You can use area as a threshold for ignoring the detected contours that do not pass certain criteria. For example, in the preceding example code where we used the drawContours function, we could get rid of contours with smaller areas than some predefined threshold value. Here's an example:

for( int i = 0; i< contours.size(); i++ ) 
{ 
    if(contourArea(contours[i]) > thresholdArea) 
    { 
        drawContours(result, 
                     contours, 
                     i, 
                     color, 
                     thickness); 
    } 
} 

Setting the second parameter of the contourArea function (which is a Boolean parameter) to true would result in the orientation being considered in the contour area, which means you can get positive or negative values of the area depending on the orientation of the contour.

Another contour-analysis function that can be quite handy is the pointPolygonTest function. As you can guess from its name, this function is used to perform a point-in-polygon test, or in other words, a point-in-contour test. Here is how this function is used:

Point pt(x, y); 
double result = pointPolygonTest(contours[i], Point(x,y), true); 

If the result is zero, it means the test point is right on the edge of the contour. A negative result would mean the test point is outside, and a positive result would mean the test point is inside the contour. The value itself is the distance between the test point and the nearest contour edge.

To be able to check whether a contour is convex or not, you can use the isContourConvex function, as seen in the following example:

bool isIt = isContourConvex(contour);

Being able to compare two contours with each other is probably the most essential algorithm that you'll need when dealing with contour and shape analysis. You can use the matchShapes function in OpenCV to compare and try to match two contours. Here is how this function is used:

ShapeMatchModes method = CONTOURS_MATCH_I1; 
double result = matchShapes(cntr1, cntr2, method, 0); 

method can take any of the following values, while the last parameter must always be set to zero, unless specified by the method used:

  • CONTOURS_MATCH_I1
  • CONTOURS_MATCH_I2
  • CONTOURS_MATCH_I3

For details about the mathematical difference between the preceding list of contour-matching methods, you can refer to the OpenCV documentation.

Being able to find the boundaries of a contour is the same as being able to correctly localize it, for instance to find a region that can be used for tracking or performing any other computer vision algorithm. Let's assume we have the following image and its single contour detected using the findContours function:

Having this contour, we can perform any of the contour- and shape-analysis algorithms that we've learned about. In addition, we can use a number of OpenCV functions to localize the extracted contour. Let's start with the boundingRect function, which is used to find the minimal upright rectangle (Rect object) that contains a given point set or contour. Here's how this function is used:

Rect br = boundingRect(contour);

The following is the result of drawing the upright rectangle acquired by using boundingRect in the preceding sample code:

Similarly, you can use the minAreaRect function to find the minimal rotated rectangle that contains a given set of points or a contour. Here's an example:

RotatedRect br = minAreaRect(contour); 

You can use the following code to visualize the resultant rotated rectangle:

Point2f points[4]; 
br.points(points); 
for (int i=0; i<4; i++) 
    line(image, 
         points[i], 
         points[(i+1)%4], 
         Scalar(0,0,255), 
         2); 

You can draw an ellipse instead, using the ellipse function, or you can do both, which would result in something similar to the following:

In addition to algorithms for finding the minimal upright and rotated bounding rectangles of contours, you can also use the minEnclosingCircle and minEnclosingTriangle functions to find the minimal bounding circle and rectangle of a given set of points or a contour. Here's an example of how these functions can be used:

// to detect the minimal bounding circle 
Point2f center; 
float radius; 
minEnclosingCircle(contour, center, radius); 
 
// to detect the minimal bounding triangle 
vector<Point2f> triangle; 
minEnclosingTriangle(contour, triangle); 

There is no end to the list of possible use cases of contours, but we will name just a few of them before moving on to the next section. You can try using contour-detection and shape-analysis algorithms in conjunction with thresholding algorithms or back-projection images, for instance, to make sure your tracking algorithm uses the shape information in addition to the color and intensity values of pixels. You can also use contours to count and analyze shapes of objects on a production line, where the background and the visual environment is more controlled.

The final section of this chapter will teach you how to use feature detection, descriptor extraction, and descriptor-matching algorithms to detect known objects, but with rotation, scale, and even perspective invariance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.80.34