针对一副二值图像,区域内的点只有背景点(白点,0值)和前景点(黑点,1值)。对于给定区域的像素点逐次应用两个基本步骤,以提取骨架:
step1,如果一个像素点满足下列4个条件,那么将它标记为要删除的点:
(1)2<=N(p1)<=6,其中N(p1)=p2+p3+p4+...+p8+p9;
(2)T(p1)=1,其中T(p1)是以p2,p3,...,p8,p9,p2的次序旋转,从0到1的变换次数;
(3)p2*p4*p6=0;
(4)p4*p6*p8=0.
step2,条件(1)(2)不变,但是条件(3)(4)变为:
(3)p2*p4*p8=0;
(4)p2*p6*p8=0.
这里,每个像素点的八邻域结构为
p9 | p2 | p3 |
p8 | p1 | p4 |
p7 | p6 | p5 |
基于Mat变换的骨架提取的完整步骤:
(1)执行step1,对需要删除的边界点进行标记;
(2)删除标记点;
(3)执行step2,对需要删除的边界点进行标记;
(4)删除标记点;
(1)到(4)属于一个循环过程,不断反复进行这一循环过程,检测是否存在符合条件的删除点,直到再也找不到可删除的点的时候,说明此时骨架已经生成,结束循环。
1 package com.example.lenovo.linehough; 2 3 import android.graphics.Color; 4 5 public class Mat { 6 7 public static int[] matswitch(int w, int h, int[] inputs) { 8 int[] imgBuf = new int[w * h]; 9 int[] neighbor = new int[10]; 10 int[] mark = new int[w * h]; 11 int markNum1; 12 int markNum2; 13 boolean s = true; 14 for(int index=0;index<w*h;index++) 15 imgBuf[index] = inputs[index]; 16 while (s) { 17 //第一步,统一黑点值为1,白点值为0 18 markNum1 = 0;//步骤1中标记被删除的边界点的个数 19 for (int x = 1; x < w - 1; x++) { 20 for (int y = 1; y < h - 1; y++) { 21 //条件1:p必须是边界点,值为1, 8邻域内至少有1个像素点值为0 22 if (imgBuf[y * w + x] == Color.WHITE) continue; 23 int[] detectBlack = new int[10]; 24 neighbor[2] = ((imgBuf[(y - 1) * w + x] & 0x00ff0000) >> 16) / 255;//黑点neighbor为0,白点neighbor为1 25 neighbor[3] = ((imgBuf[(y - 1) * w + x + 1] & 0x00ff0000) >> 16) / 255; 26 neighbor[4] = ((imgBuf[y * w + x + 1] & 0x00ff0000) >> 16) / 255; 27 neighbor[5] = ((imgBuf[(y + 1) * w + x + 1] & 0x00ff0000) >> 16) / 255; 28 neighbor[6] = ((imgBuf[(y + 1) * w + x] & 0x00ff0000) >> 16) / 255; 29 neighbor[7] = ((imgBuf[(y + 1) * w + x - 1] & 0x00ff0000) >> 16) / 255; 30 neighbor[8] = ((imgBuf[(y) * w + x - 1] & 0x00ff0000) >> 16) / 255; 31 neighbor[9] = ((imgBuf[(y - 1) * w + x - 1] & 0x00ff0000) >> 16) / 255; 32 for (int i = 2; i <= 9; i++) { 33 if (neighbor[i] == 0) 34 detectBlack[i]++;//(黑点)neighbor为0,detectBlack就为1;(白点)neighbor为1,detectBlack就为0 35 } 36 //8领域的点都是黑点,证明该点不是边界点,退出该轮循环,检测下一个点 37 if (detectBlack[2] * detectBlack[3] * detectBlack[4] * detectBlack[5] 38 * detectBlack[6] * detectBlack[7] * detectBlack[8] * detectBlack[9] != 0) 39 continue; 40 41 //条件2:2<=N(p)<=6 42 int np = (detectBlack[2] + detectBlack[3] + detectBlack[4] + detectBlack[5] 43 + detectBlack[6] + detectBlack[7] + detectBlack[8] + detectBlack[9]); 44 if (np < 2 || np > 6) continue; 45 46 //条件3:T(p)=1 47 int tp = 0; 48 for (int i = 3; i <= 9; i++) { 49 /* if(neighbor[i]-neighbor[i-1]==Color.WHITE-Color.BLACK )*/ 50 if (detectBlack[i] - detectBlack[i - 1] == 1) 51 tp++; 52 } 53 if (detectBlack[2] - detectBlack[9] == 1) 54 tp++; 55 if (tp != 1) continue; 56 57 //条件4:p2*p4*p6=0 58 if (detectBlack[2] * detectBlack[4] * detectBlack[6] != 0) 59 continue; 60 //条件5:p4*p6*p8=0 61 if (detectBlack[4] * detectBlack[6] * detectBlack[8] != 0) 62 continue; 63 64 //标记要被删除的点 65 mark[y * w + x] = 1; 66 markNum1++; 67 } 68 } 69 70 //将标记删除的点置为背景色 71 if (markNum1 > 0) { 72 for (int x = 1; x < w - 1; x++) { 73 for (int y = 1; y < h - 1; y++) { 74 //删除被标记的点,即置为背景色黑色 75 if (mark[y * w + x] == 1) { 76 imgBuf[y * w + x] = Color.WHITE; 77 } 78 } 79 } 80 } 81 82 83 //第二步 84 markNum2 = 0;//步骤2中标记被删除的点的个数 85 for (int x = 1; x < w - 1; x++) { 86 for (int y = 1; y < h - 1; y++) { 87 //条件1:p必须是前景点BLACK 88 if (imgBuf[y * w + x] == Color.WHITE) continue; 89 int[] detectBlack = new int[10]; 90 neighbor[2] = ((imgBuf[(y - 1) * w + x] & 0x00ff0000) >> 16) / 255; 91 neighbor[3] = ((imgBuf[(y - 1) * w + x + 1] & 0x00ff0000) >> 16) / 255; 92 neighbor[4] = ((imgBuf[y * w + x + 1] & 0x00ff0000) >> 16) / 255; 93 neighbor[5] = ((imgBuf[(y + 1) * w + x + 1] & 0x00ff0000) >> 16) / 255; 94 neighbor[6] = ((imgBuf[(y + 1) * w + x] & 0x00ff0000) >> 16) / 255; 95 neighbor[7] = ((imgBuf[(y + 1) * w + x - 1] & 0x00ff0000) >> 16) / 255; 96 neighbor[8] = ((imgBuf[(y) * w + x - 1] & 0x00ff0000) >> 16) / 255; 97 neighbor[9] = ((imgBuf[(y - 1) * w + x - 1] & 0x00ff0000) >> 16) / 255; 98 for (int i = 2; i < 10; i++) { 99 if (neighbor[i] == 0) detectBlack[i]++; 100 } 101 102 if (detectBlack[2] * detectBlack[3] * detectBlack[4] * detectBlack[5] 103 * detectBlack[6] * detectBlack[7] * detectBlack[8] * detectBlack[9] != 0) 104 continue; 105 106 //条件2:2<=N(p)<=6 107 int np = (detectBlack[2] + detectBlack[3] + detectBlack[4] + detectBlack[5] 108 + detectBlack[6] + detectBlack[7] + detectBlack[8] + detectBlack[9]); 109 if (np < 2 || np > 6) continue; 110 111 //条件3:T(p)=1 112 int tp = 0; 113 for (int i = 3; i <= 9; i++) { 114 /* if(neighbor[i]-neighbor[i-1]==Color.WHITE-Color.BLACK )*/ 115 if (detectBlack[i] - detectBlack[i - 1] == 1) 116 tp++; 117 } 118 if (detectBlack[2] - detectBlack[9] == 1) 119 tp++; 120 if (tp != 1) continue; 121 122 //条件4:p2*p4*p8==0 123 if (detectBlack[2] * detectBlack[4] * detectBlack[8] != 0) 124 continue; 125 //条件5:p2*p6*p8==0 126 if (detectBlack[2] * detectBlack[6] * detectBlack[8] != 0) 127 continue; 128 129 //标记删除 130 mark[y * w + x] = 1; 131 markNum2++; 132 } 133 } 134 135 //将标记删除的点置为背景色WHITE 136 if (markNum2 > 0) { 137 for (int x = 1; x < w - 1; x++) { 138 for (int y = 1; y < h - 1; y++) { 139 if (mark[y * w + x] == 1) { 140 imgBuf[y * w + x] = Color.WHITE; 141 } 142 } 143 } 144 } 145 //先步骤1再步骤2,一次周期循环后,不再出现标记删除的点时,说明已生成骨架了 146 if (markNum1 == 0 && markNum2 == 0) s = false; 147 else s = true; 148 } 149 return imgBuf; 150 } 151 152 153 }