基于红黑树的骨架提取Java

前面有提到基于Mat变换的骨架提取,然而在实际的应用中处理稍微大点的图片的时候耗时较长就是个问题了,于是针对这个问题寻找了另外一种方法——基于红黑树的骨架提取,这种方法明显处理速度要快一些。

基于红黑树的骨架提取的思路如下:

1,对输入的二值图像进行延拓(直白的说就是在图像的外边界加一圈白点),得到二值图像P;

2,针对骨架提取有8种结构类型(S0~S7)的待删除点。骨架提取的过程实际上就是不断的找符合这8种结构的待删除点,删除待删除点。初始化8个空的红黑树结构T0~T7,初始化current=0,每一个红黑树对应存储一种类别的待删除点,例如:T0存储符合S0结构的待删除点,T1存储符合S1结构的待删除点......;

3,初始化标记矩阵L;

4,遍历P,确定所有待移除点及其对应的红黑树索引值,将待移除点的索引值插入对应的红黑树,;

5,判断T0~T7是否都为空,如果是,则已完成骨架提取,返回P。如果不是全为空,初始化round=0,到下一步;

6,判断round是否等于8,如果是返回第5步,如果不是,到下一步;

7,用数组R记录Tcurrent中的所有区域点索引值,清空Tcurrent,更新current=current+1;

