OpenCV 10 (image contour)

1. Image outline

An image contour is a curve of consecutive points with the same color or grayscale. Contours are useful in shape analysis and detection and recognition of objects.

The role of outline:

- For graphical analysis
- Recognition and detection of objects

important point:

- For detection accuracy, the image needs to be ** binarized** or **Canny operated ** first.
- The input image will be modified when drawing the outline. If you want to continue to use the original image later, you should store the original image in other variables.

1.1 Find contours

- findContours(image, mode, method[, contours[, hierarchy[, offset]]]) 

  - mode mode for finding contours

    - RETR_EXTERNAL = 0, means only detect the outer contour

     

    - RETR_LIST = 1, the detected contours do not establish a hierarchical relationship, that is, all contours are detected, which is more commonly used

 

    - RETR_CCOMP = 2, each layer has up to two levels, from small to large, from inside to outside.

    - RETR_TREE = 3, store outlines in tree format, from large to small, from right to left.

  - method The contour approximation method is also called ApproximationMode 

    - CHAIN_APPROX_NONE saves all points on the contour
    - CHAIN_APPROX_SIMPLE, only saves corner points, such as a quadrilateral, only retains the 4 corners of the quadrilateral, stores less information, and is more commonly used

  - Return contours and hierachy, that is, contours and levels

import cv2
import numpy as np

# 该图像显示效果是黑白的, 但是实际上却是3个通道的彩色图像.
img = cv2.imread('./contours1.jpeg')

# 变成单通道的黑白图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化, 注意有2个返回值, 阈值和结果
ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)

# cv2.imshow('img', img)
# cv2.imshow('binary', binary)

# 轮廓查找, 新版本返回两个结果, 轮廓和层级, 老版本返回3个参数, 图像, 轮廓和层级
result, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 打印轮廓
print(contours)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.2 Draw outlines

- drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])

  - image The contour image to be drawn
  - contours contour points
  - contourIdx The number of the contour to be drawn. -1 means drawing all contours
  - color The color of the contour, such as (0, 0, 255) means red
  - thickness line width, -1 means Fill all

import cv2
import numpy as np

# 该图像显示效果是黑白的, 但是实际上却是3个通道的彩色图像.
img = cv2.imread('./contours1.jpeg')

# 变成单通道的黑白图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化, 注意有2个返回值, 阈值和结果
ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)


# 轮廓查找, 新版本返回两个结果, 轮廓和层级, 老版本返回3个参数, 图像, 轮廓和层级
result, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓, 注意, 绘制轮廓会改变原图
cv2.drawContours(img, contours, 1, (0, 0, 255), 2)

cv2.imshow('img', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

1.3 Area and perimeter of contour

The contour area refers to the area surrounded by all pixels in each contour, and the unit is pixels .

Contour area is one of the important statistical properties of contours. The information hidden in each contour can be further analyzed through the size of the contour area. For example, the contour area can be used to distinguish the size of the object and identify different objects.

After finding the contour, there may be many small contours, and we can filter by the area of ​​the contour.

- contourArea(contour)
- arcLength(curve, closed)
  - curve is the contour
  - whether closed is a closed contour

 

import cv2
import numpy as np

# 该图像显示效果是黑白的, 但是实际上却是3个通道的彩色图像.
img = cv2.imread('./contours1.jpeg')

# 变成单通道的黑白图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化, 注意有2个返回值, 阈值和结果
ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)


# 轮廓查找, 新版本返回两个结果, 轮廓和层级, 老版本返回3个参数, 图像, 轮廓和层级
result, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓, 注意, 绘制轮廓会改变原图
cv2.drawContours(img, contours, 1, (0, 0, 255), 2)

# 计算面积
area = cv2.contourArea(contours[1])
print('area: ', area)
cv2.imshow('img', img)

# 计算周长
perimeter = cv2.arcLength(contours[1], True)
print('perimeter:', perimeter)

cv2.waitKey(0)
cv2.destroyAllWindows()

1.4 Polygon approximation and convex hull 

**The contour information contours after findContours may be too complex and not smooth. You can use the approxPolyDP function to make an appropriate approximation to the polygon curve**. This is the polygon approximation of the contour.

approxPolyDP uses polygons to approximate contours, using the Douglas-Peucker algorithm (DP in the method name)

