当前位置:   article > 正文

图像细化(骨骼获取)OpenCV3.0 Python_灰度图像细化

灰度图像细化

原作者(opencv 2):https://www.cnblogs.com/xianglan/archive/2011/01/01/1923779.html

方法1(python版):https://blog.csdn.net/hehedadaq/article/details/80303218

最近做项目用到图像细化算法,上网找了一下很少有用python的,找到一个还是opencv2的,无法使用,简单加以修改.

其中第一种算法速度较快,但效果并不理想;第二种算法效果比较理想,但速度很慢.


首先介绍图像细化:

图像细化主要是针对二值图而言,所谓骨架,可以理解为图像的中轴,,一个长方形的骨架,是它的长方向上的中轴线,圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。我们来看看典型的图形的骨架(用粗线表示)

细化的算法有很多种,但比较常用的算法是查表法

细化是从原来的图中去掉一些点,但仍要保持原来的形状。实际上是保持原图的骨架。判断一个点是否能去掉是以8个相邻点(八连通)的情况来作为判据的,具体判据为:

  1. 内部点不能删除
  2. 孤立点不能删除
  3. 直线端点不能删除
  4. 如果P是边界点,去掉P后,如果连通分量不增加,则P可删除

看看上面那些点,就是3*3矩阵中的中心点。

第一个点不能去除,因为它是内部点

第二个点不能去除,它也是内部点

第三个点不能去除,删除后会使原来相连的部分断开

第四个点可以去除,这个点不是骨架

第五个点不可以去除,它是直线的端点

第六个点不可以去除,它是直线的端点

等等~图中无法列举出所有的情况,所以我们将有一个算法和映射,将所有的情况用表格的形式列举出来,如下图所示

即假设我们要求,某个点是否需要被细化(去除),我们需要将它周围的八个点都列出来,形成一个矩阵,标号好,如上图,然后每个位置的点,赋予不同的权值,即右边的表格值,就可以将每一种情况列举出来了。

我们对于黑色的像素点,对于它周围的8个点,我们赋予不同的权值,若周围为黑色,我们认为其权值为0,为白色则取九宫格中对应的权值,这个其实根据你自己图像中的值来确定,如果你的目标值本身就是白色,那么效果肯定相反

对于前面那幅图中第一个图,也就是内部点,它周围的点都是黑色,所以它的总价值是0,对应于索引表的第一项。

前面那幅图中第二点,它周围有三个白色点,它的总价值为1+4+32=37,对应于索引表中第三十八项

我们用这种方法,把所有点的情况映射到0~255的索引表中

 索引表也就是下面的16*16矩阵:

array = [  0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\

        1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\

         0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\

        1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\

        1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\

        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\

        1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\

        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\

        0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\

        1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\

        0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\

        1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\

         1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\

        1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\

        1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\

        1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]

