16-opencv-python-Opencv中的轮廓

目录

一、轮廓

1、什么是轮廓

2、怎么绘制轮廓

3、轮廓的近似方法

二、轮廓特征

1、矩

2、轮廓面积

3、轮廓的周长(弧长)

4、轮廓近似

5、凸包、凸性检测

6、边界矩形

7、最小外接圆

8、椭圆拟合

9、直线拟合


 

一、轮廓

1、什么是轮廓

轮廓可以简单认为是成为连续的点(连着边界)连在一起的曲线具有相同的颜色或者是灰度。轮廓在形状分析和物体识别方面中很有用。

  • 为了准确,要使用二值化图像。需要进行阀值化处理或者Canny边界检测
  • 查找轮廓的函数会修改原始图像。如果继续使用原始图像的话,应该将原始图像存储到其他变量中
  • 在Opencv中,查找轮廓就像是在黑色的背景中找白色物体。

2、怎么绘制轮廓

找到轮廓:contours, hierarchy = cv2.findContours(thresh, mode, method)

  • contours:轮廓本身(是一个列表)
  • hierachy:每条轮廓对应的属性
  • thresh:输入的二值化后的图像
  • mode:轮廓的检索模式,四种:
  1. cv2.RETR_EXTERNAL表示只检测外轮廓
  2. cv2.RETR_LIST检测的轮廓不建立等级关系
  3. cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
  4. cv2.RETR_TREE建立一个等级树结构的轮廓
  • method:轮廓的近似办法:
  1. cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
  2.  cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
  3. cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

注意:opencv2返回两个值:contours:hierarchy;opencv3会返回三个值,分别是img, countours, hierarchy

绘制轮廓:cv2.drawContours( img, contours , contourIdx , color(r,g,b),thickness)

  • contourIdx:绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓
  • color(r,g,b):线条的颜色
  • thickness:轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('outline1.png')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray,127,255,0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
imag = cv2.drawContours(img,contours,-1,(0,255,0),3)

while True:
    cv2.imshow('img',img)
    cv2.imshow('imag', imag)
    k = cv2.waitKey(1) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

对于每一个轮廓的counters都会有一个这样对应列表:

3、轮廓的近似方法

之前 提到的轮廓是一个形状具有相同灰度值的边界,它会存储形状边界上的所有的(x,y)坐标。实际上,我们不需要所有的点,当需要直线的时候,找到两个端点就可。cv2.CHAIN_APPROX_SIMPLE可以实现。它会将轮廓上的冗余点去掉,压缩轮廓,从而节约内存开支。

二、轮廓特征

1、矩

图像的矩可以帮助我们计算图像的质心、面积等

函数cv2.moments()会将计算得到的矩以一个字典的形式返回

import cv2

img = cv2.imread('rectangle.png',0)
ret, thresh = cv2.threshold(img, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)
print(M)
print(len(M))
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print(cx,cy)

#输出
{'m00': 135072.0, 'm10': 54501552.0, 'm01': 34443360.0, 'm20': 24467257248.0, 'm11': 13897895760.0, 'm02': 9716674464.0, 'm30': 11870574279480.0, 'm21': 6239150598240.0, 'm12': 3920678146224.0, 'm03': 2953896996960.0, 'mu20': 2475881016.0, 'mu11': -1.9073486328125e-06, 'mu02': 933617663.9999981, 'mu30': 0.0, 'mu21': 0.0018310546875, 'mu12': 0.00079345703125, 'mu03': 0.00048828125, 'nu20': 0.13570601851851852, 'nu11': -1.0454407429638942e-16, 'nu02': 0.0511727078891257, 'nu30': 0.0, 'nu21': 2.7307880219458127e-16, 'nu12': 1.1833414761765188e-16, 'nu03': 7.2821013918555e-17}
24
403 255

我们计算对象的重心

在这里插入图片描述

2、轮廓面积

