首页 > 编程语言 >opencv-python 4.9.2. 轮廓特征

opencv-python 4.9.2. 轮廓特征

时间:2023-03-31 17:46:28浏览次数:33  
标签:cnt img python Pictures 4.9 opencv contours cv 255

图像的矩可帮助你计算某些特征,如对象的质心,对象的面积等特征。函数cv.moments()给出了计算的所有矩值的字典。

从这一刻起,你可以提取有用的数据,如面积,质心等。质心由关系给出,
$$ C_{x}=\frac{M_{10}}{M_{00}} $$和 $$ C_{y}=\frac{M_{01}}{M_{00}} $$。
这可以按如下方式完成:

import cv2 as cv

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 标记选中的区域
res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3)

# 计算矩
M = cv.moments(cnt)

# 计算质心
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])

# 画出质心
cv.circle(img, (cx, cy), 5, (255, 0, 0), -1)

cv.imshow('img', img)

cv.waitKey(0)

image

轮廓面积

轮廓区域由函数cv.contourArea()或M['m00']给出。

import cv2 as cv

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 标记选中的区域
res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3)

# 计算矩
M = cv.moments(cnt)

# 计算轮廓面积
area = cv.contourArea(cnt)
print(111, area, M['m00'])

image

轮廓周长

轮廓周长也被称为弧长。可以使用cv.arcLength()函数找到它。第二个参数指定形状是闭合轮廓(如果传递为True),还是仅仅是曲线。

import cv2 as cv

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 标记选中的区域
res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3)

# 计算轮廓周长
perimeter = cv.arcLength(cnt, True)
print(222, perimeter)

image

轮廓近似

它根据我们指定的精度将轮廓形状近似为具有较少顶点数的另一个形状。它是Douglas-Peucker算法的一种实现方式。 要理解这一点,可以假设你试图在图像中找到一个正方形,但是由于图像中的一些问题,你没有得到一个完美的正方形,而是一个“坏形状”(如下图第一张图所示)。现在你可以使用此功能来近似形状。在这里,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。这是一个准确度参数。需要选择适当的epsilon才能获得正确的输出。参数越小,两直线越接近。

epsilon = 0.01 * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)
import cv2 as cv

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 计算轮廓近似 epsilon=弧长的5%的近似曲线
epsilon = 0.05 * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)

# 绘制轮廓近似
res3 = cv.drawContours(img, [approx], -1, (0, 0, 255), 3)

cv.imshow('img', img)

cv.waitKey(0)

下边第一幅图是 epsilon=弧长的5%的近似曲线, 第二幅图是 epsilon=弧长的1%的近似曲线
image
image

凸包

凸包看起来类似于轮廓近似,但它不是(两者在某些情况下可能提供相同的结果)。这里,cv.convexHull()函数检查曲线的凸性缺陷并进行修正。一般而言,凸曲线是总是凸出或至少平坦的曲线。如果它在内部膨胀,则称为凸性缺陷。例如,检查下面的手形图像。红线表示手的凸包。双面箭头标记显示凸起缺陷,即船体与轮廓的局部最大偏差。

hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]
参数详情:

  • points:是我们传入的轮廓。
  • hull:是输出,通常我们忽略它。
  • clocwise:方向标志。如果为True,则输出凸包顺时针方向。否则,它逆时针方向。
  • reurnPoints:默认为True。然后它返回凸包点的坐标。如果为False,则返回与凸包点对应的轮廓点的索引。
import cv2 as cv

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 凸包
hull = cv.convexHull(cnt)

# 绘制凸包
res4 = cv.drawContours(img, [hull], -1, (0, 0, 0), 3)

cv.imshow('img', img)

cv.waitKey(0)

image

检查凸性

函数cv.isContourConvex()可以检查曲线是否凸的,它只返回True或False,没有什么理解上的问题。
k = cv.isContourConvex(cnt)

边界矩形

有两种类型的边界矩形。

a.直边矩形

