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.processing.morphology;
31
32 import java.util.HashSet;
33 import java.util.Set;
34
35 import org.openimaj.image.FImage;
36 import org.openimaj.image.pixel.ConnectedComponent;
37 import org.openimaj.image.pixel.Pixel;
38 import org.openimaj.image.processor.KernelProcessor;
39 import org.openimaj.image.processor.connectedcomponent.ConnectedComponentProcessor;
40 import org.openimaj.math.geometry.shape.Rectangle;
41
42
43
44
45
46
47
48 public class HitAndMiss implements ConnectedComponentProcessor, KernelProcessor<Float, FImage> {
49
50
51
52 public final static HitAndMiss CONVEX_CORNERS;
53 static {
54 CONVEX_CORNERS = new HitAndMiss(
55 new StructuringElement(
56 new Pixel[] {new Pixel(0,-1), new Pixel(0,0), new Pixel(1,0)},
57 new Pixel[] {new Pixel(-1,0), new Pixel(-1,1), new Pixel(0,1)}),
58 new StructuringElement(
59 new Pixel[] {new Pixel(0,-1), new Pixel(0,0), new Pixel(-1,0)},
60 new Pixel[] {new Pixel(1,0), new Pixel(1,1), new Pixel(0,1)}),
61 new StructuringElement(
62 new Pixel[] {new Pixel(-1,0), new Pixel(0,0), new Pixel(0,1)},
63 new Pixel[] {new Pixel(0,-1), new Pixel(1,-1), new Pixel(1,0)}),
64 new StructuringElement(
65 new Pixel[] {new Pixel(0,1), new Pixel(0,0), new Pixel(1,0)},
66 new Pixel[] {new Pixel(-1,-1), new Pixel(0,-1), new Pixel(-1,0)})
67 );
68 }
69
70 protected Set<Pixel> outputPixels = new HashSet<Pixel>();
71 protected StructuringElement [] elements;
72 protected int cx;
73 protected int cy;
74 protected int sw=0;
75 protected int sh=0;
76
77
78
79
80
81
82 public HitAndMiss(StructuringElement... ses) {
83 this.elements = ses;
84
85 for (StructuringElement se : ses) {
86 int [] sz = se.size();
87
88 if (sw < sz[0]) sw = sz[0];
89 if (sh < sz[1]) sh = sz[1];
90 }
91 cx = sw/2;
92 cy = sw/2;
93 }
94
95 @Override
96 public void process(ConnectedComponent cc) {
97
98 outputPixels.clear();
99
100 for (StructuringElement element : elements) {
101 Set<Pixel> pixels = cc.getPixels();
102 int [] se_size = element.size();
103 Rectangle cc_bb = cc.calculateRegularBoundingBox();
104 for (int j=(int) (cc_bb.y-se_size[1]); j<=cc_bb.y+se_size[1]+cc_bb.height; j++) {
105 for (int i=(int) (cc_bb.x-se_size[0]); i<=cc_bb.x+se_size[0]+cc_bb.width; i++) {
106 Pixel p = new Pixel(i, j);
107
108 if (element.matches(p, pixels)) {
109 outputPixels.add(p);
110 }
111 }
112 }
113 }
114 }
115
116
117
118
119
120 public Set<Pixel> getPixels() {
121 return outputPixels;
122 }
123
124 @Override
125 public int getKernelHeight() {
126 return sh;
127 }
128
129 @Override
130 public int getKernelWidth() {
131 return sw;
132 }
133
134 @Override
135 public Float processKernel(FImage patch) {
136
137 for (StructuringElement element : elements) {
138 int count = 0;
139 for (Pixel p : element.positive) {
140 int px = cx - p.x;
141 int py = cy - p.y;
142 if (px>=0 && py>=0 && px<sw && py<sh && patch.pixels[py][px] == 1)
143 count++;
144 }
145
146 for (Pixel p : element.negative) {
147 int px = cx - p.x;
148 int py = cy - p.y;
149 if (px>=0 && py>=0 && px<sw && py<sh && patch.pixels[py][px] == 0)
150 count++;
151 }
152
153 if (count == element.positive.size()+element.negative.size()) return 1f;
154 }
155
156 return 0f;
157 }
158 }