8,根据R更新P,L和T0~T7,round=round+1,返回第6步。

  1 package com.example.lenovo.linehough;
  2 
  3 import android.graphics.Color;
  4 
  5 public class Framework {
  6     int width;
  7     int height;
  8     int Fpn;
  9     int[] pixels;
 10     int[] treeValue;
 11     GRBTree[] grbTree;
 12     int currentTree;
 13     TList[] L;
 14     int[] InfluencedPnt;
 15     int lutTreeNum[] = {
 16             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 17             0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 2,
 18             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 19             0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1,
 20             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 21             0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 1, 1,
 22             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 23             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 24             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 25             0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
 26             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 27             1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 28             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 29             0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 0, 0,
 30             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 31             1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 32             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 33             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 34             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 35             0, 0, 1, 1, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
 36             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 37             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 38             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 39             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 40             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 41             0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
 42             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 43             1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 44             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 45             1, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0,
 46             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 47             2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
 48     };
 49 
 50     int lutTreeIdx1[] = {
 51             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 52             0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 3, 2,
 53             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 54             0, 0, 5, 5, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 2,
 55             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 56             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 3,
 57             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 58             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 59             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 60             0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
 61             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 62             7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 63             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 64             0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
 65             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 66             7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 67             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 68             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 69             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 70             0, 0, 5, 5, 6, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
 71             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 72             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 73             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 74             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 75             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 76             0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
 77             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 78             7, 0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 79             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 80             4, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
 81             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 82             4, 0, 0, 0, 7, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0
 83     };
 84 
 85     int lutTreeIdx2[] = {
 86             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 87             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
 88             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 89             0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
 90             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 91             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
 92             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 93             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 94             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 95             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 96             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 97             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 98             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 99             0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
100             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105             0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
109             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113             0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115             0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
116             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117             7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
118     };
119 
120     public Framework() {
121 
122     }
123 
124     //TList建立一个矩阵,矩阵元素包含TreeIndex,Visited两个字段;
125     // TreeIndex记录待移除点对应的红黑树序号(0~7),TreeIndex为-1时,该点为非移除点;Visited标记点是否被访问过了
126     public class TList {
127         int TreeIndex;
128         int Visited;
129 
130         public TList() {
131             this.TreeIndex = -1;
132             this.Visited = 0;
133         }
134     }
135 
136     //提取骨架
137     public int[] getFramework(int w, int h, int[] inputs) {
138         width = w;
139         height = h;
140         pixels = new int[width * height];
141         //黑色为1,白色为0
142         for (int y = 0; y < height; y++) {
143             for (int x = 0; x < width; x++) {
144                 if (inputs[y * width + x] == Color.BLACK)
145                     pixels[y * width + x] = 1;
146                 else pixels[y * width + x] = 0;
147             }
148         }
149         //新建8个红黑树对象
150         grbTree = new GRBTree[8];
151         for (int i = 0; i <= 7; i++) {
152             grbTree[i] = new GRBTree();
153         }
154         currentTree = 0;
155 
156         L = new TList[width * height];
157         for (int i = 0; i < width * height; i++) {
158             L[i] = new TList();
159         }
160         //第一次遍历二值化图像
161         FirstMatchTree();
162 
163         //当所有的树里面不再插入结点的时候,说明骨架已经生成,即n0~n7都为0
164         while (grbTree[0].root != null || grbTree[1].root != null || grbTree[2].root != null || grbTree[3].root != null ||
165                 grbTree[4].root != null || grbTree[5].root != null || grbTree[6].root != null || grbTree[7].root != null) {
166             for (int round = 0; round <= 7; round++) {
167                 treeValue = new int[width * height];
168                 //前序遍历树currentTree的移除点索引值,将它们先存放在数组treeValue里面
169                 treeValue = grbTree[currentTree].preOrder(width, height);
170                 //存放在树currentTree里面的移除点总数
171                 int valueCount = grbTree[currentTree].getiCount();
172 
173                 //再清空树currentTree里面的数据,root置为null
174                 grbTree[currentTree].Free();
175 
176                 currentTree++;
177                 if (currentTree == 8) currentTree = 0;
178 
179                 //更新pixels,L
180                 for (int i1 = 0; i1 < valueCount; i1++) {
181                     int pntIndex = treeValue[i1];
182                     pixels[pntIndex] = 0;
183                     L[pntIndex].TreeIndex = -1;//TreeIndex为-1时,该点为非移除点
184                     L[pntIndex].Visited = -1;//Visited为-1时,表明该点已成为非待移除点
185                 }
186                 //遍历数组treeValue,InfluencedPnt记录受影响的领域点坐标,Fpn为受影响点的个数
187                 InfluencedPnt = new int[width * height];
188                 Fpn = 0;
189                 for (int i1 = 0; i1 < valueCount; i1++) {
190                     int pntIndex = treeValue[i1];
191                     //查找移除点的8领域点
192                     for (int i2 = -1; i2 <= 1; i2++) {
193                         for (int i3 = -1; i3 <= 1; i3++) {
194                             if (i2 == 0 && i3 == 0) continue;
195                             //8个领域点的下标索引值index
196                             int index = pntIndex + i2 * width + i3;
197                             if (index < 0) index = 0;
198                             if (index > width * height - 1)
199                                 index = width * height - 1;
200                             //该领域点为白点直接退出
201                             if (pixels[index] == 0) continue;
202                             //Visite为1时,表明该领域点已被访问过,直接退出;
203                             if (L[index].Visited == 1) continue;
204                             else {
205                                 L[index].Visited = 1;
206                                 InfluencedPnt[Fpn] = index;
207                                 Fpn++;
208                             }
209                             //更新树T0到T7,只要检测到8领域点是待移除点的话,首先将它从原来的树里面删除;不是的话,不操作;
210                             // 之后再根据该领域点的3*3结构(可能发生变化)来判断它是否是待移除点,以及它该插入到哪棵红黑树里面
211                             int treeindex = L[index].TreeIndex;
212                             if (treeindex >= 0)
213                                 grbTree[treeindex].Delete(index);
214                             //获取领域点index的3*3结构
215                             int[] b = new int[9];
216                             for (int i4 = -1; i4 <= 1; i4++) {
217                                 for (int i5 = -1; i5 <= 1; i5++) {
218                                     int index8 = index + i5 * width + i4;
219                                     if (index8 < 0) index = 0;
220                                     if (index8 > width * height - 1)
221                                         index8 = width * height - 1;
222                                     b[(i4 + 1) * 3 + (i5 + 1)] = pixels[index8];
223                                 }
224                             }
225                             //计算领域点index对应的lutTreeNum的下标值lutValue
226                             int lutValue = 0;
227                             for (int i = 0; i <= 8; i++) {
228                                 if (b[i] == 1)
229                                     lutValue += Math.pow(2, i);
230                             }
231                             //将待移除的领域点index插入对应的红黑树k里面,并将k值记录到L中
232                             int k = Put(index, lutValue);
233                             if (k >= 0) L[index].TreeIndex = k;
234                             else L[index].TreeIndex = -1;
235                         }
236                     }
237                 }
238 
239                 for (int i = 0; i < Fpn; i++) {
240                     int f = InfluencedPnt[i];
241                     L[f].Visited = 0;
242                 }
243 
244             }
245         }
246         //while循环结束,再也没有移除点
247         for (int y = 0; y < height; y++) {
248             for (int x = 0; x < width; x++) {
249                 if (pixels[y * width + x] == 1) inputs[y * width + x] = Color.BLACK;
250                 else inputs[y * width + x] = Color.WHITE;
251             }
252         }
253         return inputs;
254     }
255 
256     private void FirstMatchTree() {
257         //第一次遍历二值化图像,currentTree=0,把待移除点插入对应的红黑树里面
258         for (int y = 1; y < height - 1; y++) {
259             for (int x = 1; x < width - 1; x++) {
260                 int pntIndex = y * width + x;
261                 //是白色点的话直接退出本次循环,检测下一个点
262                 if (pixels[pntIndex] == 0) continue;
263                 //检测像素点的3*3领域结构,组成a[8]a[7]...a[1]a[0]的九位二进制数
264                 int[] a = new int[9];
265                 for (int i = -1; i <= 1; i++) {
266                     for (int j = -1; j <= 1; j++) {
267                         a[(i + 1) * 3 + (j + 1)] = pixels[(y + j) * width + (x + i)];
268                     }
269                 }
270                 //通过上面的九位二进制数,计算出该像素点对应于lutTreeNum的下标值
271                 int lutValue = 0;
272                 for (int i = 0; i <= 8; i++) {
273                     if (a[i] == 1)
274                         lutValue += Math.pow(2, i);
275                 }
276                 //k为树的序号数,pntIndex为待移除点的话,k的范围为0到7;不是待移除点的话,k为-1
277                 int k = Put(pntIndex, lutValue);
278                 if (k >= 0) L[pntIndex].TreeIndex = k;
279                 else L[pntIndex].TreeIndex = -1;
280             }
281         }
282     }
283 
284     private int GetTreeIndex(int lutValue) {
285         if (lutTreeNum[lutValue] == 0)
286             return -1;
287 
288         if (lutTreeNum[lutValue] == 1)
289             return lutTreeIdx1[lutValue];
290 
291         if (currentTree > lutTreeIdx1[lutValue] && currentTree <= lutTreeIdx2[lutValue])
292             return lutTreeIdx2[lutValue];
293 
294         return lutTreeIdx1[lutValue];
295     }
296 
297     private int Put(int pntIndex, int lutValue) {
298         int ti = GetTreeIndex(lutValue);
299 
300         if (ti < 0)
301             return -1;
302 
303         grbTree[ti].Insert(pntIndex);
304 
305         return ti;
306     }
307 
308     private void Delete(int pntIndex, int lutValue) {
309         int ti = GetTreeIndex(lutValue);
310 
311         if (ti < 0 || ti == currentTree)
312             return;
313 
314         grbTree[ti].Delete(pntIndex);
315     }
316 
317 
318 }

 

posted on 2017-09-10 12:35  萌虾  阅读(313)  评论(0编辑  收藏  举报

导航