1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.openimaj.image.connectedcomponent.proc;
31
32 import java.util.List;
33
34 import org.openimaj.feature.DoubleFV;
35 import org.openimaj.feature.FeatureVectorProvider;
36 import org.openimaj.image.pixel.ConnectedComponent;
37 import org.openimaj.image.pixel.ConnectedComponent.ConnectMode;
38 import org.openimaj.image.pixel.Pixel;
39 import org.openimaj.image.processor.connectedcomponent.ConnectedComponentProcessor;
40 import org.openimaj.math.util.Interpolation;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class BoundaryDistanceDescriptor implements ConnectedComponentProcessor, FeatureVectorProvider<DoubleFV> {
57
58
59
60 public final static int DESCRIPTOR_LENGTH = 360;
61
62
63
64
65 public double [] descriptor = new double[DESCRIPTOR_LENGTH];
66 protected boolean normaliseScale;
67 protected boolean normaliseAngle;
68
69
70
71
72
73 public BoundaryDistanceDescriptor() {
74 this(true, true);
75 }
76
77
78
79
80
81
82
83 public BoundaryDistanceDescriptor(boolean normaliseDistance, boolean normaliseAngle) {
84 this.normaliseScale = normaliseDistance;
85 this.normaliseAngle = normaliseAngle;
86 }
87
88 @Override
89 public void process(ConnectedComponent cc) {
90 cc = new ConnectedComponent(cc.calculateConvexHull());
91
92 List<Pixel> bound = cc.getInnerBoundary(ConnectMode.CONNECT_8);
93 double [] centroid = cc.calculateCentroid();
94 double direction = cc.calculateDirection();
95
96 float[] distances = new float[bound.size()];
97 float[] angle = new float[bound.size()];
98 int count = 0;
99
100 for (int i=0; i<bound.size(); i++) {
101 Pixel p = bound.get(i);
102 double o = p.y - centroid[1];
103 double a = p.x - centroid[0];
104
105 float dist = (float) Math.sqrt((a*a) + (o*o));
106 distances[i] = dist;
107
108 if (normaliseAngle) {
109 angle[i] = (float) (direction - Math.atan2(o, a));
110 } else {
111 angle[i] = (float) (Math.atan2(o, a));
112 }
113
114 angle[i] = (float) ((angle[i] %= 2.0*Math.PI) >= 0 ? angle[i] : (angle[i] + 2.0*Math.PI));
115 angle[i] = (float) (360.0 * angle[i] / (2.0*Math.PI));
116 }
117
118 for (int i=0; i<DESCRIPTOR_LENGTH; i++) {
119 int index1 = -1;
120 int index2 = -1;
121
122 for (int j=0; j<angle.length; j++) {
123 int n = ((j+1 == angle.length) ? 0 : j+1);
124
125 float aj = angle[j];
126 float an = angle[n];
127
128 if (an > 350 && aj < 10) if (i<10) an-=360; else aj+=360;
129 if (aj > 350 && an < 10) if (i<10) aj-=360; else an+=360;
130
131 if (aj==i) {
132 index1 = j;
133 index2 = j;
134 break;
135 } else if (aj<an) {
136 if (i <= an && i > aj) {
137 index1 = j;
138 index2 = n;
139 break;
140 }
141 } else {
142 if (i <= aj && i > an) {
143 index1 = j;
144 index2 = n;
145 break;
146 }
147 }
148 }
149
150
151 descriptor[i] = Interpolation.lerp(i, angle[index1], distances[index1], angle[index2], distances[index2]);
152 count += descriptor[i];
153 }
154
155 if (normaliseScale) {
156 for (int i=0; i<DESCRIPTOR_LENGTH; i++)
157 descriptor[i] /= count;
158 }
159 }
160
161
162
163
164
165 public double[] getFeatureVectorArray() {
166 return descriptor;
167 }
168
169 @Override
170 public DoubleFV getFeatureVector() {
171 return new DoubleFV(getFeatureVectorArray());
172 }
173 }