OpenCV image contour detection

        This article is the 15th article of the OpenCV image vision entry road. This article introduces various operations of image contour detection in detail, such as: contour retrieval mode, contour approximation operator and other operations.

        Image contours are curves of continuous points with the same color or grayscale , and contours are useful in shape analysis and object detection and recognition. The role of image contours: pattern analysis, object detection and recognition.

        It should be noted that: for the accuracy of detection, the image needs to be binarized or Canny operation 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.

OpenCV image contour detection directory

1 Find contours

2 Draw the outline

3 Area and perimeter of contours

4 Polygon approximation

5 convex hull

6 bounding rectangle


1 Find contours

cv2.findContours(image, mode, method, contours, hierarchy, offset)

  • image original image
  • mode the 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, detect all contours.
  •         RETP_CCOMP = 2, each layer has a maximum of two levels, from small to large, from inside to outside.
  •         RETP_TREE = 3, according to the tree storage outline, from small to large, from right to left.
  • method contour approximation method, also called ApproximationMode
  •         CHAIN_APPROX_NONE: save points on all contours
  •         CHAIN_APPROX_SIMPLE: Only corner points are saved. For example, for quadrilaterals, only the four corners of the quadrilaterals are reserved, and less information is stored, so it is more commonly used
  • Returns contours and hierarchy, that is, contours and levels.

import cv2
import numpy as np
from numpy import unicode

d

if __name__ == '__main__':
    img = cv2.imread('D:/Jupyter_Notebooks/1.2.png') #, cv2.IMREAD_GRAYSCALE

    # 转变成单通道
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 二值化,第一个返回值是执行的结果和状态是否成功,第二个返回值才是真正的图片结果
    ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    # 轮廓查找,第一个返回值是轮廓,第二个是层级
    contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # 绘制轮廓
    cv2.drawContours(img, contours, -1, (0, 0, 255), 1)  # 改变的是img这张图


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

    cv2.waitKey(0)
    cv2.destroyAllWindows()

2 Draw the outline

  • cv2.drawContours(image, contours, contourIdx, color, thickness, lineType, hierarchy, maxLevel, offset)
  • image: the contour image to draw
  • contours: contour points
  • contourIdx: the number of the contour to be drawn, -1 means to draw all contours
  • color: the color of the outline, such as (0, 0, 255) means red
  • thickness: line width, -1 means full fill
import cv2
import numpy as np
from numpy import unicode



if __name__ == '__main__':
    img = cv2.imread('D:/Jupyter_Notebooks/1.2.png') #, cv2.IMREAD_GRAYSCALE

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

    # 阈值 结果
    thresh, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    # 轮廓 层级
    contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # 绘制轮廓
    cv2.drawContours(img_copy, contours, -1, (0, 0, 255), 2)

    cv2.imshow('img', np.hstack((img, img_copy)))

    cv2.waitKey(0)
    cv2.destroyAllWindows()

3 Area and perimeter of contours

        The contour area refers to the area surrounded by all the pixels in each contour, and the unit is pixel. The contour area is one of the important statistical characteristics of the contour. The hidden information of each contour can be further analyzed through the size of the contour area, for example, the size of the object can be distinguished by the contour area, and then different objects can be identified. After finding the contour, there may be many small contours, and we can filter by the area of ​​the contour.

  • Area         contourArea()        cv2.contourArea(contour, oriented) contour: contour
  • Circumference          arcLength()        cv2.arcLength(curve, closed) curve: contour closed: whether it is a closed contour
import cv2
import numpy as np
from numpy import unicode



if __name__ == '__main__':
    img = cv2.imread('D:/Jupyter_Notebooks/1.2.png') #, cv2.IMREAD_GRAYSCALE

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

    # 阈值 结果
    thresh, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    # 轮廓 层级
    contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # 绘制轮廓
    cv2.drawContours(img_copy, contours, -1, (0, 0, 255), 2)
    # 轮廓面积
    area = cv2.contourArea(contours[1])
    print('area:', area)
    # 轮廓周长
    perimeter = cv2.arcLength(contours[1], closed=True)
    print('perimeter:', perimeter)

    cv2.imshow('img', np.hstack((img, img_copy)))

    cv2.waitKey(0)
    cv2.destroyAllWindows()

4 Polygon approximation

The contour information contours  after          findContours  may be too complex and not smooth, and  the approxPolyDP function can be used to make a proper approximation  to the polygonal curve , which is the polygonal approximation of the contour. approxPolyDP is to approximate the contour with polygons, using Douglas-Peucker (DP in the method name). The principle of the DP algorithm is relatively simple. The core is to continuously find the farthest point of the polygon and add it to form a new polygon until the shortest distance is less than the specified accuracy.

  • approxPolyDP()用法:        cv2.approxPolyDP(curve, epsilon, closed, approxCurve)
  • curve: the contour to approximate
  • epsilon: the threshold used by the DP algorithm
  • closed: whether the contour is closed
