Contour detection refers to the detection of object boundaries in an image, more focused on the upper semantic objects.For example, the findContours() function in OpenCV gets each contour and stores it as a point vector. In addition, it gets the topological information of an image, that is, the index number of the last contour, the previous contour, the parent contour and the embedded contour of a contour.
1. Code,
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace cv; using namespace std; Mat src; Mat src_gray; int thresh = 100; int max_thresh = 255; RNG rng(12345); /// Function header void thresh_callback(int, void* ); /** @function main */ int main( int argc, char** argv ) { ///Load source image src = imread( argv[1], 1 ); ///Convert to grayscale and blur noise reduction cvtColor( src, src_gray, CV_BGR2GRAY ); blur( src_gray, src_gray, Size(3,3) ); ///Create Form char* source_window = "Source"; namedWindow( source_window, CV_WINDOW_AUTOSIZE ); imshow( source_window, src ); createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); thresh_callback( 0, 0 ); waitKey(0); return(0); } /** @function thresh_callback */ void thresh_callback(int, void* ) { Mat canny_output; vector<vector<Point> > contours; vector<Vec4i> hierarchy; ///Use Canny operator to detect edges Canny( src_gray, canny_output, thresh, thresh*2, 3 ); ///Find Outline findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); First parameter: image,A single-channel image matrix, which can be a grayscale image, but is more commonly a binary image, typically through Canny,Laplace Equilateral Binary image processed by edge detection operator; Second parameter: contours,Defined as " vector<vector<Point>> contours",Is a vector, and is a double vector, a vector Within each element a set of consecutive elements is saved Point The vector of the set of points made up of points, each group Point A point set is a contour. How many contours, vectors contours How many elements are there. Third parameter: hierarchy,Defined as " vector<Vec4i> hierarchy",Take a look first Vec4i Definition: typedef Vec<int, 4> Vec4i; Vec4i yes Vec<int,4>An alias that defines a vector in which each element contains four int Vector of type variable. So by definition, hierarchy It is also a vector in which each element holds one containing four int An array of integers. vector hiararchy Elements and outline vectors within contours The elements within are one-to-one, and the capacity of the vectors is the same. hierarchy Four for each element in a vector int Type variable-- hierarchy[i][0] ~hierarchy[i][3],Individually denotes i The index number of the last contour, the previous contour, the parent contour, and the inline contour of each contour.If the current outline does not correspond to the next one Contour, previous contour, parent contour, or inline contour hierarchy[i][0] ~hierarchy[i][3]The corresponding bit is set to Default value-1. Fourth parameter: int Type mode,Retrieval modes that define contours: Value one: CV_RETR_EXTERNAL Only the periphery outline is detected, and the inner outline contained within the periphery outline is ignored Value two: CV_RETR_LIST Detects all contours, including the inner and outer contours, but the detected contours do not establish a hierarchical level. System, independent of each other, has no hierarchical relationship, which means there is no parent or embedded contour in this retrieval mode. therefore hierarchy The third and fourth components of all elements in a vector are set to-1,As you will see below Value three: CV_RETR_CCOMP All contours are detected, but only two hierarchical relationships are established for all contours, with the periphery at the top, if the periphery The inner contour also contains other contour information, so all contours within the inner contour belong to the top level Value four: CV_RETR_TREE, All outlines are detected and a hierarchical tree structure is established for all outlines.Outer outline contains inner outline, inner outline Layer outlines can also continue to contain embedded outlines. Fifth parameter: int Type method,Approximate methods for defining contours: Value one: CV_CHAIN_APPROX_NONE Save all contour points on the boundary of the object to contours Within Vector Value two: CV_CHAIN_APPROX_SIMPLE Save only the inflection point information of the contour, and save all the points at the inflection point of the contour contours Within a vector, information points on the straight line between the inflection point and the inflection point are not preserved Value three and four: CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS Use teh-Chinl chain near Similar algorithm Sixth parameter: Point Offset, the amount by which all contour information is offset from the corresponding points in the original image, equal to adding at each detected contour point The offset above, and Point It can also be negative! ///outline Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); for( int i = 0; i< contours.size(); i++ ) { Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); } ///Display results in the form namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); imshow( "Contours", drawing ); }
2. Definition of outline convex hull
Convex Hull is a concept in computational geometry (graphics).
In a real vector space V, for a given set X, the intersection S of all convex sets containing X is called the convex hull of X.The convex hull of X can be constructed by a convex combination of all points (X1,... Xn) in X.
In two-dimensional Euclidean space, a convex hull can be imagined as a rubber ring enclosing exactly all points.
In an imprecise way, given a point set on a two-dimensional plane, a convex hull is a convex polygon that connects the outermost points together and contains all the points in the point set.
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace cv; using namespace std; Mat src; Mat src_gray; int thresh = 100; int max_thresh = 255; RNG rng(12345); /// Function header void thresh_callback(int, void* ); /** @function main */ int main( int argc, char** argv ) { ///Load source image src = imread( argv[1], 1 ); ///Convert to grayscale and blur noise reduction cvtColor( src, src_gray, CV_BGR2GRAY ); blur( src_gray, src_gray, Size(3,3) ); ///Create Form char* source_window = "Source"; namedWindow( source_window, CV_WINDOW_AUTOSIZE ); imshow( source_window, src ); createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); thresh_callback( 0, 0 ); waitKey(0); return(0); } /** @function thresh_callback */ void thresh_callback(int, void* ) { Mat src_copy = src.clone(); Mat threshold_output; vector<vector<Point> > contours; vector<Vec4i> hierarchy; ///Binarize the image threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); ///Find Outline findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); ///Calculate its convex hull for each contour vector<vector<Point> >hull( contours.size() ); for( int i = 0; i < contours.size(); i++ ) { convexHull( Mat(contours[i]), hull[i], false ); } First parameter: the set of points entered, which can be Mat Type matrix, or it can be std::vector<point>Point container for The second parameter can be vector<int>,This returns the index of each convex hull point in the container of the origin outline point, or vector<Point>,The location of the convex hull point is stored here,Point ( x,y)Coordinates. Third parameter: bool Variable indicating whether the output convex hull is clockwise or counterclockwise. true Is clockwise,false Is counterclockwise, the default is true,That is, output convex hull clockwise. Fourth parameter: bool Type variable returnPoints,Represents the output type of the second parameter, which defaults to true,That is to return the points of the convex hull, set to false Represents the index that returns the points of the convex hull.When the second parameter type is std::vector,Then this flag bit is ignored, that is, it takes the second parameter as the criterion, that is vector<int>,This returns the index of each convex hull point in the container of the origin outline point, which is vector<Point>Then, the location of the convex hull point is stored,Point ( x,y)Coordinates. ///Draw outlines and their convex hulls Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); for( int i = 0; i< contours.size(); i++ ) { Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() ); drawContours( drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point() ); } ///Show results in form namedWindow( "Hull demo", CV_WINDOW_AUTOSIZE ); imshow( "Hull demo", drawing ); }
3. Create rectangular and circular bounding boxes around outlines
Create rectangular and circular bounding boxes around outlines
using namespace cv; using namespace std; Mat src; Mat src_gray; int thresh = 100; int max_thresh = 255; RNG rng(12345); ///Function declaration void thresh_callback(int, void* ); /** @Principal function */ int main( int argc, char** argv ) { ///Load original image, return 3-channel image src = imread( argv[1], 1 ); ///Convert to grayscale image and smooth cvtColor( src, src_gray, CV_BGR2GRAY ); blur( src_gray, src_gray, Size(3,3) ); ///Create a window char* source_window = "Source"; namedWindow( source_window, CV_WINDOW_AUTOSIZE ); imshow( source_window, src ); createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); thresh_callback( 0, 0 ); waitKey(0); return(0); } /** @thresh_callback function */ void thresh_callback(int, void* ) { Mat threshold_output; vector<vector<Point> > contours; vector<Vec4i> hierarchy; ///Use Threshold to detect edges threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); ///Find Outline findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); ///Polygon approximates contour + Get rectangular and circular bounding boxes vector<vector<Point> > contours_poly( contours.size() ); vector<Rect> boundRect( contours.size() ); vector<Point2f>center( contours.size() ); vector<float>radius( contours.size() ); for( int i = 0; i < contours.size(); i++ ) { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true ); boundRect[i] = boundingRect( Mat(contours_poly[i]) ); minEnclosingCircle( contours_poly[i], center[i], radius[i] ); } ///Draw polygonal outline + surrounded rectangular box + circular box Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); for( int i = 0; i< contours.size(); i++ ) { Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() ); rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 ); circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 ); } ///Show in a window namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); imshow( "Contours", drawing ); }
4. Contour Moment
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
///Function declaration void thresh_callback(int, void* ); /** @Principal function */ int main( int argc, char** argv ) { ///Read in the original image and return 3 channels of image data src = imread( argv[1], 1 ); ///Convert the original image to grayscale and smooth it cvtColor( src, src_gray, CV_BGR2GRAY ); blur( src_gray, src_gray, Size(3,3) ); ///Create a new window char* source_window = "Source"; namedWindow( source_window, CV_WINDOW_AUTOSIZE ); imshow( source_window, src ); createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); thresh_callback( 0, 0 ); waitKey(0); return(0); } /** @thresh_callback function */ void thresh_callback(int, void* ) { Mat canny_output; vector<vector<Point> > contours; vector<Vec4i> hierarchy; ///Use Canndy to detect edges Canny( src_gray, canny_output, thresh, thresh*2, 3 ); ///Find Outline findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); ///Calculate Moment vector<Moments> mu(contours.size() ); for( int i = 0; i < contours.size(); i++ ) { mu[i] = moments( contours[i], false ); } ///Calculate center moment: vector<Point2f> mc( contours.size() ); for( int i = 0; i < contours.size(); i++ ) { mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); } ///Draw contours Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); for( int i = 0; i< contours.size(); i++ ) { Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); circle( drawing, mc[i], 4, color, -1, 8, 0 ); } ///Show in window namedWindow( "Contours", CV_WINDOW_AUTOSIZE ); imshow( "Contours", drawing ); ///Calculate contour area from m00 and compare with OpenCV function printf("\t Info: Area and Contour Length \n"); for( int i = 0; i< contours.size(); i++ ) { printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) ); Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); circle( drawing, mc[i], 4, color, -1, 8, 0 ); } }
1) Moment finding
Moments moments(inputArray array, bool binaryImage=false)
Input parameters, which can be raster images (single channel, two-dimensional arrays of 8 bits or floating points) or two-dimensional arrays (1N or N1)
The default value is false, and if this parameter is true, all non-zero pixels are 1. This parameter is used only for images
(2) Calculating contour area
double contourArea(inputArray contour, bool oriented=false)
Input vector, 2-D point (outline vertex)
Area-oriented identifier, if true, returns a signed area value that is positive or negative depending on the direction of the outline (clockwise or counterclockwise).Based on this feature, we can determine the position of the outline by the area symbol.It is important to note that this parameter has a default value of false, meaning it is returned as an absolute value, unsigned.
(3) Calculating the outline length
double arcLength(inputArray curve,bool closed)
Input two-dimensional point set
An identifier indicating whether a curve is closed or not, the default is closed, indicating that the curve is closed
4. About Several Moments
Point2d center(m.m10 / m.m00, m.m01 / m.m00); //This is the focus
double a = m.m20 / m.m00 - center.xcenter.x;
double b = m.m11 / m.m00 - center.xcenter.y;
double c = m.m02 / m.m00 - center.y*center.y;
Double theta = fastAtan2 (2 * b, (a - c))/ 2; //This is the direction of the shape
The angle returned by fastAtan2() refers to the angle clockwise from the positive x-axis to the image axis in a natural coordinate system
Note: Direction is defined by the axis of the image
5. The relationship between points and outlines
The pointPolygonTest checks if the point is within the contour:
C++: double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
When measureDist is set to true, the actual distance value is returned.If the return value is positive, the point is inside the polygon, the return value is negative, the return value is outside the polygon, the return value is 0, the return value is on the polygon.When measureDist is set to false, three fixed values - 1, 0, 1 are returned.If the return value is + 1, the point is inside the polygon, and the return value is -1, which is outside the polygon, and the return value is 0, which is on the polygon.