iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >深入解析opencv骨架提取的算法步骤
  • 872
分享到

深入解析opencv骨架提取的算法步骤

2024-04-02 19:04:59 872人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录前言一.算法步骤1.算法步骤2.分析二.代码实现1.预处理2. 骨架提取实现前言 个人感觉骨架提取提取的就是开运算过程的不可逆。 一.算法步骤 1.算法步骤 首先上一下比较官方的

前言

个人感觉骨架提取提取的就是开运算过程的不可逆。

一.算法步骤

1.算法步骤

首先上一下比较官方的算法步骤:

1.获得原图像的首地址及图像的宽和高,并设置循环标志1

2.用结构元素腐蚀原图像,并保存腐蚀结果

3.设置循环标志为0,如果腐蚀结果中有一个点为255,即原图像尚未被完全腐蚀成空集,则将循环标志设为1.

4.用结构元素对腐蚀后的图像进行开运算(消除小的白色区域),并求取腐蚀运算与开运算的差(得到消除的白色区域)

5.用[4]中求得的结果与之前求得的骨架进行并集运算,以获得本次循环求得的骨架
6.把本次循环中保存的腐蚀结果赋值给原图像

7.重复步骤[2]-[6],直到将原图像腐蚀成空集为止。

最终求得的骨架就是结果。

2.分析

作者的理解是这样的:

输入:img(二值图)
输出:out(和img一样shape的图像,初始化是全0)
while img中有像素值为255(在这个循环里面,一直腐蚀我们的二值图,直到全部为黑色):
    腐蚀img图像
    对img开运算
	img2=开运算前的图像减去开运算后的图像
	out+=img2
输出out

首先说一下开运算,就是对图像先做腐蚀再做膨胀。上面一个核心点就是这一步(img2=开运算前的图像减去开运算后的图像),在这里为什么说个人感觉骨架提取提取的就是开运算过程的不可逆呢?我们对这个开运算过程分析一下:

1.假如开运算后的图像和开运算前的图像不一样,比如下面这张图片:

在这里插入图片描述

可以看到这张图片中白色的大部分都比较细小,我们对这张图片做开运算的时候,我们先腐蚀,很容易就让一部分的白色的部分消失掉,那么这个白色的部分消失掉之后对腐蚀后的图片做膨胀消失的白色部分是膨胀不回来的。这些消失的部分就是开运算过程中的不可逆的部分了。

然后我们在后面(img2=开运算前的图像减去开运算后的图像),这一步当中就是得到了开运算中消失的那些白色部分了,这一部分就是开运算过程中的不可逆的部分,然后将它叠加到out上。

然后我们通过对图像不断的腐蚀,开运算,得到了所有这些图像中在开运算中不可逆的部分,就得到了我们的骨架了。

2.假如开运算后的图像和开运算前的图像不一样,那这样的话我们在这一步(img2=开运算前的图像减去开运算后的图像)得到img2中的每一个元素就为0了,那在后面out+=img2这一步的时候就out相当于不变,进入下一步循环在继续把白色部分腐蚀地更小,直到得到开运算中出现了不可逆地部分再叠加到out上。

所以粗暴地来说,骨架提取就是对我们地前景区域,不断地腐蚀,细化前景,直到将前景压缩到细地不能再细了。我们的骨架提取提取的就是这一部分。

二.代码实现

1.预处理

这里我们的图片是以灰度图片方式读取进来的,然后需要阈值处理转换到二值图。

然后我们的图片可能会有一些其他的较大的噪声的影响,我们首先对图像先进行腐蚀操作,手动过滤掉一些滤波可能无法过滤的较大噪声。

'''
用于挑选一个好的二值图
'''
import cv2
import numpy as np
import os

def refine(img_path):
    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
    # thresh, img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    thresh, img = cv2.threshold(img, 50, 255, cv2.THRESH_BINARY)
    h, w = img.shape[0:2]
    #前景背景反转
    for i in range(h):
        for j in range(w):
            if img[i, j] == 255:
                img[i, j] = 0
            else:
                img[i, j] = 255
    cv2.namedWindow("binary", 0)
    cv2.resizeWindow("binary", 640, 480)
    cv2.imshow('binary', img)
    dst = img.copy()

    num_erode = 0

    while (True):
        if np.sum(dst) == 0:
            break
        kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
        dst = cv2.erode(dst, kernel)
        cv2.namedWindow("z", 0)
        cv2.resizeWindow("z", 640, 480)
        cv2.imshow('z', dst)
        c = cv2.waiTKEy(0)
        if c == ord("q"):
            print("保存")
            cv2.imwrite("./refine.png", dst)
            break
        num_erode = num_erode + 1

if __name__ == '__main__':
    refine("input.png")

