python提取文字的轮廓_OpenCV-Python系列八:提取图像轮廓

当你完成图像分割之后,图像轮廓检测往往可以进一步筛选你要的目标,OpenCV中可以使用cv2.findContours来得到轮廓。

1. 基本使用方法如下:

轮廓检测

import cv2

import numpy as np

img = cv2.imread('black_rect1.png', 0)

ret, th = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)

contours, hierarchy = cv2.findContours(th,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

color_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

img = cv2.drawContours(color_img, contours, -1, (255, 0, 0), 2)

# bitwise_not对二值图像取反

cv2.imshow('th_img', cv2.bitwise_not(th))

cv2.imshow('contours_img', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

补充:

再不少场景中,找轮廓的最小外接矩形是基本需求,opencv中minAreaRect得到的是一个带有旋转角度信息的rect,可以使用cv2.boxPoints(rect)来将其转为矩形的四个顶点坐标(浮点类型).你也可以使用cv2.polylines来绘制这样的轮廓信息

最小外接矩形轮廓绘制

import cv2

import numpy as np

img = cv2.imread('rotate_rect.png', 0)

ret, th = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)

contours, hierarchy = cv2.findContours(th,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

# 利用cv2.boxPoints用来计算minAreaRect所得到的最小面积外接圆的四个顶点,不过得到的是浮点型

rect = cv2.minAreaRect(contours[0])

# 浮点类型转换

box = np.int64(cv2.boxPoints(rect))

# 为了绘制彩色,将图像转为三通道

color_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

# 你可以用polylines来绘制点集数据,第三个参数为绘制时是否将轮廓首尾相连

cv2.polylines(color_img, [box], True, (25, 25, 255), 3)

cv2.imshow('rotate_rect_contour_img', color_img)

cv2.waitKey(0)

cv2.destroyAllWindows()

2. 轮廓函数的解释

cv2.findContours(img, mode, method[, contours[, hierarchy[, offset]]])

img:支持8bit单通道的图像,对于非0的像素点会当作1来处理,所以基本上你需要先二值化图像;

mode: 提取轮廓的方式,常用的参数为cv2.RETR_TREE, cv2.RETR_EXTERNAL,前者按照外层轮廓和里层孔来建立等级结构,后者则只求取最外层的轮廓;

method:cv2.CHAIN_APPROX_SIMPLE最常用,压缩水平、垂直、倾斜部分,只会保留最后的一个点,某些情况下,会减少大量不必要的点,比如你需要找矩形,这种方法只会保留四个端点,但对你来说,这样的轮廓就满足需求了;其次cv2.CHAIN_APPROX_NONE则会保留所有找到的轮廓点,会增大消耗;

offset:表示你需要的偏移量,当你是在ROI中进行查找轮廓,那在原图中绘制轮廓信息时,则offset会非常有用,tuple(x_offset, y_offset)

对于hierarchy的信息,其结构形式为[next, previous, first_child, parent],分别代表同级的下一条轮廓,同级的上一条轮廓,当前轮廓的第一个条轮廓,当前轮廓的父轮廓。

参考博客:图像轮廓检索方式详解https://www.cnblogs.com/wojianxin/p/12602490.html

注意findContours参数的变化,在opencv4中,返回值只有contours和hierarchy ,这一点与opencv3中不同。对与轮廓的层级结构,比较难用,虽然可以通过轮廓的层级结构来进行索引你需要的轮廓,不过对于大部分机器视觉应用场景,二值化的结果有时候很难预料,单单通过这种层级关系索引,非常容易出错。所以,只找最外部结构的cv2.RETR_EXTERNAL是不是真香呢?

绘制轮廓:cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]])

contourIdx:可以绘制指定的某条轮廓,为-1代表绘制全部轮廓

thickness:线条的宽度,为-1时代表填充轮廓内部区域(看你的需要)

3. 轮廓的近似

approx = cv2.approxPolyDP(cnt, epsilon, closed)

epsilon:决定了近似的准确性,代表原始的轮廓与拟合轮廓的最大距离,你可以自己尝试不同的精度来拟合轮廓信息

closed:bool, 轮廓是否闭合

使用approxPolyDP来近似表达轮廓

# approxPolyDP

import cv2

import numpy as np

img = cv2.imread('approx_star.png', -1)

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

ret, th = cv2.threshold(gray_img, 127, 255, cv2.THRESH_BINARY)

contours, hierarchy = cv2.findContours(th,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

img_temp = img.copy()

for contour in contours:

# 求轮廓的周长,传递轮廓参数和轮廓是否闭合

epsilon = 0.06 * cv2.arcLength(contour, True)

approx_cnt = cv2.approxPolyDP(contour, epsilon, True)

# 绘制轮廓

cv2.polylines(img_temp, [contour], True, (25, 25, 255), 3)

cv2.polylines(img, [approx_cnt], True, (255, 25, 25), 3)

cv2.imshow('contours', img_temp)

cv2.imshow('approx_lines', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

处理cv2.approxPolyDP()外,你也可以使用cv2.convexHull来求轮廓的近似凸包,其中凸形状内部--任意两点连线都在该形状内部。

cv2.convexHull(cnt, clockwise, returnPoints)

clockwise:默认为False,即轮廓为逆时针方向进行排列;

returnPoints:设置为False会返回与凸包上对应的轮廓的点索引值,设置为True,则会返回凸包上的点坐标集,默认为True

对于opencv-python的提取图像轮廓部分有问题欢迎留言, Have Fun With OpenCV-Python, 下期见。

你可能感兴趣的:(python提取文字的轮廓)