CV | 轮廓检测并绘出矩形框(两种方法)

摘抄至:
https://blog.csdn.net/wsp_1138886114/article/details/82945328
https://segmentfault.com/q/1010000010452320/a-1020000010453711

简介

近日写论文时,发现用网上提供的YOLOv3 代码测试图像并检测矩形框时,程序中并没有设置矩形框线宽的参数。但是如果不调整线宽的话,打印出来的黑白色论文,边框效果并不明显。因此搜索了一下如何调整边框宽度的方法,顺便把OpenCV轮廓检测和绘图的方法了解了一下。

一、基于OpenCV

1. 轮廓检测


cv2.findContours(binary, cv2.RETR_TREE, 
					cv2.CHAIN_APPROX_SIMPLE)

其中,cv2.findContours() 的第二个参数主要有:

  • cv2.RETR_LIST:检测的轮廓不建立等级关系
  • cv2.RETR_TREE:建立一个等级树结构的轮廓
  • cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息
  • cv2.RETR_EXTERNAL:表示只检测外轮廓

cv2.findContours() 的第三个参数 method为轮廓的近似办法:

  • cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
  • cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
  • cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

返回值: image, contours, hierarchy

  • contour返回值
    cv2.findContours()函数首先返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。
  • hierarchy返回值
    该函数还可返回一个可选的hiararchy结果,这是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。

需要注意的是,OpenCV自带的轮廓检测函数,参考的论文为90年发表的论文,轮廓检测效果肯定不如近年来先进的轮廓检测算法的结果!算法设计时,可自行编写程序

2. 轮廓绘制

"""
x, y, w, h = cv2.boundingRect(img)   
    参数:
    img  是一个二值图
    x,y 是矩阵左上点的坐标,
    w,h 是矩阵的宽和高

cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
    img:       原图
    (x,y):   矩阵的左上点坐标
    (x+w,y+h):是矩阵的右下点坐标
    (0,255,0): 是画线对应的rgb颜色
    2:         线宽
"""
for i in range(0,len(contours)):  
    x, y, w, h = cv2.boundingRect(contours[i])   
    cv2.rectangle(image, (x,y), (x+w,y+h), (153,153,0), 5) 

cv2.drawContours()函数
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])

  • 第一个参数是指明在哪幅图像上绘制轮廓;
  • 第二个参数是轮廓本身,在Python中是一个list。
  • 第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。绘制参数将在以后独立详细介绍。

为了看到自己画了哪些轮廓,可以使用 cv2.boundingRect()函数获取轮廓的范围,即左上角原点,以及他的高和宽。然后用cv2.rectangle()方法画出矩形轮廓。

3. 获取轮廓区域

new_image=image[y+2:y+h-2,x+2:x+w-2]    # 先用y确定高,再用x确定宽
input_dir=("E:/cut_image/")
if not os.path.isdir(input_dir):
    os.makedirs(input_dir)
cv2.imwrite( nrootdir+str(i)+".jpg",newimage) 
print (i)

4. 获取物体最小外界矩阵

使用 cv2.minAreaRect(cnt) ,返回点集cnt的最小外接矩形,cnt是所要求最小外接矩形的点集数组或向量,这个点集不定个数。
其中:

cnt = np.array([[x1,y1],[x2,y2],[x3,y3],[x4,y4]]) # 必须是array数组的形式
rect = cv2.minAreaRect(cnt) # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)
box = np.int0(cv2.boxPoints(rect)) #通过box会出矩形框

CV | 轮廓检测并绘出矩形框(两种方法)_第1张图片

二、基于rectangle()函数

YOLOv3中画轮廓边框的时候,其中并没有线宽的设置,用的是rectangle函数(不知道这个函数是不是属于PIL )。代码如下:

            for i in range(thickness):
                draw.rectangle(
                    [left + i, top + i, right - i, bottom - i],
                    outline=self.colors[c])

最开始读的时候,以为这个函数跟OpenCV中的 cv2.rectangle 函数类似,可以再接参数设置线宽。后来才明白,原来这个里面,thickness 的大小,就代表了线宽。相当于是画thickness 次轮廓框。

这种写法其实还是比较的麻烦的,而且不是很直观,推荐用OpenCV中绘制轮廓的方法:cv2.rectangle()

你可能感兴趣的:(Computer,Vision,python,学习总结,python,cv,轮廓绘制)