它是一个直的矩形,它不考虑对象的旋转。因此,边界矩形的面积不是最小的。它由函数cv.boundingRect()找到。
设(x,y)为矩形的左上角坐标,(w,h)为宽度和高度。

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

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 直边矩形
x, y, w, h = cv.boundingRect(cnt)
cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv.imshow('img', img)

cv.waitKey(0)

image

b.旋转矩形

这里,以最小面积绘制边界矩形,因此它也考虑旋转。使用的函数是cv.minAreaRect()。它返回一个Box2D结构,其中包含以下detals - (center(x,y),(width,height),rotation of rotation)。但要画这个矩形,我们需要矩形的4个角。它是由函数cv.boxPoints()获得的。

rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(img,[box],0,(0,0,255),2)
import cv2 as cv
import numpy as np

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 旋转矩形
rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(img, [box], 0, (0, 0, 255), 2)

cv.imshow('img', img)

cv.waitKey(0)

image

最小外接圈

接下来,我们使用函数cv.minEnclosingCircle()找到对象的外接圆。它是一个完全覆盖物体的圆圈,面积最小。

(x,y),radius = cv.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv.circle(img,center,radius,(0,255,0),2)
import cv2 as cv
import numpy as np

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 最小外接圆
(x, y), radius = cv.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
cv.circle(img, center, radius, (0, 255, 0), 2)

cv.imshow('img', img)

cv.waitKey(0)

image

椭圆拟合

接下来是将椭圆拟合到一个对象上。它返回刻有椭圆的旋转矩形。

ellipse = cv.fitEllipse(cnt)
cv.ellipse(img, ellipse, (0, 255, 0), 2)
import cv2 as cv
import numpy as np

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 拟合椭圆
ellipse = cv.fitEllipse(cnt)
cv.ellipse(img, ellipse, (0, 255, 0), 2)

cv.imshow('img', img)

cv.waitKey(0)

image

拟合一条线

类似地,我们可以在一组点上拟合一条线。

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

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 拟合一条线
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
cv.line(img, (cols - 1, righty), (0, lefty), (0, 255, 0), 2)

cv.imshow('img', img)

cv.waitKey(0)

image

上边完整代码

点击查看代码
import cv2 as cv
import numpy as np

img = cv.imread(r'C:\Users\yuyalong\Pictures\Saved Pictures\rectangle1.jpg')

imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)

# 获取轮廓点
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print(99, len(contours))

# 找到最内层的元素, 这里是2是因为图像总共有三层
cnt = contours[2]

# 标记选中的区域
# res1 = cv.drawContours(img, cnt, -1, (0, 255, 0), 3)

# 计算矩
M = cv.moments(cnt)

# 计算质心
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])

# 画出质心
cv.circle(img, (cx, cy), 5, (255, 0, 0), -1)

# 计算轮廓面积
area = cv.contourArea(cnt)
print(111, area, M['m00'])

# 计算轮廓周长
perimeter = cv.arcLength(cnt, True)
print(222, perimeter)

# 计算轮廓近似 epsilon=弧长的5%的近似曲线
epsilon = 0.01 * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)
res3 = cv.drawContours(img, [approx], -1, (0, 0, 255), 3)

# 凸包
hull = cv.convexHull(cnt)
res4 = cv.drawContours(img, [hull], -1, (0, 0, 0), 3)

# 检查凸性
k = cv.isContourConvex(cnt)
print(333, k)

# 直边矩形
x, y, w, h = cv.boundingRect(cnt)
cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

# 旋转矩形
rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(img, [box], 0, (0, 0, 255), 2)

# 最小外接圆
(x, y), radius = cv.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
cv.circle(img, center, radius, (0, 255, 0), 2)

# 拟合椭圆
ellipse = cv.fitEllipse(cnt)
cv.ellipse(img, ellipse, (0, 255, 0), 2)

# 拟合一条线
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
cv.line(img, (cols - 1, righty), (0, lefty), (0, 255, 0), 2)

