cv2.findContours()函数
函数的原型为
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
'''
返回两个值:contours:hierarchy。
参数
第一个参数是寻找轮廓的图像;
第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
cv2.RETR_EXTERNAL表示只检测外轮廓
cv2.RETR_LIST检测的轮廓不建立等级关系
cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
cv2.RETR_TREE建立一个等级树结构的轮廓。
第三个参数method为轮廓的近似办法
cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
cv2.CHAIN_APPROX_TC89_
'''
'''
返回值
cv2.findContours()函数返回两个值,一个是轮廓本身,还有一个是每条轮廓对应的属性。
contour返回值
cv2.findContours()函数首先返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。这个概念非常重要。在下面drawContours中会看见。通过
print (type(contours))
print (type(contours[0]))
print (len(contours))
可以验证上述信息。会看到本例中有两条轮廓,一个是五角星的,一个是矩形的。每个轮廓是一个ndarray,每个ndarray是轮廓上的点的集合。
由于我们知道返回的轮廓有两个,因此可通过
cv2.drawContours(img,contours,0,(0,0,255),3)
和
cv2.drawContours(img,contours,1,(0,255,0),3)
'''
轮廓的绘制
OpenCV中通过cv2.drawContours在图像上绘制轮廓。
cv2.drawContours()函数
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
'''
第一个参数是指明在哪幅图像上绘制轮廓;
第二个参数是轮廓本身,在Python中是一个list。
第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。绘制参数将在以后独立详细介绍。
'''
例子
'''
简单场景:形态学操作法
转灰度图,降噪二值化,多次膨胀(高亮部分扩张)腐蚀(高亮部分蚕食)突出轮廓消除边框线条,查找轮廓,返回文字检测边框
'''
import cv2
import numpy as np
imagepath = './data/13.jpg'
img = cv2.imread(imagepath)
w,h,c = img.shape
print('shape: ',img.shape)
imgcopy = img.copy()
# b, g, r = cv2.split(img)
# cv2.imshow("Blue 1", b)
# cv2.imshow("Green 1", g)
# cv2.imshow("Red 1", r)
img_gry = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
print('shape: ',img_gry.shape)
cv2.imshow('img_gry',img_gry)
# sobel = cv2.Sobel(img_gry,cv2.CV_8U,1,0,ksize=3)
# cv2.imshow("sober",sobel)
guass = cv2.GaussianBlur(img_gry,(5,5),0)
cv2.imshow("guass",guass)
# 二值化,白底黑字
min, max, minLoc, maxLoc = cv2.minMaxLoc(guass)
print("min: %.2f, max: %.2f"% (min, max))
print("min loc: ", minLoc)
print("max loc: ", maxLoc)
means, stddev = cv2.meanStdDev(guass)
print("mean: %.2f, stddev: %.2f"% (means, stddev))
guass[np.where(guass < means)] = 0
guass[np.where(guass > means)] = 255
cv2.imshow("binary-白底黑字", guass)
# 二值化,黑底白字,图像反色
for row in range(h):
for col in range(w):
pv = guass[col,row]
guass[col,row] = 255 - pv
cv2.imshow("binary-黑底白字", guass)
ret,binary1 = cv2.threshold(guass,0,255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)
ret2,binary2 = cv2.threshold(guass,0,255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
ret3,binary3 = cv2.threshold(guass,0,255,cv2.THRESH_TRUNC + cv2.THRESH_OTSU)
ret4,binary4 = cv2.threshold(guass,0,255,cv2.THRESH_TOZERO + cv2.THRESH_OTSU)
ret5,binary5 = cv2.threshold(guass,0,255,cv2.THRESH_TOZERO_INV + cv2.THRESH_OTSU)
ret6,binary6 = cv2.threshold(guass,0,255,cv2.THRESH_TRIANGLE)
binary7 = cv2.adaptiveThreshold(guass,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
# cv2.imshow('binary1',binary1)
# cv2.imshow('binary2',binary2)
# # cv2.imshow('binary3',binary3)
# cv2.imshow('binary4',binary4)
# cv2.imshow('binary5',binary5)
# cv2.imshow('binary6',binary6)
# cv2.imshow('binary7',binary7)
#cv2.imshow('binary-binary2',guass-binary2)
element1 = cv2.getStructuringElement(cv2.MORPH_CROSS,(11,11))
element2 = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
element3 = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
dilation1 = cv2.dilate(guass,element1,iterations=2) # 膨胀
cv2.imshow('dilation1',dilation1)
cv2.imshow('dilation1-binary2',dilation1-binary2)
erosion1 = cv2.erode(dilation1, element2, iterations=3) # 腐蚀
cv2.imshow('erosion', erosion1)
dilation = cv2.dilate(erosion1,element2,iterations=2)
cv2.imshow('dilation',dilation)
erosion2 = cv2.erode(dilation,element2,iterations=1)
cv2.imshow('erosion2',erosion2)
cv2.imshow('dilation-erosion',dilation-erosion1)
#查找轮廓和筛选文字区域
region = []
rects = []
area_max = 0
contours,hierarchy = cv2.findContours(dilation,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
print('len(contours)',len(contours))
cnt = contours[i]
# 计算轮廓面积,并筛选掉面积小的
area = cv2.contourArea(cnt)
print('area',area)
if (area > area_max):
area_max=area
region.clear()
rects.clear()
# continue
# 获取最小外接矩阵,中心点坐标,宽高,旋转角度
rect = cv2.minAreaRect(cnt)
print("rect is:")
print(rect)
# 获取矩形四个顶点,浮点型
box = cv2.boxPoints(rect)
# 取整
box = np.int64(box)
left_point_x = np.min(box[:, 0])
right_point_x = np.max(box[:, 0])
top_point_y = np.min(box[:, 1])
bottom_point_y = np.max(box[:, 1])
# 计算高和宽
height = abs(box[0][1] - box[2][1])
width = abs(box[0][0] - box[2][0])
# 跟据文字特征,筛选太细的矩形,留下扁的
# if(height > width*1.3):
# continue
region.append(box)
rects.append(rect)
print('region',region)
# for rect in rects:
# center_x_y = rect[0]
# w = rect[1][0]
# h = rect[1][1]
# angle = rect[2]
# # 左上
# x1 = int(center_x_y[0]-w/2)
# y1 = int(center_x_y[1]-h/2)
# # 左下
# x3 = int(center_x_y[0]-w/2)
# y3 = int(center_x_y[1]+h/2)
# # 右上
# x2 = int(center_x_y[0]+w/2)
# y2 = int(center_x_y[1]-h/2)
# # 右下
# x4 = int(center_x_y[0]+w/2)
# y4 = int(center_x_y[1]+h/2)
# rect_box = np.array([[x1, y1], [x3, y3], [x2, y2],
# [x4, y4]])
# print('rect_box',rect_box)
# cv2.rectangle(img,(x1,y1),(x4,y4),(0,255,0),2)
# # imgcopy = guass[y1:y4,x1:x4]
# # imgcopy = cv2.cvtColor(imgcopy,cv2.COLOR_GRAY2BGR)
#
# # # 二值化,黑底白字
# # for row in range(imgcopy.shape[1]):
# # for col in range(imgcopy.shape[0]):
# # pv = imgcopy[col, row]
# # imgcopy[col, row] = 255 - pv
# 绘制轮廓
for box in region:
print('box',box)
#center =
# 获取四个顶点坐标
left_point_x = np.min(box[:, 0])
right_point_x = np.max(box[:, 0])
top_point_y = np.min(box[:, 1])
bottom_point_y = np.max(box[:, 1])
left_point_y = box[:, 1][np.where(box[:, 0] == left_point_x)][0]
right_point_y = box[:, 1][np.where(box[:, 0] == right_point_x)][0]
top_point_x = box[:, 0][np.where(box[:, 1] == top_point_y)][0]
bottom_point_x = box[:, 0][np.where(box[:, 1] == bottom_point_y)][0]
# 上下左右四个点坐标
vertices = np.array([[top_point_x, top_point_y], [bottom_point_x, bottom_point_y], [left_point_x, left_point_y],
[right_point_x, right_point_y]])
print('vertices',vertices)
cv2.drawContours(img,[box],0,(0,0,255),2)
imgcopy = guass[top_point_y:bottom_point_y,left_point_x:right_point_x]
# p1 = np.float32([[0, 0], [w-1 , 0], [0, h-1 ],[w-1,h-1]])
# p2 = np.float32([[left_point_x, top_point_y], [right_point_x, top_point_y], [left_point_x, bottom_point_y],[right_point_x,bottom_point_y]])
# M = cv2.getAffineTransform(p1, p2)
# imgcopy = cv2.warpAffine(imgcopy, M, (w, h))
cv2.imshow('img',img)
cv2.imshow('imgcopy',imgcopy)
cv2.imwrite('./data/result.jpg',imgcopy)
cv2.waitKey(0)
cv2.destroyAllWindows()