函数cv2.contourArea()计算得到

import cv2

img = cv2.imread('rectangle.png',0)
ret, thresh = cv2.threshold(img, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
area = cv2.contourArea(cnt)
print(area)

#输出
135072.0

3、轮廓的周长(弧长)

函数cv2.arcLength(cnt, True)计算周长(闭合:True)

import cv2

img = cv2.imread('rectangle.png',0)
ret, thresh = cv2.threshold(img, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
perimeter = cv2.arcLength(cnt, True)
print(perimeter)

#输出
1514.0

4、轮廓近似

将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓形状的点的数目由我们设定的准确度来决定。

假设我们要在一幅图片中查找一个矩形,但是由于图像的种种原因我们找不到一个完美的矩形,而是一个鼓鼓的矩形,那么我们可以用函数来近似这个形状:

epsilon = 0.1*cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)

import cv2

img = cv2.imread('rectangle.png',0)
ret, thresh = cv2.threshold(img, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
epsilon = 0.1*cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
print(approx)

#输出
[[[169 111]]

 [[169 399]]

 [[638 399]]

 [[638 111]]]

5、凸包、凸性检测

暂不处理

6、边界矩形

直边界矩形,一个直矩形,没有旋转,所以直矩形的面积不是最小的。可以通过函数找到:

注意注意:千万不要直接img = cv2.imread('outline2.png',0)这样读取一个灰度图片,这样,你在画图像的时候你会发现,我为什么画出来的只有灰度线条!

x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x,y), (x+w,y+h),(0,0,255),2)

  • (x,y):矩形的左上角的坐标
  • (x+w,y+h):矩形的宽和长

rect = cv2.minAreaRect(cnt)
box = np.int0(cv2.boxPoints(rect))
cv2.polylines(img,[box],True,(255,0,0),2)

  • rect:得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)
  • box:得到最外接矩形的四个点
import numpy as np
import cv2

img = cv2.imread('outline2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
#画出直形矩形
x,y,w,h = cv2.boundingRect(cnt)
print(x,y,w,h)
cv2.rectangle(img, (x,y), (x+w,y+h),(0,0,255),2)
#画出最小矩形(由画多边形的代码画出)
rect = cv2.minAreaRect(cnt)
box = np.int0(cv2.boxPoints(rect))
print(box)#矩形的四个点
cv2.polylines(img,[box],True,(255,0,0),2)
while True:
    cv2.imshow('image',img)
    k = cv2.waitKey(1) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

#输出
161 52 545 400
[[191 480]
 [ 93 313]
 [663 -19]
 [761 148]]

7、最小外接圆

(x,y), radius = cv2.minEnclosingCircle(cnt)

得到圆心坐标和半径

import cv2

img = cv2.imread('outline2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
(x,y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img, center, radius, (0,255,0),2)
while True:
    cv2.imshow('image',img)
    k = cv2.waitKey(1) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

8、椭圆拟合

ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img, ellipse,(0,255,0),2)

import cv2

img = cv2.imread('outline2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img, ellipse,(0,255,0),2)
while True:
    cv2.imshow('image',img)
    k = cv2.waitKey(1) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

9、直线拟合

可以根据一组点拟合出一条直线,同样我们也可以为图像中的白色点拟合出一条直线

rows, cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx)+y)
righty = int(((cols-x)*vy/vx)+y)
cv2.line(img, (cols-1,righty),(0,lefty),(0,255,0),5)

  • (cols-1,righty),(0,lefty):直线的两个坐标
import cv2

img = cv2.imread('outline2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127,255,0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
rows, cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx)+y)
righty = int(((cols-x)*vy/vx)+y)
cv2.line(img, (cols-1,righty),(0,lefty),(0,255,0),5)
print((cols-1,righty),(0,lefty))
while True:
    cv2.imshow('image',img)
    k = cv2.waitKey(1) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

#输出
(797, -12) (0, 571)

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值