第12章 图像轮廓 -- 12.5 凸包,利用形状场景算法比较轮廓,轮廓的特征值

《OpenCV 轻松入门 面向Python》 学习笔记

获取凸包

hull = cv2.convexHull( points[, clockwise[, returnPoints]] )

返回值:

  • hull:凸包角点

参数:

  • points:轮廓
  • clockwise 布尔值
    • 值为True时(默认),凸包角点将按顺时针方向排序,
    • 值为False时,逆时针排列凸包角点
  • returnPoints 布尔值
    • 值为True时(默认),函数返回凸包角点的 x/y 轴坐标
    • 值为False时,返回轮廓中凸包角点的索引

举例:

import cv2
import numpy as np

# 读取图像
o = cv2.imread('/Users/manmi/Desktop/contours.bmp')
# 灰度图
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
# 二值图
threshold, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 查找轮廓
image, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

hull = cv2.convexHull(contours[1])
print(hull)
hull = cv2.convexHull(contours[1], returnPoints=False)
print('\n', hull)

# 输出为:
# [[[1259  715]]
#  [[ 926  715]]
#  [[ 926  484]]
#  [[1259  484]]]
# 
#  [[2]
#  [1]
#  [0]
#  [3]]

凸缺陷

凸包与轮廓之间的部分就是凸缺陷

convexityDefects = cv2.convexityDefects( contour, convexhull )

返回值是凸缺陷点集,是一个数组,每一行包括的值是 [起点,终点,轮廓上距离凸包最远的点,最远点到凸包的近似距离] .另外前三个值都是轮廓点的索引,要到轮廓点中再寻找。参数就是轮廓和凸包。

举例:

import cv2
import numpy as np

# 读取图像
o = cv2.imread('/Users/manmi/Desktop/contours.bmp')
# 灰度图
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
# 二值图
threshold, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 查找轮廓
image, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 提取第一个轮廓, cv2.CHAIN_APPROX_SIMPLE 只保留该方向的终点坐标
cnt = contours[0]   # (61, 1, 2)
# 凸包  (20, 1)
hull = cv2.convexHull(cnt, returnPoints=False)
# 凸缺陷 (13, 1, 4)  有13个凸缺陷
defects = cv2.convexityDefects(cnt, hull)

for i in range(defects.shape[0]):
    s, e, f, d = defects[i, 0]
    start = tuple(cnt[s][0])           # 得到的是索引,要再轮廓中选出来
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv2.line(o, start, end, [0, 0, 255],2)
    cv2.circle(o, far, 5, [255, 0, 0], -1)

cv2.imshow('result', o)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

把第0个轮廓(箭头)放大观察,如下:
在这里插入图片描述

几何学测试

检测轮廓是否是凸型的

retval = cv2.isContourConvex( contour ) 

返回值是布尔值,True表示轮廓是凸的,contour 是判断的轮廓

举例:

import cv2
import numpy as np

# 读取图像
o = cv2.imread('/Users/manmi/Desktop/contour_star.bmp')
# 灰度图
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
# 二值图
threshold, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 查找轮廓
image, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# --------- 凸包 ----------
image1 = o.copy()
# 提取第一个轮廓, cv2.CHAIN_APPROX_SIMPLE 只保留该方向的终点坐标
cnt = contours[0]   # (61, 1, 2)
# 凸包  (20, 1)
hull = cv2.convexHull(cnt)
# 画出凸包
cv2.polylines(image1, [hull], True, (0, 255, 0), 2)
# 判断是否是凸形的
resval = cv2.isContourConvex(hull)
print('构造的凸包是否是凸形的:', resval)

# --------- 逼近多边形 ----------
image2 = o.copy()
epsilon = 0.01 * cv2.arcLength(contours[0], True)
approx = cv2.approxPolyDP(contours[0], epsilon, True)
# 画出逼近多边形
cv2.drawContours(image2, [approx], 0, (0, 0, 255), 2)
# 判断是否是凸形的
resval = cv2.isContourConvex(approx)
print('构造的逼近多边形是否是凸形的:', resval)

cv2.imshow('image1', image1)
cv2.imshow('image2', image2)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 输出为:
# 构造的凸包是否是凸形的: True
# 构造的逼近多边形是否是凸形的: False

在这里插入图片描述


点到轮廓的距离

用来计算点到多边形(轮廓)的最短距离(也就是垂线距离),又叫点和多边形的关系测试。

retval = cv2.pointPolygonTest( contour, pt, measureDist )

返回值:

  • retval:点到轮廓的距离 / 点与轮廓的关系(内, 外,上),由参数measureDist决定
    参数:
  • contour 轮廓
  • pt 待判定的点
  • measureDist 布尔值,表示距离的判定方式:
    • True时,表示计算点到轮廓的距离,如果点在轮廓外,返回负值;如果点在轮廓上,返回0;如果点在轮廓内部,就是正数
    • False 时,不计算距离,只返回 -1, 0, 1 表示点相对于轮廓的位置,外,上,内。

举例:

import cv2

