OpenCV(python)一键入门--十七篇(二值图像分析补充)

举报
拓佑豪 发表于 2021/08/05 11:35:57 2021/08/05
【摘要】 介绍了椭圆拟合,直线拟合,点多边形测试,凸包检测及其相关函数

本系列OpenCV博客旨在以最简单的方式分享OpenCV知识,欢迎大家交流和提出指导意见

凡是有本文未详细介绍的函数,都可以在以往的博客找到介绍及其使用方法


本期介绍函数:

cv.fitEllipse

cv.line

cv.fitLine

cv.pointPolygonTest 

cv.convertScaleAbs

cv.getStructuringElement 获取结构元素

cv.convexHull 凸包检测


1:椭圆拟合

import cv2 as cv
import numpy as np

src = cv.imread("D:/cycle.png")
cv.imshow("input", src)

#Canny
t = 80
binary = cv.Canny(src, t, t * 2)
cv.imshow("canny_output", binary)

k = np.ones((3, 3), dtype=np.uint8)
binary = cv.morphologyEx(binary, cv.MORPH_DILATE, k)  #形态学膨胀

# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
    # 椭圆拟合
    (cx, cy), (a, b), angle = cv.fitEllipse(contours[c])
    # 绘制椭圆
    cv.ellipse(src, (np.int32(cx), np.int32(cy)),
               (np.int32(a/2), np.int32(b/2)), angle, 0, 360, (0, 0, 255), 2, 8, 0)

cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()

1):cv.fitEllipse 椭圆拟合函数

输入cv.findContours给出的轮廓,就可以使用  该椭圆拟合函数  获取绘制椭圆必须的参数

即获得:【(中心点坐标x,中心点坐标y),(长短轴长度2a,长短轴长度2b),旋转角】

椭圆绘制函数的demo在该篇博客有介绍,这里仅简单放个函数介绍供大家对照参考: OpenCV(python)——一键入门--第4篇

效果如下:

附上素材供大家调试使用:

cycle.png


2:直线拟合

import cv2 as cv
import numpy as np
#直线拟合

def canny_demo(image):
    t = 80
    canny_output = cv.Canny(image, t, t * 2)
    return canny_output


src = cv.imread("d:/morph01.png")
cv.imshow("input", src)

k = np.ones((3, 3), dtype=np.uint8)

binary = canny_demo(src)
binary = cv.morphologyEx(binary, cv.MORPH_DILATE, k)
cv.imshow("binary", binary)

contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

# 直线拟合与极值点寻找
for c in range(len(contours)):
    x, y, w, h = cv.boundingRect(contours[c])
    m = max(w, h)
    if m < 30:
        continue

    vx, vy, x0, y0 = cv.fitLine(contours[c], cv.DIST_L1, 0, 0.01, 0.01)

    #斜率截距的计算
    k = vy/vx
    b = y0 - k*x0

    #初始化  赋初值
    maxx = 0
    maxy = 0
    miny = 100000
    minx = 0

    #寻找轮廓极值点
    for pt in contours[c]:
        px, py = pt[0]
        if maxy < py:
            maxy = py
        if miny > py:
            miny = py

    maxx = (maxy - b) / k
    minx = (miny - b) / k
    cv.line(src, (np.int32(maxx), np.int32(maxy)), (np.int32(minx), np.int32(miny)), (0, 0, 255), 2)

cv.imshow("contours_analysis", src)

cv.waitKey(0)
cv.destroyAllWindows()

1):cv.fitLine

将线拟合到二维或者三维的点集上

函数可以简单看成:cv.fitLine(输入轮廓,拟合方法,param,半径精度(坐标原点和直线之间的距离),角度精度)

  • 对于 半径精度 和 角度精度,0.01 将是一个很好的默认值
  • param:某些类型距离的数值参数 ( C )。如果为 0,则选择最佳值
  • 关于拟合方法,opencv支持如下六种方法
    DIST_L1 = 1
    DIST_L2 = 2
    DIST_L12 = 4
    DIST_FAIR = 5
    DIST_WELSCH = 6
    DIST_HUBER = 7
    其中5~7的模式需要对应参数C

cfafc5d01ddf583f383b87740cbbd07.png

2):cv.line 绘制直线

可以看成:cv.line(图像,(起始坐标x,起始坐标y),(终点坐标x,终点坐标y),笔画粗细)


