图像处理之Zhang Suen细化算法

ゝ一纸荒年。 2022-07-14 04:55 419阅读 0赞

转载自:http://blog.csdn.net/jia20003/article/details/52142992

在二值图像处理特别是OCR识别与匹配中,都要通过对字符进行细化以便获得图像的骨架,通过zhang-suen细化算法获得图像,作为图像的特征之一,常用来作为识别或者模式匹配。

一:算法介绍

Zhang-Suen细化算法通常是一个迭代算法,整个迭代过程分为两步:

Step One:循环所有前景像素点,对符合如下条件的像素点标记为删除:

  1. 2 <= N(p1) <=6

  2. S(P1) = 1

  3. P2 * P4 * P6 = 0

  4. P4 * P6 * P8 = 0

其中N(p1)表示跟P1相邻的8个像素点中,为前景像素点的个数

S(P1)表示从P2 ~ P9 ~ P2像素中出现0~1的累计次数,其中0表示背景,1表示前景

完整的P1 ~P9的像素位置与举例如下:

20160807160046220

其中 N(p1) = 4, S(P1) = 3, P2*P4*P6=0*0*0=0, P4*P6*P8=0*0*1=0, 不符合条件,无需标记为删除。

Step Two:跟Step One很类似,条件1、2完全一致,只是条件3、4稍微不同,满足如下条件的像素P1则标记为删除,条件如下:

  1. 2 <= N(p1) <=6

  2. S(P1) = 1

  3. P2 * P4 * P8 = 0

  4. P2 * P6 * P8 = 0

循环上述两步骤,直到两步中都没有像素被标记为删除为止,输出的结果即为二值图像细化后的骨架。

二:代码实现步骤

  1. 二值化输入图像,初始化图像像素对应的标记映射数组

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. BufferedImage binaryImage = super.process(image);
  2. int width = binaryImage.getWidth();
  3. int height = binaryImage.getHeight();
  4. int[] pixels = new**int*[width\height];
  5. int[] flagmap = new**int*[width\height];
  6. getRGB(binaryImage, 0, 0, width, height, pixels);
  7. Arrays.fill(flagmap, 0);

  8. 迭代细化算法(Zhang-Suen)

a. Step One

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. private**boolean step1Scan(int[] input, int[] flagmap, int width, int** height) {
  2. boolean stop = true;
  3. int bc = 255 - fcolor;
  4. int p1=0, p2=0, p3=0;
  5. int p4=0, p5=0, p6=0;
  6. int p7=0, p8=0, p9=0;
  7. int offset = 0;
  8. for(int row=1; row<height-1; row++) {
  9. offset = row*width;
  10. for(int col=1; col<width-1; col++) {
  11. p1 = (input[offset+col]>>16)&0xff;
  12. if(p1 == bc) continue;
  13. p2 = (input[offset-width+col]>>16)&0xff;
  14. p3 = (input[offset-width+col+1]>>16)&0xff;
  15. p4 = (input[offset+col+1]>>16)&0xff;
  16. p5 = (input[offset+width+col+1]>>16)&0xff;
  17. p6 = (input[offset+width+col]>>16)&0xff;
  18. p7 = (input[offset+width+col-1]>>16)&0xff;
  19. p8 = (input[offset+col-1]>>16)&0xff;
  20. p9 = (input[offset-width+col-1]>>16)&0xff;
  21. // match 1 - 前景像素 0 - 背景像素
  22. p1 = (p1 == fcolor) ? 1 : 0;
  23. p2 = (p2 == fcolor) ? 1 : 0;
  24. p3 = (p3 == fcolor) ? 1 : 0;
  25. p4 = (p4 == fcolor) ? 1 : 0;
  26. p5 = (p5 == fcolor) ? 1 : 0;
  27. p6 = (p6 == fcolor) ? 1 : 0;
  28. p7 = (p7 == fcolor) ? 1 : 0;
  29. p8 = (p8 == fcolor) ? 1 : 0;
  30. p9 = (p9 == fcolor) ? 1 : 0;
  31. int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
  32. String sequence = “” + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
  33. String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
  34. int index1 = sequence.indexOf(“01”);
  35. int index2 = sequence.lastIndexOf(“01”);
  36. int con3 = p2*p4*p6;
  37. int con4 = p4*p6*p8;
  38. if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
  39. flagmap[offset+col] = 1;
  40. stop = false;
  41. }
  42. }
  43. }
  44. return stop;
  45. }