在这里需要注意的是我们对图像进行二值化可能会将我们的背景和前景反转,在这里我们需要反转回来。否则的话把反转的代码注释掉即可。

我的原图如下:

在这里插入图片描述

然后经过腐蚀的图片如下:

在这里插入图片描述

2. 骨架提取实现

然后下面就是骨架提取的代码了:

'''
骨架提取
'''
import cv2
import numpy as np

#由于我们经过之前的代码转换到了二值图,所以这里不需要转换
img = cv2.imread('refine.png', cv2.IMREAD_GRAYSCALE)
dst = img.copy()

skeleton = np.zeros(dst.shape, np.uint8)
while (True):
    if np.sum(dst) == 0:
        break
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (7, 7))
    dst = cv2.erode(dst, kernel, None, None, 1)
    open_dst = cv2.morphologyEx(dst, cv2.MORPH_OPEN, kernel)
    result = dst - open_dst
    skeleton = skeleton + result
    cv2.waitKey(1)



cv2.namedWindow("result",0)
cv2.resizeWindow("result",640,480)
cv2.imshow('result', skeleton)
cv2.imwrite("output.png",skeleton)

cv2.waitKey(0)
cv2.destroyAllwindows()

在这里我们可以通过开运算的结果元大小来稍微调整一下提取的骨架粗细。

77开运算结构元提取的骨架如下:

在这里插入图片描述

55开运算结构元提取的骨架如下:

在这里插入图片描述

 到此这篇关于深入解析OpenCV骨架提取的算法步骤的文章就介绍到这了,更多相关opencv骨架提取内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 深入解析opencv骨架提取的算法步骤

本文链接: https://www.lsjlt.com/news/117676.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 深入解析opencv骨架提取的算法步骤
    目录前言一.算法步骤1.算法步骤2.分析二.代码实现1.预处理2. 骨架提取实现前言 个人感觉骨架提取提取的就是开运算过程的不可逆。 一.算法步骤 1.算法步骤 首先上一下比较官方的...
    99+
    2024-04-02
  • OpenCV实现无缝克隆算法的步骤详解
    目录一、概述二、函数原型三、OpenCV源码1、源码路径2、源码代码四、效果图像示例一、概述 借助无缝克隆算法,您可以从一张图像中复制一个对象,然后将其粘贴到另一张图像中,从而形成一...
    99+
    2024-04-02
  • OpenCV实现图像去噪算法的步骤详解
    目录一、函数参考1、Primal-dual算法2、非局部均值去噪算法三、OpenCV源码1、源码路径2、源码代码四、效果图像示例一、函数参考 1、Primal-dual算法 Prim...
    99+
    2024-04-02
  • 怎么深入解析Vue3中的diff 算法
    今天给大家介绍一下怎么深入解析Vue3中的diff 算法。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。1.0  diff 无key子节点在处理被标记...
    99+
    2023-06-26
  • 深入解析Go语言的运算符用法
    Go语言中运算符的高级用法解析Go语言作为一门现代化的编程语言,提供了丰富的运算符供开发者使用。除了常规的算术运算符和逻辑运算符外,Go语言还提供了一些高级的运算符,可以帮助开发者更加高效地进行编程。本文将对...
    99+
    2024-01-18
    - 解析 - 高级用法
  • 如何深入理解Python中的Apriori关联分析算法
    今天就跟大家聊聊有关如何深入理解Python中的Apriori关联分析算法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在美国有这样一家奇怪的超市,它将啤酒与尿布这样两个奇怪的东西放...
    99+
    2023-06-02
  • 从 path 存储到算法优化:Python 编程中的关键步骤解析!
    Python 是一种高级编程语言,它被广泛应用于各种领域,如数据科学、机器学习、Web 开发等。Python 的易学性和灵活性使其成为许多程序员和数据科学家的首选编程语言。本文将深入探讨 Python 编程中的关键步骤,从 path 存储...
    99+
    2023-10-04
    编程算法 path 存储
  • 深入解析:Golang开发者不可或缺的时间戳获取方法
    Golang开发者必备:时间戳获取方法解析时间戳是计算机中常用的时间表示方法,它指代自某个固定时间点以来经过的秒数。在Golang中,我们经常需要获取当前时间的时间戳,或者将时间戳转换为具体的日期时间。本文将介绍Golang中常用的时间戳获...
    99+
    2023-12-29
    Golang 时间戳 方法解析
  • 深入解析Go语言中各种运算符的优先级排序方法
    深入解析Go语言中各种运算符的优先级排序方法在Go语言中,运算符的优先级决定了表达式中运算符的计算顺序。正确理解运算符的优先级是编写高效代码的关键之一。本文将深入解析Go语言中各种运算符的优先级排序方法,并提供具体的代码示例。一、算术运算符...
    99+
    2023-12-23
    运算符优先级 Go语言运算符 优先级排序方法
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作