AuD
Lecture 'Algorithmen und Datenstrukturen' (code examples)
SeamCarvingDemo.java
Go to the documentation of this file.
1package aud.example.dp;
2
3import aud.Vector;
4import java.io.*;
5import java.awt.Color;
6import java.awt.image.*;
7import javax.imageio.*;
8
36public class SeamCarvingDemo {
38 final BufferedImage image_;
40 final int width_;
42 final int height_;
43
45 int ncuts_ = 0;
46
50 float[] importance_ = null;
51
54 int[] index_map_ = null;
55
59 Vector<Integer> seams_ = new Vector<Integer>();
60
63 SeamCarvingDemo(BufferedImage image) {
64 image_ = image;
65 width_ = image.getWidth();
66 height_ = image.getHeight();
67
68 compute_importance();
69
70 // index_map_ stores indices of "remaining" pixels
71 index_map_ = new int[width_ * height_];
72 for (int i=0; i < width_*height_; ++i) {
73 index_map_[i] = i;
74 }
75 }
76
80 void apply(int ncuts) {
81 seams_.reserve((height_+1) * ncuts_);
82
83 for (int n=0; n < ncuts; ++n) {
84 compute_seam();
85 remove_seam();
86 }
87 }
88
94 void compute_seam() {
95 // This simple version assume that remove_cuts() has been called!
96
97 int current_width = width_ - ncuts_;
98
99 // Note: Not "reusing" parent and importance arrays for multiple cuts is
100 // simple but inefficient.
101 int size = current_width * height_;
102 int[] parent = new int[size];
103 for (int k=0; k<size; ++k)
104 parent[k] = -2;
105 float[] sums = new float[size];
106 for (int i=0; i<size; ++i)
107 sums[i] = importance_[i];
108
109 //
110 // compute sums bottom up
111 //
112 for (int j=1; j < height_; ++j) {
113 for (int i=0; i < current_width; ++i) {
114 int index = j * current_width + i;
115 assert index_map_[index] >= 0 : "assume earlier are removed";
116 int up = index - current_width;
117 float[] values = {
118 i > 0 ? sums[up-1] : Float.POSITIVE_INFINITY,
119 sums[up],
120 i < current_width-1 ? sums[up+1] : Float.POSITIVE_INFINITY
121 };
122 int imin = values[0] < values[1] ? 0 : 1;
123 imin = values[imin] <= values[2] ? imin : 2;
124
125 int direction = imin - 1; // -1: left, 0: center, +1: right
126 parent[index] = direction;
127 sums[index] += sums[up + direction];
128 }
129 }
130
131 //
132 // find minimum ...
133 //
134
135 int imin = sums.length - current_width;
136 for (int k = imin + 1; k<sums.length; ++k) {
137 if (sums[imin] > sums[k])
138 imin = k;
139 }
140
141 //
142 // ... and backtrack
143 //
144
145 int index = imin;
146 while (parent[index] != -2) {
147 seams_.push_back(index_map_[index]);
148 index_map_[index] = -1;
149 int from = parent[index];
150
151 index -= current_width;
152 index += from;
153 }
154 seams_.push_back(index_map_[index]);
155 index_map_[index] = -1;
156 seams_.push_back(-1); // next seam
157 }
158
164 void remove_seam() {
165 int current_width = width_ - ncuts_;
166
167 int next_width = current_width - 1;
168
169 float[] next_importance = new float[next_width * height_];
170 int[] next_index_map = new int[next_width * height_];
171
172 int j = 0;
173 for (int i=0; i < index_map_.length; ++i) {
174 if (index_map_[i] >= 0) {
175 next_index_map[j] = index_map_[i];
176 next_importance[j] = importance_[i];
177 ++j;
178 }
179 }
180
181 importance_ = next_importance;
182 index_map_ = next_index_map;
183 ++ncuts_;
184 }
185
189 void compute_importance() {
190 importance_ = new float[width_ * height_];
191
192 float[] sobel_x = { -1.0f, 0.0f, 1.0f,
193 -2.0f, 0.0f, 2.0f,
194 -1.0f, 0.0f, 1.0f };
195
196 float[] sobel_y = { -1.0f, -2.0f, -1.0f,
197 0.0f, 0.0f, 0.0f,
198 1.0f, 2.0f, 1.0f };
199
200 Kernel dx = new Kernel(3, 3, sobel_x);
201 Kernel dy = new Kernel(3, 3, sobel_y);
202
203 BufferedImage image_dx = new ConvolveOp(dx).filter(image_, null);
204 BufferedImage image_dy = new ConvolveOp(dy).filter(image_, null);
205
206 float[] components = { 0.0f, 0.0f, 0.0f };
207 int index = 0;
208 for (int j=0; j < height_; ++j) {
209 for (int i=0; i < width_; ++i) {
210 float vx = gray(image_dx.getRGB(i, j), components);
211 float vy = gray(image_dy.getRGB(i, j), components);
212 float value = (float) Math.sqrt(vx*vx + vy*vy);
213
214 importance_[index++] = Math.min(1.0f, value);
215 }
216 }
217 }
218
222 static float gray(int irgb, float[] rgb) {
223 new Color(irgb).getColorComponents(rgb);
224 float value = 0.2126f*rgb[0] + 0.7152f*rgb[1] + 0.0722f*rgb[2];
225 return Math.min(1.0f, value);
226 }
227
230 void write_result(String path) {
231 int width_result = width_ - ncuts_;
232
233 BufferedImage result =
234 new BufferedImage(width_result, height_, BufferedImage.TYPE_INT_RGB);
235
236 int index = 0;
237 for (int k=0; k<index_map_.length; ++k) {
238 if (index_map_[k] >= 0) {
239 int si = index_map_[k] % width_; // source pixel
240 int sj = index_map_[k] / width_;
241 int di = index % width_result; // destination pixel
242 int dj = index / width_result;
243 ++index;
244
245 result.setRGB(di, dj, image_.getRGB(si, sj));
246 }
247 }
248
249 write_image(result, path);
250 }
251
254 void dump_seams(String path) {
255 BufferedImage result =
256 new BufferedImage(width_, height_, BufferedImage.TYPE_INT_RGB);
257
258 for (int j=0; j<height_; ++j) {
259 for (int i=0; i<width_; ++i) {
260 result.setRGB(i, j, image_.getRGB(i, j));
261 }
262 }
263
264 Color color = Color.RED;
265 for (int index : seams_) {
266 if (index >= 0) {
267 int i = index % width_;
268 int j = index / width_;
269 result.setRGB(i, j, color.getRGB());
270 }
271 else {
272 // color code seams in their order
273 // red -> darkred -> green -> darkgreen -> blue -> drakblue
274 int r = color.getRed();
275 int g = color.getGreen();
276 int b = color.getBlue();
277
278 if (g == 63 && b > 63)
279 b -= 1;
280 if (g == 63 && b == 0)
281 b = 255;
282 if (r == 63 && g > 63)
283 g -= 1;
284 if (r == 63 && g == 0)
285 g = 255;
286 if (r > 63)
287 r -= 1;
288
289 color = new Color(r, g, b);
290 }
291 }
292
293 write_image(result, path);
294 }
295
296 void dump_importance(String path) {
297 BufferedImage dump =
298 new BufferedImage(width_, height_, BufferedImage.TYPE_INT_RGB);
299 int index = 0;
300 for (int j=0; j < height_; ++j) {
301 for (int i=0; i < width_; ++i) {
302 float v = importance_[index++];
303 int rgb = new Color(v, v, v).getRGB();
304 dump.setRGB(i, j, rgb);
305 }
306 }
307 write_image(dump, path);
308 }
309
312 void write_image(BufferedImage image, String path) {
313 try {
314 File ofile = new File(path);
315 String format = "png"; // PNG is default
316
317 if (path.toLowerCase().endsWith(".jpg"))
318 format = "jpg";
319 else if (path.toLowerCase().endsWith(".gif"))
320 format = "gif";
321
322 ImageIO.write(image, format, ofile);
323 } catch (IOException e) {
324 System.err.println(e);
325 System.exit(-1);
326 }
327 }
328
330 protected static void usage() {
331 System.err.println
332 ("usage: java aud.example.dp.SeamCarvingDemo IMAGE N OUTPUT " +
333 "[DUMP-SEAMS] [DUMP-IMPORTANCE]]\n\n" +
334 "Read IMAGE and shrink horizontally by removing N vertical seams.\n" +
335 "If the filename DUMP-SEAMS is specified, write an image that " +
336 "shows the generated seams.\n" +
337 "If the filename DUMP-IMPORTANCE is specified, the generated " +
338 "importance map is saved to this file.\n"
339 );
340 System.exit(-1);
341 }
342
343 public static void main(String[] args) {
344 if (args.length < 3)
345 usage();
346
347 try {
348 BufferedImage image = ImageIO.read(new File(args[0]));
349 int n = Integer.parseInt(args[1]);
350
351 int nmax = image.getWidth() - 1;
352 n = Math.max(0, Math.min(nmax, n));
353 SeamCarvingDemo seam_carving = new SeamCarvingDemo(image);
354 seam_carving.apply(n);
355 seam_carving.write_result(args[2]);
356
357 if (args.length > 3)
358 seam_carving.dump_seams(args[3]);
359
360 if (args.length > 4)
361 seam_carving.dump_importance(args[4]);
362
363 } catch(IOException e) {
364 System.err.println(e);
365 System.exit(-1);
366 }
367 }
368}
Implementation of an array-based vector.
Definition: Vector.java:44
void push_back(T obj)
insert new entry obj at the end [O(1) for sufficient capacity]
Definition: Vector.java:155
void reserve(int n)
Ensure capacity for n entries.
Definition: Vector.java:120
Simple implementation of seam carving.
static void usage()
print help message and exit
static void main(String[] args)
AuD lecture: Data structures, algorithms, examples.
Definition: A234Tree.java:1