效果如下:

附上原素材:

morph01.png


3:点多边形测试

import cv2 as cv
import numpy as np

#灰度二值化
src = cv.imread("D:/cycle.png")
cv.imshow("input", src)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow("binary", binary)

image = np.zeros(src.shape, dtype=np.float32)
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

h, w = src.shape[:2]

for row in range(h):
    for col in range(w):
        dist = cv.pointPolygonTest(contours[0], (col, row), False)
        if dist == 0:
            image[row,col] = (255,255,255)
        if dist > 0:
            image[row,col] = (255,0,0)
        if dist < 0:
            image[row,col] = (0,255,0)

dst = cv.convertScaleAbs(image)

cv.imshow("analysis", dst)
cv.waitKey(0)
cv.destroyAllWindows()

1):cv.pointPolygonTest 

可以看成是cv.pointPolygonTest(输入轮廓,针对轮廓测试的点,距离测量)

需要注意的是:距离测量的输入值是一个布尔值
如果输入为True,则会返回有符号距离
案例中为False,则返回+1,0,-1
    +1表示点在轮廓内
    0 表示点在轮廓上
    -1表示点在轮廓外

2):cv.convertScaleAbs

作用:缩放、计算绝对值并将结果转换为 8 位。在输入数组的每个元素上,函数 convertScaleAbs 依次执行三个操作:缩放、取绝对值、转换为无符号 8 位类型:

函数原型为:dst=cv.convertScaleAbs(src[, dst[, alpha[, beta]]])

可以看成是:cv.convertScaleAbs(输入图像,【可选输出图像】,【可选比例因子】,【添加到缩放值的可选增量】)

效果如下:


4:凸包检测

import cv2 as cv
import numpy as np
#凸包检测

src = cv.imread("D:/hand_1.jpg")
cv.imshow("input", src)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)

k = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))#得到结构元素
binary = cv.morphologyEx(binary, cv.MORPH_OPEN, k)#形态学变换
cv.imshow("binary", binary)

# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
    ret = cv.isContourConvex(contours[c])
    points = cv.convexHull(contours[c])#寻找凸包
    total = len(points)

    for i in range(len(points)):
        x1, y1 = points[i%total][0]
        x2, y2 = points[(i+1)%total][0]
        cv.circle(src, (x1, y1), 4, (255, 0, 0), 2, 8, 0)
        cv.line(src, (x1, y1), (x2, y2), (0, 0, 255), 2, 8, 0)

cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()

1):cv.getStructuringElement 获取结构元素

为形态学操作返回指定大小和形状的结构元素。

该函数构造并返回可以进一步传递给erode、dilate或morphologyEx的结构元素。但也可以自己构建任意二进制掩码并将其用作结构元素。

该函数可以看成:

cv.getStructuringElement(形状,大小,【锚,可选参数】)

形状:大致有以下

锚:元素内的锚点位置。默认值− − )意味着锚在中心。请注意,只有十字形元素的形状取决于锚点位置。在其他情况下,anchor 只是调节形态操作的结果移动了多少。

我们通过获取结构元素,然后将这个给morphologyEx,也就是形态学变换函数,在该博客2.1有详细介绍:https://bbs.huaweicloud.com/blogs/289130

2):cv.convexHull 凸包检测

对二值图像进行轮廓分析之后,对获取到的每个轮廓数据,可以构建每个轮廓的凸包,构建完成之后会返回该凸包包含的点集。根据返回的凸包点集可以绘制该轮廓对应的凸包。函数使用 Sklansky 算法找到 2D 点集的凸包,该算法在当前实现中具有O(N logN)复杂度。

函数可以看成

cv.convexHull(轮廓点集,【凸包检测输出,可选】,【方向标志】,【是否返回点集】)

  • 方向标志。如果为真,则输出凸包顺时针方向。否则,它是逆时针方向的。假设坐标系的 X 轴指向右侧,Y 轴指向上方。
  • 是否返回点集:为操作标志。在矩阵的情况下,当标志为真时,函数返回凸包点。否则,它返回凸包点的索引。

整个凸包检测方式如下图:

dc225d242d0a8f6bc9c9d75f86625ea.png

a5a847397503dccc2c41599d14ca776.png

效果如下:


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。