b. Step Two

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. private**boolean step2Scan(int[] input, int[] flagmap, int width, int** height) {
  2. boolean stop = true;
  3. int bc = 255 - fcolor;
  4. int p1=0, p2=0, p3=0;
  5. int p4=0, p5=0, p6=0;
  6. int p7=0, p8=0, p9=0;
  7. int offset = 0;
  8. for(int row=1; row<height-1; row++) {
  9. offset = row*width;
  10. for(int col=1; col<width-1; col++) {
  11. p1 = (input[offset+col]>>16)&0xff;
  12. if(p1 == bc) continue;
  13. p2 = (input[offset-width+col]>>16)&0xff;
  14. p3 = (input[offset-width+col+1]>>16)&0xff;
  15. p4 = (input[offset+col+1]>>16)&0xff;
  16. p5 = (input[offset+width+col+1]>>16)&0xff;
  17. p6 = (input[offset+width+col]>>16)&0xff;
  18. p7 = (input[offset+width+col-1]>>16)&0xff;
  19. p8 = (input[offset+col-1]>>16)&0xff;
  20. p9 = (input[offset-width+col-1]>>16)&0xff;
  21. // match 1 - 前景像素 0 - 背景像素
  22. p1 = (p1 == fcolor) ? 1 : 0;
  23. p2 = (p2 == fcolor) ? 1 : 0;
  24. p3 = (p3 == fcolor) ? 1 : 0;
  25. p4 = (p4 == fcolor) ? 1 : 0;
  26. p5 = (p5 == fcolor) ? 1 : 0;
  27. p6 = (p6 == fcolor) ? 1 : 0;
  28. p7 = (p7 == fcolor) ? 1 : 0;
  29. p8 = (p8 == fcolor) ? 1 : 0;
  30. p9 = (p9 == fcolor) ? 1 : 0;
  31. int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
  32. String sequence = “” + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
  33. String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
  34. int index1 = sequence.indexOf(“01”);
  35. int index2 = sequence.lastIndexOf(“01”);
  36. int con3 = p2*p4*p8;
  37. int con4 = p2*p6*p8;
  38. if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
  39. flagmap[offset+col] = 1;
  40. stop = false;
  41. }
  42. }
  43. }
  44. return stop;
  45. }

c. 检查如果上述两部没有任何像素被标记,则停止迭代,否则继续执行a, b

  1. 返回细化后的图像,并显示

三:运行效果

20160807160207570

