# OpenCV The outline of

1.1 What is the outline

It can be thought of as a simple continuous point （ Connected to the border ） Connected curves , Having the same color or grayscale . Contour is very useful in shape analysis and object detection and recognition .

- For accuracy , To use binary images . It needs to be thresholded or Canny boundary detection .
- The function to find the contour modifies the original image . If you want to continue using the original image later , The original image should be stored in other variables .
- stay OpenCV in , Looking for contours is like a super white object on a black background . You should remember , The object you're looking for should be white and the background should be black .

How to find the contour in a binary image .

function cv2.findContours() There are three parameters , The first is the input image , The second is the contour retrieval mode , The third is contour approximation . There are three return values , The first is the image , The second is the outline , The third is （ Contoured ） Chromatography structure . outline （ Second return value ） It's a Python list , It stores all the contours in this image . Every contour is a Numpy Array , Include object boundary points （x,y） Coordinates of .

1.2 How to draw the outline

function cv2.drawContours() Can be used to draw outlines . It can draw any shape according to the boundary points you provide . Its first parameter is the original image , The second parameter is the contour , One python list , The third parameter is the index of the contour （ It's very useful in drawing independent outlines , When set to -1 All contours are drawn ）. The next parameters are the color and thickness of the contour .

Draw all the outlines on one image ：

```
import numpy as np
import cv2
img = cv2.imread('1024.jpg')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
image ,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# Drawing individual outlines , Like the fourth outline
#imag = cv2.drawContour(img,contours,-1,(0,255,0),3)
# But most of the time , The following method is more useful
imag = cv2.drawContours(img,contours,3,(0,255,0),3)
while(1):
cv2.imshow('img',img)
cv2.imshow('imgray',imgray)
cv2.imshow('image',image)
cv2.imshow('imag',imag)
if cv2.waitKey(1) == ord('q'):
break
cv2.destroyAllWindows()
```

1.3 The approximate method of contour

As mentioned earlier, a contour is a boundary of a shape with the same gray value , It will store all the （x,y） coordinate . Actually, we don't need all the dots , When you need a straight line , You can find two endpoints .cv2.CHAIN_APPROX_SIMPLE Can achieve . It removes redundant points from the contour , Compress the contour , So as to save memory expenses .

Let's use the matrix to demonstrate , Draw a blue circle on each coordinate in the outline list . The first display uses cv2.CHAIN_APPROX_NONE The effect of , altogether 734 A little bit , The second graph is using cv2.CHAIN_APPROX_SIMPLE Result , Only 4 A little bit .

2. Contour feature

2.1 Moment

The moment of the image can help us calculate the centroid of the image , Area etc. .

function cv2.moments() The calculated moment is returned as a dictionary .

```
import numpy as np
import cv2
img = cv2.imread('1024.jpg',0)
ret,thresh = cv2.threshold(img,127,255,0)
image,contours,hierarchy=cv2.findContours(thresh,1,2)
cnt=contours[0]
M=cv2.moments(cnt)
print(M)
```

According to the values of these moments , We can calculate the center of gravity of the object ：

```
cx=int(M['m10']/M['m00'])
cy=int(M['m01']/M['m00'])
```

2.2 Contour area

You can use functions cv2.contourArea() To calculate the , You can also use moments （0 moment ）,M['m00'].

```
area=cv2.contourArea(cnt)
```

2.3 Contour circumference

Also known as arc length . You can use functions cv2.arcLength() To calculate the . The second parameter of this function can be used to specify that the shape of the object is closed （True）, It's still open （ A curve ）.

```
perimeter = cv2.arcLength(cnt,True)
```

2.4 The outline is approximate

The contour shape is approximated to another contour shape composed of fewer points , The number of points in the new contour is determined by the accuracy we set , The use of Douglas-Peucker Algorithm , You can do it yourself Google.

Suppose we're looking for a rectangle in an image , But for various reasons in the image, we can't get a perfect rectangle , It is a “ Bad shape ”, Now you can use this function to approximate the shape , The second parameter is epsilon, It is the maximum distance from the original contour to the approximate contour , It's an accuracy parameter .

```
epsilon=0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
```

2.5 convex hull

The convex hull is similar to the contour , But it's different , Although in some cases they give the same result . function cv2.convexHull() It can be used to detect whether a curve has convex defects , And it can correct the defects . Generally speaking , Convex curves are always convex , At least it's flat . If there's a dent, it's called a convex defect . For example, the hand in the picture below , The red curve shows the convex hull of the hand , Convex defects are marked with double arrows .

```
hull = cv2.convexHull(points,hull,clockwise,returnPoints)
```

Parameters ：

- points The profile we're going to pass in
- hull Output , Usually you don't need
- clockwise Direction signs , If set to True, The output convex hull is clockwise , Otherwise it's counter clockwise .
- returnPoints The default value is True. It will return the coordinates of the points on the convex hull , If set to False, The point on the contour corresponding to the convex hull point is returned .

To get the convex hull of the above figure , You can use the following command ：

```
hull=cv2.convexHull(cnt)
```

But if you want to get convex defects , Need to put returnPoints Set to False. Take the upper rectangle as an example , First of all, we find his outline from cnt. Now the returnPoints Set to True Find convex hull , What you get is the four corners of the rectangle . hold returnPoints Set to False, What you get is the index of the contour points .

2.6 Convexity detection

function cv2.isContourConvex() You can detect whether a curve is convex or not . It can only return True perhaps False.

```
k=cv2.isContourConvex(cnt)
```

2.7 Border rectangle

Straight border rectangle , A straight rectangle , No rotation . It doesn't take into account whether the object is rotating . So the area of the bounding rectangle is not the smallest . You can use functions cv2.boundingRect() Find out

```
#（x,y） Is the coordinates of the upper left corner of the rectangle ,（w,h） It's the width and height of the rectangle
x,y,w,h=cv2.boundingRect(cnt)
img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
```

Rotating border rectangle , This bounding rectangle is the smallest in area , Because it takes into account the rotation of the object . Use functions cv2.minAreaRect(). Back to a Box2D structure , It contains the coordinates of the top corner of the rectangle （x,y） The width and height of the rectangle （w,h） And the angle of rotation . But to draw this rectangle, you need rectangular 4 Corner points , You can do this through a function cv2.boxPoints() get .

The green one is a straight rectangle , Red is the rotating rectangle .

2.8 The smallest circumscribed circle

function cv2.minEnclosingCircle() It can help us find the circumcircle of an object . It's the smallest of all circles that can contain objects .

```
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)
```

2.9 Ellipse fitting

Using functions cv2.ellipse(), The return value is actually the inscribed circle of the rotated bounding rectangle .

```
ellipse = cv2.fitEllipse(cnt)
img = cv2.ellipse(img,ellipse,(0,255,0),2)
```

2.10 Straight line fitting

A line can be fitted from a set of points , Similarly, we can fit a straight line for the white points in the image .

```
rows,cols = img.shape[:2]
[vx,vy,x,y]=cv2.fitLine(cnt,cv2.DIST_L2,0,0.01,0.01)
lefty=int((x*vy/vx)+y)
righty=int(((cols-x)*vy/vx)+y)
img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
```