Finding Contours in Images with OpenCV
In this tutorial, let’s see how easy to find all contours in an image with OpenCV APIs.
Overview
Finding contours is a useful task during image processing. The relevant OpenCV functions are as follows:
-
Find contours in a binary image.
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
-
Draw contour outlines or fill contours.
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
-
Calculates a contour perimeter or a curve length.
double arcLength(InputArray curve, bool closed)
-
Calculates a contour area.
double contourArea(InputArray contour, bool oriented=false )
-
Calculates the upright bounding rectangle of a point set.
Rect boundingRect(InputArray points)
-
Find a rotated rectangle of the minimum area enclosing the input 2D point set.
RotatedRect minAreaRect(InputArray points)
-
Find a circle of the minimum area enclosing a 2D point set.
void minEnclosingCircle(InputArray points, Point2f& center, float& radius)
Building Contour Demo with Visual Studio 2013
- Make sure to prepare your OpenCV environment successfully. If you want to make OpenCV library by yourself, please refer to blog Building OpenCV with CMake on Windows.
- Create a win32 console project “FindContourDemo”.
-
Add include directories of OpenCV for project:
F:\\opencv\\build\\include F:\\opencv\\build\\include\\opencv2
-
Add library directories of OpenCV for project:
F:\\opencv\\build\\x86\\vc12\\lib
-
Find Post-Build Event and add the following commands to copy relevant OpenCV DLLs:
copy "F:\\opencv\\build\\x86\\vc12\\bin\\opencv_core2410.dll" $(OutDir) copy "F:\\opencv\\build\\x86\\vc12\\bin\\opencv_imgproc2410.dll" $(OutDir) copy "F:\\opencv\\build\\x86\\vc12\\bin\\opencv_highgui2410.dll" $(OutDir)
-
Edit the main function like this:
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #ifdef _DEBUG #pragma comment(lib, "opencv_core2410d.lib") #pragma comment(lib, "opencv_imgproc2410d.lib") #pragma comment(lib, "opencv_highgui2410d.lib") #else #pragma comment(lib, "opencv_core249.lib") #pragma comment(lib, "opencv_imgproc249.lib") #pragma comment(lib, "opencv_highgui249.lib") #endif using namespace cv; using namespace std; int main( int, char** argv ) { const char * file_name = "shape.png"; Mat src_mat, gray_mat, canny_mat; Mat contour_mat; Mat bounding_mat; const char* src_name = "Source"; const char* contours_name = "Contours"; const char* bounding_name = "Bounding"; //1.Read image file & clone. src_mat = imread( file_name ); contour_mat = src_mat.clone(); bounding_mat = src_mat.clone(); //2. Convert to gray image and apply canny edge detection cvtColor( src_mat, gray_mat, COLOR_RGB2GRAY ); Canny(gray_mat, canny_mat, 30, 128, 3, false); //3. Find & process the contours //3.1 find contours on the edge image. vector< vector< cv::Point> > contours; findContours(canny_mat, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //3.2 draw contours & property value on the source image. double area, length; drawContours(contour_mat, contours, -1, cv::Scalar(0), 2); //draw contours on the image for(int i = 0; i < contours.size(); ++i) { Point2f center; float radius; area = contourArea(contours[i]); length = arcLength(contours[i], true); minEnclosingCircle(contours[i], center, radius); //draw contour property value at the contour center. char buffer[64] = {0}; sprintf(buffer, "Area: %.2lf", area); putText(contour_mat, buffer, center, FONT_HERSHEY_SIMPLEX, .6, Scalar(0), 1); sprintf(buffer, "Length: %.2lf", length); putText(contour_mat, buffer, Point(center.x,center.y+20), FONT_HERSHEY_SIMPLEX, .6, Scalar(0), 1); } //3.3 find bounding of each contour, and draw it on the source image. for(int i = 0; i < contours.size(); ++i) { Point2f points[4]; Point2f center; float radius; Rect rect; RotatedRect rotate_rect; //compute the bounding rect, rotated bounding rect, minum enclosing circle. rect = boundingRect(contours[i]); rotate_rect = minAreaRect(contours[i]); minEnclosingCircle(contours[i], center, radius); rotate_rect.points(points); vector< vector< Point> > polylines; polylines.resize(1); for(int j = 0; j < 4; ++j) polylines[0].push_back(points[j]); //draw them on the bounding image. cv::rectangle(bounding_mat, rect, Scalar(0,0,255), 2); cv::polylines(bounding_mat, polylines, true, Scalar(0, 255, 0), 2); cv::circle(bounding_mat, center, radius, Scalar(255, 0, 0), 2); } //4. show window namedWindow( src_name, WINDOW_AUTOSIZE ); namedWindow( contours_name, WINDOW_AUTOSIZE ); namedWindow( bounding_name, WINDOW_AUTOSIZE ); imshow(src_name, src_mat); imshow(contours_name, contour_mat); imshow(bounding_name, bounding_mat); waitKey(0); return 0; }
- Build and run.
Source Code
https://github.com/DynamsoftRD/opencv-programming/tree/master/finding-contours