1 module measure.label2;
2 import measure.types;
3 
4 import std.stdio;
5 import std.array;
6 import std.algorithm.iteration;
7 import std.algorithm;
8 import std.typecons;
9 
10 /* The algorithm is based on:
11  * https://stackoverflow.com/questions/14465297/connected-component-labelling
12  */
13 private
14 {
15     alias UnionFun4Conn = void function(int x, int y);
16     Mat2D!ubyte input;
17     size_t w, h;
18     uint[] component;
19 }
20 
21 private void doUnion(uint a, uint b)
22 {
23     while (component[a] != a)
24         a = component[a];
25     while (component[b] != b)
26         b = component[b];
27     component[b] = a;
28 }
29 
30 private void unionCoords(int x, int y, int x2, int y2)
31 {
32     if (y2 < h && x2 < w && input[x, y] && input[x2, y2])
33         doUnion(cast(uint)(x*h + y), cast(uint)(x2*h + y2));
34 }
35 
36 private void conn8Fun(int x, int y)
37 {
38     unionCoords(x, y, x+1, y);
39     unionCoords(x, y, x, y+1);
40     unionCoords(x, y, x+1, y+1);
41 }
42 
43 private void conn4Fun(int x, int y)
44 {
45     unionCoords(x, y, x+1, y);
46     unionCoords(x, y, x, y+1);
47 }
48 
49 XYList[] bwlabel2(Mat2D!ubyte img, bool conn8 = true)
50 {
51     // gives coordinates of connected components
52     XYList[] coords;
53     
54     input = img;
55     
56     h = img.width;
57     w = img.height;
58     
59     component = new uint[w*h];
60     
61     UnionFun4Conn uFun;
62     if(conn8)
63         uFun = &conn8Fun;
64     else
65         uFun = &conn4Fun;
66     
67     for (int i = 0; i < w*h; i++)
68         component[i] = i;
69     for (int x = 0; x < w; x++)
70     for (int y = 0; y < h; y++)
71         uFun(x, y);
72     
73     XYList[uint] pmap;
74     
75     for (int x = 0; x < w; x++)
76     {
77         for (int y = 0; y < h; y++)
78         {
79             if (input[x, y] == 0)
80             {
81                 continue;
82             }
83             uint c = cast(uint)(x*h + y);
84             while (component[c] != c) c = component[c];
85             
86             if(c !in pmap)
87             {
88                 XYList tmp;
89                 tmp.xs ~= y;
90                 tmp.ys ~= x;
91                 pmap[c] = tmp;
92             }else{
93                 pmap[c].xs ~= y;
94                 pmap[c].ys ~= x;
95             }
96 
97             
98         }
99     }
100     
101     foreach(key; pmap.keys)
102     {
103         coords ~= pmap[key];
104     }
105     
106     return coords;
107 }