# ----------------原始图像-------------------------
o = cv2.imread('/Users/manmi/Documents/GitHub/open_cv/源代码及图像/chapter12/cs.bmp')
cv2.imshow('original', o)

# ----------------获取凸包------------------------
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
threshold, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
image, contours, hierarchy = cv2.findContours(binary,
                                             cv2.RETR_LIST,
                                             cv2.CHAIN_APPROX_SIMPLE)
hull = cv2.convexHull(contours[0])
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)   # 转成三通道后,在能在图像上画有色的轮廓
cv2.polylines(image, [hull], True, (0, 255, 0), 2)

# ---------------- 内部点A到轮廓的距离 ------------------------

distA = cv2.pointPolygonTest(hull, (300, 150), True)   # 参数measureDist=True, 返回点到轮廓的距离
cv2.putText(image, 'A', (300, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 3)
print(distA)

# ---------------- 外部点B到轮廓的距离 ------------------------
distB = cv2.pointPolygonTest(hull, (300, 250), True)   # 参数measureDist=True, 返回点到轮廓的距离
cv2.putText(image, 'B', (300, 250), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 3)
print(distB)

# ---------------- 轮廓上的点C到轮廓的距离 ------------------------
distC = cv2.pointPolygonTest(hull, (423, 112), True)   # 参数measureDist=True, 返回点到轮廓的距离
cv2.putText(image, 'C', (423, 112), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 3)
print(distC)

cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 输出为:
# 16.891650862259112
# -81.17585848021565
# -0.0

在这里插入图片描述


利用形状场景算法比较轮廓

计算形状场景距离

使用 ‘距离’ 作为形状比较的度量标准,这是因为形状之间的差异值(矩)和距离有相似之处,二者的表达都只能是零或者正数;当两个形状一模一样时,距离值和差值(矩)都等于零。

retval = cv2.createShapeContextDistanceExtractor( 
[, nAngularBins[, 
nRadialBins[, 
innerRadius[, 
outerRadius[, 
iterations[, 
comparer[, 
transformer]]]]]]] ) 

使用这个函数计算形状场景距离,使用 ‘形状上下文算法’,在每个点上附加一个“形状上下文”描述符,让每个点都能够捕获剩余点相对于它的分布特征,从而提供全局鉴别特征

返回结果可以通过如下函数计算两个不同形状之间的距离,参数是两个不同的轮廓。

retval=cv2.ShapeDistanceExtractor.computeDistance(contour1, contour2) 

举例:

import cv2
# -----------原始图像o1边缘--------------------
o1 = cv2.imread('/Users/manmi/Documents/GitHub/open_cv/源代码及图像/chapter12/cs.bmp')
cv2.imshow("original1",o1)
gray1 = cv2.cvtColor(o1,cv2.COLOR_BGR2GRAY)
ret, binary1 = cv2.threshold(gray1,127,255,cv2.THRESH_BINARY)
image,contours1, hierarchy = cv2.findContours(binary1,
                                              cv2.RETR_LIST,
                                              cv2.CHAIN_APPROX_SIMPLE)
cnt1 = contours1[0]

# -----------原始图像o2边缘--------------------
o2 = cv2.imread('/Users/manmi/Documents/GitHub/open_cv/源代码及图像/chapter12/cs3.bmp')
cv2.imshow("original2",o2)
gray2 = cv2.cvtColor(o2,cv2.COLOR_BGR2GRAY)
ret, binary2 = cv2.threshold(gray2,127,255,cv2.THRESH_BINARY)
image, contours2, hierarchy = cv2.findContours(binary2,
                                              cv2.RETR_LIST,
                                              cv2.CHAIN_APPROX_SIMPLE)
cnt2 = contours2[0]

# -----------原始图像o3边缘--------------------
o3 = cv2.imread('/Users/manmi/Documents/GitHub/open_cv/源代码及图像/chapter12/hand.bmp')
cv2.imshow("original3",o3)
gray3 = cv2.cvtColor(o3,cv2.COLOR_BGR2GRAY)
ret, binary3 = cv2.threshold(gray3,127,255,cv2.THRESH_BINARY)
image, contours3, hierarchy = cv2.findContours(binary3,
                                              cv2.RETR_LIST,
                                              cv2.CHAIN_APPROX_SIMPLE)
cnt3 = contours3[0]

# -----------构造距离提取算子--------------------
sd = cv2.createShapeContextDistanceExtractor()

# -----------计算距离--------------------
d1 = sd.computeDistance(cnt1,cnt1)
print("自身距离d1=", d1)
d2 = sd.computeDistance(cnt1,cnt2)
print("旋转缩放后距离d2=", d2)
d3 = sd.computeDistance(cnt1,cnt3)
print("不相似对象距离d3=", d3)
# -----------显示距离--------------------
cv2.waitKey()
cv2.destroyAllWindows()

# 输出为:
# 旋转缩放后距离d2= 0.7844208478927612
# 不相似对象距离d3= 2.7514803409576416

在这里插入图片描述


计算 Hausdorff 距离

cv2.createHausdorffDistanceExtractor() 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Enzo 想砸电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值