1 /**
2 * Copyright (c) 2011, The University of Southampton and the individual contributors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * * Neither the name of the University of Southampton nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 package org.openimaj.image.processing.edges;
31
32 import org.openimaj.image.FImage;
33 import org.openimaj.image.combiner.ImageCombiner;
34
35 /**
36 * Non-maximum suppression using X and Y gradient images.
37 *
38 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
39 */
40 public class NonMaximumSuppressionTangent implements ImageCombiner<FImage, FImage, FImage> {
41
42 /**
43 * Perform non-maximum suppression.
44 *
45 * @param dxImage
46 * x-gradients
47 * @param dyImage
48 * y-gradients
49 * @return non-maximum suppressed magnitude image.
50 */
51 public static FImage computeSuppressed(FImage dxImage, FImage dyImage) {
52 return computeSuppressed(dxImage, dyImage, null);
53 }
54
55 /**
56 * Perform non-maximum suppression.
57 *
58 * @param dxImage
59 * x-gradients
60 * @param dyImage
61 * y-gradients
62 * @param magsOut
63 * an image with the same dimensions as dxImage and dyImage for
64 * holding the magnitudes before non-maximum suppression. May be
65 * <code>null</code>.
66 * @return non-maximum suppressed magnitude image.
67 */
68 public static FImage computeSuppressed(FImage dxImage, FImage dyImage, FImage magsOut) {
69 final float[][] diffx = dxImage.pixels;
70 final float[][] diffy = dyImage.pixels;
71 final int width = dxImage.width;
72 final int height = dxImage.height;
73
74 final float[][] mag = magsOut == null ? new float[height][width] : magsOut.pixels;
75
76 for (int y = 0; y < height; y++)
77 for (int x = 0; x < width; x++)
78 mag[y][x] = (float) Math.sqrt(diffx[y][x] * diffx[y][x] + diffy[y][x] * diffy[y][x]);
79
80 final FImage outimg = new FImage(width, height);
81 final float[][] output = outimg.pixels;
82
83 for (int y = 1; y < height - 1; y++) {
84 for (int x = 1; x < width - 1; x++) {
85 int dx, dy;
86
87 if (diffx[y][x] > 0)
88 dx = 1;
89 else
90 dx = -1;
91
92 if (diffy[y][x] > 0)
93 dy = -1;
94 else
95 dy = 1;
96
97 float a1, a2, b1, b2, A, B, point, val;
98 if (Math.abs(diffx[y][x]) > Math.abs(diffy[y][x]))
99 {
100 a1 = mag[y][x + dx];
101 a2 = mag[y - dy][x + dx];
102 b1 = mag[y][x - dx];
103 b2 = mag[y + dy][x - dx];
104 A = (Math.abs(diffx[y][x]) - Math.abs(diffy[y][x])) * a1 + Math.abs(diffy[y][x]) * a2;
105 B = (Math.abs(diffx[y][x]) - Math.abs(diffy[y][x])) * b1 + Math.abs(diffy[y][x]) * b2;
106 point = mag[y][x] * Math.abs(diffx[y][x]);
107 if (point >= A && point > B) {
108 val = Math.abs(diffx[y][x]);
109 output[y][x] = val;
110 }
111 else {
112 val = 0;
113 output[y][x] = val;
114 }
115 }
116 else
117 {
118 a1 = mag[y - dy][x];
119 a2 = mag[y - dy][x + dx];
120 b1 = mag[y + dy][x];
121 b2 = mag[y + dy][x - dx];
122 A = (Math.abs(diffy[y][x]) - Math.abs(diffx[y][x])) * a1 + Math.abs(diffx[y][x]) * a2;
123 B = (Math.abs(diffy[y][x]) - Math.abs(diffx[y][x])) * b1 + Math.abs(diffx[y][x]) * b2;
124 point = mag[y][x] * Math.abs(diffy[y][x]);
125 if (point >= A && point > B) {
126 val = Math.abs(diffy[y][x]);
127 output[y][x] = val;
128 }
129 else {
130 val = 0;
131 output[y][x] = val;
132 }
133 }
134 }
135 }
136
137 return outimg;
138 }
139
140 /**
141 * Perform non-maximum suppression.
142 *
143 * @param dxImage
144 * x-gradients
145 * @param dyImage
146 * y-gradients
147 * @return non-maximum suppressed magnitude image.
148 *
149 * @see org.openimaj.image.combiner.ImageCombiner#combine(org.openimaj.image.Image,
150 * org.openimaj.image.Image)
151 */
152 @Override
153 public FImage combine(FImage dxImage, FImage dyImage) {
154 return computeSuppressed(dxImage, dyImage);
155 }
156 }