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.workinprogress;
31
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.Comparator;
35 import java.util.List;
36
37 import org.openimaj.image.DisplayUtilities;
38 import org.openimaj.image.FImage;
39 import org.openimaj.image.MBFImage;
40 import org.openimaj.image.analysis.watershed.feature.MomentFeature;
41 import org.openimaj.image.colour.ColourSpace;
42 import org.openimaj.image.colour.RGBColour;
43 import org.openimaj.image.connectedcomponent.ConnectedComponentLabeler;
44 import org.openimaj.image.feature.local.interest.EllipticInterestPointData;
45 import org.openimaj.image.feature.local.interest.InterestPointDetector;
46 import org.openimaj.image.pixel.ConnectedComponent;
47 import org.openimaj.image.pixel.ConnectedComponent.ConnectMode;
48 import org.openimaj.image.pixel.IntValuePixel;
49 import org.openimaj.image.pixel.Pixel;
50 import org.openimaj.image.renderer.MBFImageRenderer;
51 import org.openimaj.math.geometry.shape.Ellipse;
52 import org.openimaj.math.geometry.shape.Rectangle;
53
54 public class LOCKY implements InterestPointDetector<EllipticInterestPointData> {
55 private static float DEFAULT_THRESHOLD_PERCENTAGE = 0.24f;
56 protected BrightnessClusteringTransform bct = new BrightnessClusteringTransform();
57 protected ConnectedComponentLabeler ccl = new ConnectedComponentLabeler(ConnectMode.CONNECT_4);
58 protected int shiftx = 0;
59 protected int shifty = 0;
60 private float threshold;
61 private ArrayList<EllipticInterestPointData> regions;
62
63 public LOCKY() {
64 this(DEFAULT_THRESHOLD_PERCENTAGE);
65 }
66
67 public LOCKY(float threshold) {
68 this.threshold = threshold;
69 }
70
71 @Override
72 public void findInterestPoints(FImage image) {
73 final FImage bctImage = image.process(bct);
74 bctImage.normalise();
75 final FImage thresholdImage = bctImage.clone().threshold(this.threshold);
76 final List<ConnectedComponent> components = ccl.findComponents(thresholdImage);
77
78 this.regions = new ArrayList<EllipticInterestPointData>(components.size());
79 for (final ConnectedComponent cc : components) {
80 final EllipticInterestPointData ipd = new EllipticInterestPointData();
81 ipd.score = findMaxValue(cc, bctImage);
82
83
84 final MomentFeature mf = new MomentFeature();
85 final IntValuePixel tmp = new IntValuePixel(0, 0);
86 for (final Pixel p : cc) {
87 tmp.x = p.x;
88 tmp.y = p.y;
89 mf.addSample(tmp);
90 }
91 final Ellipse e = mf.getEllipse(2);
92
93 ipd.transform = e.transformMatrix().getMatrix(0, 1, 0, 1);
94 ipd.scale = 10;
95
96 final Pixel centroid = cc.calculateCentroidPixel();
97 ipd.x = centroid.x;
98 ipd.y = centroid.y;
99
100 regions.add(ipd);
101 }
102
103 DisplayUtilities.display(bctImage);
104 DisplayUtilities.display(thresholdImage);
105
106 Collections.sort(regions, new Comparator<EllipticInterestPointData>() {
107 @Override
108 public int compare(EllipticInterestPointData o1, EllipticInterestPointData o2) {
109 return -Float.compare(o1.score, o2.score);
110 }
111 });
112 }
113
114 private float findMaxValue(ConnectedComponent cc, FImage bctImage) {
115 float max = -1;
116 for (final Pixel p : cc) {
117 max = Math.max(max, bctImage.pixels[p.y][p.x]);
118 }
119 return max;
120 }
121
122 @Override
123 public void findInterestPoints(FImage image, Rectangle window) {
124 findInterestPoints(image.extractROI(window));
125 shiftx = (int) window.x;
126 shifty = (int) window.y;
127 }
128
129 @Override
130 public List<EllipticInterestPointData> getInterestPoints(int npoints) {
131 return regions.subList(0, Math.min(npoints, regions.size()));
132 }
133
134 @Override
135 public List<EllipticInterestPointData> getInterestPoints(float threshold) {
136 for (int i = regions.size(); i > 0; i++) {
137 if (regions.get(i - 1).score < threshold)
138 return regions.subList(0, i);
139 }
140
141 return new ArrayList<EllipticInterestPointData>(0);
142 }
143
144 @Override
145 public List<EllipticInterestPointData> getInterestPoints() {
146 return regions;
147 }
148
149 public static void main(String[] args) {
150 final MBFImage image = new MBFImage(400, 400, ColourSpace.RGB);
151 final MBFImageRenderer renderer = image.createRenderer();
152
153 image.fill(RGBColour.BLACK);
154 final List<Ellipse> ellipses = new ArrayList<Ellipse>();
155 ellipses.add(new Ellipse(200, 100, 10, 8, Math.PI / 4));
156 ellipses.add(new Ellipse(200, 300, 5, 3, -Math.PI / 4));
157 ellipses.add(new Ellipse(100, 300, 3, 5, -Math.PI / 3));
158
159 for (final Ellipse ellipse : ellipses) {
160 renderer.drawShapeFilled(ellipse, RGBColour.WHITE);
161 }
162
163 final LOCKY locky = new LOCKY();
164 locky.findInterestPoints(image.flatten());
165 final List<EllipticInterestPointData> pts = locky.getInterestPoints();
166 for (final EllipticInterestPointData pt : pts) {
167 image.drawShape(pt.getEllipse(), RGBColour.RED);
168 }
169
170 DisplayUtilities.display(image);
171 }
172 }