cv.imshow('img', img)

cv.waitKey(0)

标签:cnt,img,python,Pictures,4.9,opencv,contours,cv,255
From: https://www.cnblogs.com/yimeimanong/p/17276562.html

相关文章

  • python正则表达式记录
    今天写个脚本用到正则表达式,查阅了资料加问了gpt老师终于解决,在此记录。记录两种正则表达式有用的用法:1、匹配指定了前后文的字符串如我们需要匹配'ontheonehand'中的'one',而不要'ontheotherhand'中的'other';需要用到正则表达式语法中的“特殊构造”:(?...),之所以是特殊构......
  • 跟着查老四学Python Day 4:列表推导式 生成器 迭代器
    忽略掉例行寒暄,让查老四直接讲课了列表推导式(ListComprehension)列表推导式是一种简洁的构建列表的方法。它可以将一个循环和条件表达式结合起来,从而生成一个新的列表。示例:#普通循环创建一个列表squares=[]forxinrange(1,6):squares.append(x**2)print(squares)......
  • Python 数字类型之 int float
    数字常量int:一般的整数,long:长整型,2.x版本需在数字后加“L”或“l”,表示长整型如100000000L;python3.x版本后不分长整型,统一为int,不可加“L”或“l”float:浮点数,1.0也为浮点数,float可强制转换为int,取整;print(type(1234))print(type(-24))print......
  • 关于python 的if __name__ == "__main__"的模块测试
    if__name__=="__main__"也就是说执行当前文件,不调用模块的时候__name__=__main__调用模块的时候,测试如下:1、新建test01.py文件测试代码如下print("这条消息来自test01")deffunc():print('hello,world!***')print("这条消息来自func")if__name__=="__......
  • python isinstance()函数
    pythonisinstance()函数描述isinstance()函数来判断一个对象是否是一个已知的类型,类似type()isinstance()与type()的区别type()不会认为子类是一种父类类型,不考虑继承关系isinstance()会认为子类是一种父类类型,考虑继承关系如果要判断两个类型是否相同推荐使用isinstanc......
  • Python3内置函数之C系列
    1、callable()callable()是一个内置函数,用于检查给定对象是否是可调用的。如果对象是可调用的,则返回True,否则返回False。可调用对象包括函数、方法、类和某些类的实例。如果一个对象定义了__call__()方法,则也被认为是可调用的。 2、chr()chr()是Python内置函数之一,用于......
  • 【python基础】python字典根据值查询键
    前言 测试>>>tfl_label={'circle_green':0,'circle_red':1,'circle_yellow':2,'left_green':3,'left_red':4,'left_yellow':5,'nomotor_green':6,'nomotor_red':7,......
  • ubuntu16.04升级python3.7.1教程
    ubuntu16.04升级python3.7.1教程准备sudoapt-getinstall--reinstallzlibczlib1gzlib1g-devsudoapt-getinstalllibffi-devlibssl-devlibreadline-dev-y安装使用python官方站点的以下命令下载Python。您也可以下载最新版本代替下面指定的版本#下载python3......
  • python win32gui 无法控制 最小化后的桌面
    当远程桌面被最小化时,发现使用win32gui控制某软件置于最前台显示时失效,并报错:File"C:\Users\Administrator\Desktop\py-auto-login\robot\ktt_auth_code.py",line156,inwx_loginwin32gui.SetForegroundWindow(self._main_wnd)pywintypes.error:(0,'SetForegroun......
  • python selenium 判断元素是否存在,实现:找到元素,执行对应的代码;找不到元素,继续执行其他
    selenium因为找不到元素会抛出异常,导致执行结束可以考虑使用driver.find_elements(),找不到元素时就会返回空列表,使用if-else语句,判断列表是否为空,非空,则正常找到元素,进行后续代码执行;空,则直接跳过,执行其他代码iflen(driver.find_elements())!=0#判断列表的长度是否为0......