import cv2
import numpy as np
from numpy import unicode



if __name__ == '__main__':
    img = cv2.imread('D:/Jupyter_Notebooks/1.3.png') #, cv2.IMREAD_GRAYSCALE

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

    # 二值化:阈值 结果
    ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    # 查找轮廓 轮廓 层级
    contours, hierarchy = cv2.findContours(binary, 0, cv2.CHAIN_APPROX_SIMPLE)
    # 绘制轮廓
    cv2.drawContours(img, contours, 1, (0, 0, 255), 2)
    # 多边形逼近
    approx = cv2.approxPolyDP(contours[1], 10, True)
    # 把多边形逼近的轮廓画出来
    cv2.drawContours(img, [approx], -1, (200, 255, 0), 2)

    cv2.imshow('hand', np.hstack((img_ori, img)))

    cv2.waitKey(0)
    cv2.destroyAllWindows()

RETR_EXTERNAL=0 indicates that the value detects the outer contour

 RETR_LIST=1 The detected contour does not establish a hierarchical relationship, and detects all contours

5 convex hull

        Polygonal approximation is a high approximation of a contour, but sometimes we wish to simplify it using the convex hull of a polygon. A convex hull is similar to a polygonal approximation, except that it is the outermost convex polygon of an object. A convex hull refers to a polygon that completely contains the original contour and is only composed of points on the contour. Everywhere on the convex hull is convex, that is, the straight line connecting any two points in the convex hull is inside the convex hull. In a convex hull, the interior angle of any three consecutive points is less than 180°.

  • convexHull()用法:cv2.convexHull(points, hull, clockwise, returnPoints)
  • points: outline
  • clockwise: draw clockwise
import cv2
import numpy as np
from numpy import unicode



if __name__ == '__main__':
    img = cv2.imread('D:/Jupyter_Notebooks/1.3.png') #, cv2.IMREAD_GRAYSCALE

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

    # 二值化:阈值 结果
    ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    # 查找轮廓 轮廓 层级
    contours, hierarchy = cv2.findContours(binary, 0, cv2.CHAIN_APPROX_SIMPLE)
    # 绘制轮廓
    cv2.drawContours(img, contours, 1, (0, 0, 255), 2)
    # 多边形逼近
    approx = cv2.approxPolyDP(contours[1], 10, True)
    # 把多边形逼近的轮廓画出来
    cv2.drawContours(img, [approx], -1, (0, 255, 0), 2)
    # 计算凸包
    hull = cv2.convexHull(contours[1])
    cv2.drawContours(img, [hull], -1, (255, 0, 0), 2)

    cv2.imshow('hand', np.hstack((img_ori, img)))

    cv2.waitKey(0)
    cv2.destroyAllWindows()

6 bounding rectangle

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

In the figure below, the red part is the smallest bounding rectangle, and the green part is the largest bounding rectangle:

minAreaRect()Usage:  Minimum circumscribed matrix cv2.minAreaRect(points)

  • points: outline
  • Returns a tuple, the content of which is a rotated rectangle (RotatedRect) parameter: the starting coordinates x, y of the rectangle, the width and height of the rectangle, and the rotation angle of the rectangle

boundingRect()Usage: Maximum bounding matrix cv2.boundingRect(points)

  • points: outline
import cv2
import numpy as np
from numpy import unicode



if __name__ == '__main__':
    img = cv2.imread('D:/Jupyter_Notebooks/1.3.png') #, cv2.IMREAD_GRAYSCALE

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

    # 二值化:阈值 结果
    ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    # 查找轮廓 轮廓 层级
    contours, hierarchy, = cv2.findContours(binary, 0, cv2.CHAIN_APPROX_SIMPLE)

    # 最小外接矩形
    rect = cv2.minAreaRect(contours[1])
    box = cv2.boxPoints(rect)
    # 四舍五入
    box = np.round(box).astype('int64')
    # 绘制最小外接矩形
    cv2.drawContours(img, [box], 0, (255, 0, 0), 2)

    # 最大外接矩形
    x, y, w, h = cv2.boundingRect(contours[1])
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)

    cv2.imshow('hand', np.hstack((img_ori, img)))

    cv2.waitKey(0)
    cv2.destroyAllWindows()

 

Guess you like

Origin blog.csdn.net/qq_37529913/article/details/129234277