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)