方法一:

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Sat May 12 16:36:06 2018
  4. @author: lele
  5. """
  6. import cv2
  7. #细化函数,输入需要细化的图片(经过二值化处理的图片)和映射矩阵array
  8. #这个函数将根据算法,运算出中心点的对应值
  9. def Thin(image,array):
  10. h,w = image.shape
  11. iThin = image
  12. for i in range(h):
  13. for j in range(w):
  14. if image[i,j] == 0:
  15. a = [1]*9
  16. for k in range(3):
  17. for l in range(3):
  18. #如果3*3矩阵的点不在边界且这些值为零,也就是黑色的点
  19. if -1<(i-1+k)<h and -1<(j-1+l)<w and iThin[i-1+k,j-1+l]==0:
  20. a[k*3+l] = 0
  21. sum = a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
  22. #然后根据array表,对ithin的那一点进行赋值。
  23. iThin[i,j] = array[sum]*255
  24. return iThin
  25. #最简单的二值化函数,阈值根据图片的昏暗程度自己设定,我选的180
  26. def Two(image):
  27. w,h = image.shape
  28. size = (w,h)
  29. iTwo = image
  30. for i in range(w):
  31. for j in range(h):
  32. if image[i,j]<180:
  33. iTwo[i,j] = 0
  34. else:
  35. iTwo[i,j] = 255
  36. return iTwo
  37. #映射表
  38. array = [0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  39. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
  40. 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  41. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
  42. 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
  43. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
  44. 1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\
  45. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
  46. 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  47. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
  48. 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  49. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
  50. 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
  51. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
  52. 1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\
  53. 1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]
  54. #读取灰度图片,并显示
  55. img = cv2.imread('letter.jpg',0) #直接读为灰度图像
  56. cv2.imshow('image',img)
  57. cv2.waitKey(0)
  58. #自适应二值化函数,需要修改的是55那个位置的数字,越小越精细,细节越好,噪点更多,最大不超过图片大小
  59. th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,55,2) #换行符号 \
  60. cv2.imshow('iTwo',th3)
  61. cv2.waitKey(0)
  62. #获取自适应二值化的细化图,并显示
  63. iThin = Thin(th3,array)
  64. cv2.imshow('iThin',iThin)
  65. cv2.waitKey(0)
  66. #获取简单二值化的细化图,并显示
  67. iTwo = Two(img)
  68. iThin_2 = Thin(iTwo,array)
  69. cv2.imshow('iTwo_2',iThin_2)
  70. cv2.waitKey(0)
  71. cv2.destroyAllWindows()

方法二: 我自己在中间加了高斯滤波和腐蚀操作,使图像效果更好一些.另外直接用自适应二值化函数获取二值化图像.

  1. # -*- coding: utf-8 -*-
  2. import cv2
  3. def VThin(image,array):
  4. h,w = image.shape
  5. NEXT = 1
  6. for i in range(h):
  7. for j in range(w):
  8. if NEXT == 0:
  9. NEXT = 1
  10. else:
  11. M = int(image[i,j-1])+int(image[i,j])+int(image[i,j+1]) if 0<j<w-1 else 1
  12. if image[i,j] == 0 and M != 0:
  13. a = [0]*9
  14. for k in range(3):
  15. for l in range(3):
  16. if -1<(i-1+k)<h and -1<(j-1+l)<w and image[i-1+k,j-1+l]==255:
  17. a[k*3+l] = 1
  18. sum = a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
  19. image[i,j] = array[sum]*255
  20. if array[sum] == 1:
  21. NEXT = 0
  22. return image
  23. def HThin(image,array):
  24. h,w = image.shape
  25. NEXT = 1
  26. for j in range(w):
  27. for i in range(h):
  28. if NEXT == 0:
  29. NEXT = 1
  30. else:
  31. M = int(image[i-1,j])+int(image[i,j])+int(image[i+1,j]) if 0<i<h-1 else 1
  32. if image[i,j] == 0 and M != 0:
  33. a = [0]*9
  34. for k in range(3):
  35. for l in range(3):
  36. if -1<(i-1+k)<h and -1<(j-1+l)<w and image[i-1+k,j-1+l]==255:
  37. a[k*3+l] = 1
  38. sum = a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
  39. image[i,j] = array[sum]*255
  40. if array[sum] == 1:
  41. NEXT = 0
  42. return image
  43. def Xihua(image,array,num=10):
  44. for i in range(num):
  45. VThin(image,array)
  46. HThin(image,array)
  47. return image
  48. def main(path):
  49. #映射表
  50. array = [0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  51. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
  52. 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  53. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
  54. 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
  55. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
  56. 1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\
  57. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
  58. 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  59. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
  60. 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
  61. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
  62. 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
  63. 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
  64. 1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\
  65. 1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]
  66. #读取灰度图片,并显示
  67. img = cv2.imread(path,0) #直接读为灰度图像
  68. cv2.imshow('image',img)
  69. cv2.waitKey(0)
  70. gaussian_img = cv2.GaussianBlur(img, (5, 5),5)
  71. kernel3 = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
  72. dilate_img = cv2.dilate(gaussian_img,kernel3)
  73. binary_img = cv2.adaptiveThreshold(dilate_img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,99,5)
  74. cv2.imshow('binary',binary_img)
  75. cv2.waitKey(0)
  76. xihua_img = Xihua(binary_img,array)
  77. cv2.imshow('xihua',xihua_img)
  78. cv2.waitKey(0)
  79. cv2.destroyAllWindows()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/605134
推荐阅读
相关标签
  

闽ICP备14008679号