坐看云起时|

一枚码农

园龄:7年6个月粉丝:5关注:1

opencv-python 4.9.2. 轮廓特征

图像的矩可帮助你计算某些特征,如对象的质心,对象的面积等特征。函数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)

本文作者:一枚码农

本文链接:https://www.cnblogs.com/yimeimanong/p/17276562.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   一枚码农  阅读(279)  评论(0编辑  收藏  举报
历史上的今天:
2022-03-31 bfs&dfs
 
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 Sold Out Hawk
  2. 2 光辉岁月 Beyond
Sold Out - Hawk
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : Jon Steingard

作曲 : Jon Steingard

I ain't like no one you met before

I'm running for the front

When they're all running for the door

And I won't sit down won't back out

You can't ever shut me up

Cause I'm on a mission

And I won't quit now

In a world full of followers

I'll be a leader

In a world full of doubters

I'll be a believer

I'm stepping out without a hesitation

Because the battle's already been won

I'm sold out

I'm no longer living

Just for myself

Running after Jesus

With my whole heart

And now I'm ready to show

I am sold out

I'm sold out

With every single

Step that I take now

With every drop of blood

Left in my veins

I'm gonna be making it count

I am sold out

This ain't just some temporary phase

You can't face this kind of grace

And leave the way you came

This is permanent with intent

And there won't be no stopping it now

I'm on a mission and it's heaven sent

In a world full of followers

I'll be a leader

In a world full of doubters

I'll be a believer

I'm stepping out without a hesitation

Cause my soul is like a stadium

I'm sold out

I'm no longer living

Just for myself

Running after Jesus

With my whole heart

And now I'm ready to shout

I am sold out

I'm sold out

With every single

Step that I take now

With every drop of blood

Left in my veins

I'm gonna be making it count

I am sold out

No trials coming against me

Could put a dent in my passion

They're just an opportunity

To put my faith into action

In a world full of followers

I'll be a leader

In a world full of doubters

I'll be a believer

I'm stepping out without a hesitation

I ain't got nothing left to be afraid of

I'm sold out

I'm no longer living

Just for myself

Running after Jesus

With my whole heart

And now I'm ready to show

I am sold out

I'm sold out

With every single

Step that I take now

With every drop of blood

Left in my veins

I'm gonna be making it count

I am sold out