四:完整的Zhang-suen算法代码实现:

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. import java.awt.image.BufferedImage;
  2. import java.util.Arrays;
  3. public**class ZhangSuenThinFilter extends** BinaryFilter {
  4. private**int** fcolor;
  5. public ZhangSuenThinFilter() {
  6. fcolor = 0;
  7. }
  8. public**int** getFcolor() {
  9. return fcolor;
  10. }
  11. public**void setFcolor(int** fcolor) {
  12. this.fcolor = fcolor;
  13. }
  14. @Override
  15. public BufferedImage process(BufferedImage image) {
  16. BufferedImage binaryImage = super.process(image);
  17. int width = binaryImage.getWidth();
  18. int height = binaryImage.getHeight();
  19. int[] pixels = new**int*[width\height];
  20. int[] flagmap = new**int*[width\height];
  21. getRGB(binaryImage, 0, 0, width, height, pixels);
  22. Arrays.fill(flagmap, 0);
  23. // 距离变化
  24. boolean stop = false;
  25. while(!stop) {
  26. // step one
  27. boolean s1 = step1Scan(pixels, flagmap, width, height);
  28. deletewithFlag(pixels, flagmap);
  29. Arrays.fill(flagmap, 0);
  30. // step two
  31. boolean s2 = step2Scan(pixels, flagmap, width, height);
  32. deletewithFlag(pixels, flagmap);
  33. Arrays.fill(flagmap, 0);
  34. if(s1 && s2) {
  35. stop = true;
  36. }
  37. }
  38. // 结果
  39. BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
  40. setRGB(bi, 0, 0, width, height, pixels);
  41. return bi;
  42. }
  43. private**void deletewithFlag(int[] pixels, int**[] flagmap) {
  44. int bc = 255 - fcolor;
  45. for(int i=0; i<pixels.length; i++) {
  46. if(flagmap[i] == 1) {
  47. pixels[i] = (0xff << 24) | ((bc&0xff) << 16) | ((bc&0xff) << 8) | (bc&0xff);
  48. }
  49. }
  50. }
  51. private**boolean step1Scan(int[] input, int[] flagmap, int width, int** height) {
  52. boolean stop = true;
  53. int bc = 255 - fcolor;
  54. int p1=0, p2=0, p3=0;
  55. int p4=0, p5=0, p6=0;
  56. int p7=0, p8=0, p9=0;
  57. int offset = 0;
  58. for(int row=1; row<height-1; row++) {
  59. offset = row*width;
  60. for(int col=1; col<width-1; col++) {
  61. p1 = (input[offset+col]>>16)&0xff;
  62. if(p1 == bc) continue;
  63. p2 = (input[offset-width+col]>>16)&0xff;
  64. p3 = (input[offset-width+col+1]>>16)&0xff;
  65. p4 = (input[offset+col+1]>>16)&0xff;
  66. p5 = (input[offset+width+col+1]>>16)&0xff;
  67. p6 = (input[offset+width+col]>>16)&0xff;
  68. p7 = (input[offset+width+col-1]>>16)&0xff;
  69. p8 = (input[offset+col-1]>>16)&0xff;
  70. p9 = (input[offset-width+col-1]>>16)&0xff;
  71. // match 1 - 前景像素 0 - 背景像素
  72. p1 = (p1 == fcolor) ? 1 : 0;
  73. p2 = (p2 == fcolor) ? 1 : 0;
  74. p3 = (p3 == fcolor) ? 1 : 0;
  75. p4 = (p4 == fcolor) ? 1 : 0;
  76. p5 = (p5 == fcolor) ? 1 : 0;
  77. p6 = (p6 == fcolor) ? 1 : 0;
  78. p7 = (p7 == fcolor) ? 1 : 0;
  79. p8 = (p8 == fcolor) ? 1 : 0;
  80. p9 = (p9 == fcolor) ? 1 : 0;
  81. int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
  82. String sequence = “” + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
  83. String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
  84. int index1 = sequence.indexOf(“01”);
  85. int index2 = sequence.lastIndexOf(“01”);
  86. int con3 = p2*p4*p6;
  87. int con4 = p4*p6*p8;
  88. if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
  89. flagmap[offset+col] = 1;
  90. stop = false;
  91. }
  92. }
  93. }
  94. return stop;
  95. }
  96. private**boolean step2Scan(int[] input, int[] flagmap, int width, int** height) {
  97. boolean stop = true;
  98. int bc = 255 - fcolor;
  99. int p1=0, p2=0, p3=0;
  100. int p4=0, p5=0, p6=0;
  101. int p7=0, p8=0, p9=0;
  102. int offset = 0;
  103. for(int row=1; row<height-1; row++) {
  104. offset = row*width;
  105. for(int col=1; col<width-1; col++) {
  106. p1 = (input[offset+col]>>16)&0xff;
  107. if(p1 == bc) continue;
  108. p2 = (input[offset-width+col]>>16)&0xff;
  109. p3 = (input[offset-width+col+1]>>16)&0xff;
  110. p4 = (input[offset+col+1]>>16)&0xff;
  111. p5 = (input[offset+width+col+1]>>16)&0xff;
  112. p6 = (input[offset+width+col]>>16)&0xff;
  113. p7 = (input[offset+width+col-1]>>16)&0xff;
  114. p8 = (input[offset+col-1]>>16)&0xff;
  115. p9 = (input[offset-width+col-1]>>16)&0xff;
  116. // match 1 - 前景像素 0 - 背景像素
  117. p1 = (p1 == fcolor) ? 1 : 0;
  118. p2 = (p2 == fcolor) ? 1 : 0;
  119. p3 = (p3 == fcolor) ? 1 : 0;
  120. p4 = (p4 == fcolor) ? 1 : 0;
  121. p5 = (p5 == fcolor) ? 1 : 0;
  122. p6 = (p6 == fcolor) ? 1 : 0;
  123. p7 = (p7 == fcolor) ? 1 : 0;
  124. p8 = (p8 == fcolor) ? 1 : 0;
  125. p9 = (p9 == fcolor) ? 1 : 0;
  126. int con1 = p2+p3+p4+p5+p6+p7+p8+p9;
  127. String sequence = “” + String.valueOf(p2) + String.valueOf(p3) + String.valueOf(p4) + String.valueOf(p5) +
  128. String.valueOf(p6) + String.valueOf(p7) + String.valueOf(p8) + String.valueOf(p9) + String.valueOf(p2);
  129. int index1 = sequence.indexOf(“01”);
  130. int index2 = sequence.lastIndexOf(“01”);
  131. int con3 = p2*p4*p8;
  132. int con4 = p2*p6*p8;
  133. if((con1 >= 2 && con1 <= 6) && (index1 == index2) && con3 == 0 && con4 == 0) {
  134. flagmap[offset+col] = 1;
  135. stop = false;
  136. }
  137. }
  138. }
  139. return stop;
  140. }
  141. }

发表评论

表情:
评论列表 (有 0 条评论,419人围观)

还没有评论,来说两句吧...

相关阅读

    相关 opencv实现图像细化效果

    在图像处理中,有时候我们会想要提取图像的骨架,这是就需要对图像进行细化,opencv中没有直接进行细化的算法,网上大部分的细化算法都是基于以前IplImage结构的,对于想要使

    相关 图像处理-sift算法

    sift是图像匹配的非常经典的算法,但是很复杂,要想自己拿C或C++实现很麻烦,如果只是使用的话,有国外某高人维护的sift库,前期只要自己能够调用即可,关键是要熟悉大致的流程

    相关 图像处理基本算法

    使用openCV进行图像处理,总感觉并不能真正的理解图像处理的核心内容,因此我感觉对图像处理的理解才是关键。 基本的反色操作,主要是了解OpenCV对图像数据的操作方式:指针

    相关 Opencv处理图像--细化

    Opencv处理图像--细化 细化的算法有很多种,但比较常用的算法是查表法 细化是从原来的图中去掉一些点,但仍要保持原来的形状。 实际上是保持原图的骨架。 代码如上