The principle of the DP algorithm is relatively simple. The core is to continuously find the farthest point of a polygon and add it to form a new polygon until the shortest distance is less than the specified accuracy.

- approxPolyDP(curve, epsilon, closed[, approxCurve])

  - curve The contour to be approximated
  - epsilon is the threshold used by the DP algorithm
  - whether the closed contour is closed

import cv2
import numpy as np


img = cv2.imread('./hand.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化, 注意有2个返回值, 阈值和结果
ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)


# 轮廓查找, 新版本返回两个结果, 轮廓和层级, 老版本返回3个参数, 图像, 轮廓和层级
result, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓, 注意, 绘制轮廓会改变原图
cv2.drawContours(img, contours, 0, (0, 0, 255), 2)
# 展示没有进行多边形逼近之前的轮廓


# 进行多边形逼近, 返回的是多边形上一系列的点, 即多边形逼近之后的轮廓
approx = cv2.approxPolyDP(contours[0], 20, True)
# print(type(approx))
# print(approx)
# print('--------------------------------------')
# print(contours[0])

# 把多边形逼近的轮廓画出来.
cv2.drawContours(img, [approx], 0, (0, 255, 0), 2)
cv2.imshow('img', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

The approximating polygon is a high approximation of the contour, but sometimes, we want to simplify it using a convex hull of the polygon . The convex hull is very similar to an approximating polygon, except that it is the outermost convex polygon of an object. The convex hull refers to a polygon that completely contains the original contour and is composed only of points on the contour. Everywhere in the convex hull is convex , that is, the straight line connecting any two points in the convex hull is inside the convex hull. Within the convex hull, the interior angles of any three consecutive points are less than 180°.

- convexHull(points[, hull[, clockwise[, returnPoints]]])

  - points are contours
  - colckwise is drawn clockwise 

import cv2
import numpy as np


img = cv2.imread('./hand.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化, 注意有2个返回值, 阈值和结果
ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)


# 轮廓查找, 新版本返回两个结果, 轮廓和层级, 老版本返回3个参数, 图像, 轮廓和层级
result, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓, 注意, 绘制轮廓会改变原图
cv2.drawContours(img, contours, 0, (0, 0, 255), 2)


# 进行多边形逼近, 返回的是多边形上一系列的点, 即多边形逼近之后的轮廓
approx = cv2.approxPolyDP(contours[0], 20, True)

# 把多边形逼近的轮廓画出来.
cv2.drawContours(img, [approx], 0, (0, 255, 0), 2)


# 计算凸包
hull = cv2.convexHull(contours[0])
cv2.drawContours(img, [hull], 0, (255, 0, 0), 2)

cv2.imshow('img', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

1.5 Encircling rectangle

The circumscribed rectangle is divided into the minimum circumscribed rectangle and the maximum circumscribed rectangle. 

In the figure below, the red rectangle is the minimum enclosing rectangle, and the green rectangle is the maximum enclosing rectangle.

- minAreaRect(points) minimum external matrix

  - points are the outline
  - returns a tuple, the content of which is the parameters of a rotated rectangle (RotatedRect): the starting coordinates x, y of the rectangle, the width and height of the rectangle, and the selection angle of the rectangle.

- boundingRect(points) maximum bounding matrix
  - points is the outline
 

import cv2
import numpy as np


img = cv2.imread('./hello.jpeg')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)

result, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 最外面的轮廓是整个图像, contours[1]表示图像里面的图形轮廓
# 注意返回的内容是一个旋转的矩形, 包含矩形的起始坐标, 宽高和选择角度
(x, y), (w, h), angle = cv2.minAreaRect(contours[1])

print(x, y)
print(w, h)
print(angle)
r = cv2.minAreaRect(contours[1])

# 快速把rotatedrect转化为轮廓数据
box = cv2.boxPoints(r)
print(box)
# 轮廓必须是整数, 不能是小数, 所以转化为整数
box = np.round(box).astype('int64')
print(box)
# 绘制最小外接矩形
cv2.drawContours(img, [box], 0, (255, 0, 0), 2)

# 返回矩形的x,y和w,h
x,y, w, h = cv2.boundingRect(contours[1])
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Pixel coordinates are integers

Guess you like

Origin blog.csdn.net/peng_258/article/details/132777532