opencv骨架提取算法步骤是什么,代码实现是怎样
Admin 2022-09-19 群英技术资讯 865 次浏览
在这篇文章中我们来了解一下“opencv骨架提取算法步骤是什么,代码实现是怎样”,一些朋友可能会遇到这方面的问题,对此在下文小编向大家来讲解一下,内容详细,易于理解,希望大家阅读完这篇能有收获哦,有需要的朋友就往下看吧!
首先上一下比较官方的算法步骤:
1.获得原图像的首地址及图像的宽和高,并设置循环标志1
2.用结构元素腐蚀原图像,并保存腐蚀结果
3.设置循环标志为0,如果腐蚀结果中有一个点为255,即原图像尚未被完全腐蚀成空集,则将循环标志设为1.
4.用结构元素对腐蚀后的图像进行开运算(消除小的白色区域),并求取腐蚀运算与开运算的差(得到消除的白色区域)
5.用[4]中求得的结果与之前求得的骨架进行并集运算,以获得本次循环求得的骨架
6.把本次循环中保存的腐蚀结果赋值给原图像
7.重复步骤[2]-[6],直到将原图像腐蚀成空集为止。
最终求得的骨架就是结果。
作者的理解是这样的:
输入: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上。
所以粗暴地来说,骨架提取就是对我们地前景区域,不断地腐蚀,细化前景,直到将前景压缩到细地不能再细了。我们的骨架提取提取的就是这一部分。
这里我们的图片是以灰度图片方式读取进来的,然后需要阈值处理转换到二值图。
然后我们的图片可能会有一些其他的较大的噪声的影响,我们首先对图像先进行腐蚀操作,手动过滤掉一些滤波可能无法过滤的较大噪声。
'''
用于挑选一个好的二值图
'''
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")
在这里需要注意的是我们对图像进行二值化可能会将我们的背景和前景反转,在这里我们需要反转回来。否则的话把反转的代码注释掉即可。
我的原图如下:

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

然后下面就是骨架提取的代码了:
'''
骨架提取
'''
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开运算结构元提取的骨架如下:

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
1、数组a第0个元素(二维数组)下的所有子元素(一维数组)的第一列importnumpyasnpb=np arange(24)a=b reshape(2,3,4)printaprinta[0,:,0]
本篇文章给大家带来了关于Python的相关知识,KNN分类算法(K-Nearest-Neighbors Classification),又叫K近邻算法,是一个概念极其简单,而分类效果又很优秀的分类算法,下面一起来看一下,希望对大家有帮助。
本篇将基于Python+Django结合Vue.js前端框架,为大家介绍如何基于这三者的技术栈来实现一个前端后离的Web开发项目。文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
这篇文章主要介绍了如何解决.cuda()加载用时很长的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
split() 方法可以实现将一个字符串按照指定的分隔符切分成多个子串,本文介绍了spilt的具体使用,感兴趣的可以了解一下
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 ICP核准(ICP备案)粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008