6import java.awt.image.*;
38 final BufferedImage image_;
50 float[] importance_ =
null;
54 int[] index_map_ =
null;
65 width_ = image.getWidth();
66 height_ = image.getHeight();
71 index_map_ =
new int[width_ * height_];
72 for (
int i=0; i < width_*height_; ++i) {
80 void apply(
int ncuts) {
81 seams_.
reserve((height_+1) * ncuts_);
83 for (
int n=0; n < ncuts; ++n) {
97 int current_width = width_ - ncuts_;
101 int size = current_width * height_;
102 int[] parent =
new int[size];
103 for (
int k=0; k<size; ++k)
105 float[] sums =
new float[size];
106 for (
int i=0; i<size; ++i)
107 sums[i] = importance_[i];
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;
118 i > 0 ? sums[up-1] : Float.POSITIVE_INFINITY,
120 i < current_width-1 ? sums[up+1] : Float.POSITIVE_INFINITY
122 int imin = values[0] < values[1] ? 0 : 1;
123 imin = values[imin] <= values[2] ? imin : 2;
125 int direction = imin - 1;
126 parent[index] = direction;
127 sums[index] += sums[up + direction];
135 int imin = sums.length - current_width;
136 for (
int k = imin + 1; k<sums.length; ++k) {
137 if (sums[imin] > sums[k])
146 while (parent[index] != -2) {
148 index_map_[index] = -1;
149 int from = parent[index];
151 index -= current_width;
155 index_map_[index] = -1;
165 int current_width = width_ - ncuts_;
167 int next_width = current_width - 1;
169 float[] next_importance =
new float[next_width * height_];
170 int[] next_index_map =
new int[next_width * height_];
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];
181 importance_ = next_importance;
182 index_map_ = next_index_map;
189 void compute_importance() {
190 importance_ =
new float[width_ * height_];
192 float[] sobel_x = { -1.0f, 0.0f, 1.0f,
196 float[] sobel_y = { -1.0f, -2.0f, -1.0f,
200 Kernel dx =
new Kernel(3, 3, sobel_x);
201 Kernel dy =
new Kernel(3, 3, sobel_y);
203 BufferedImage image_dx =
new ConvolveOp(dx).filter(image_,
null);
204 BufferedImage image_dy =
new ConvolveOp(dy).filter(image_,
null);
206 float[] components = { 0.0f, 0.0f, 0.0f };
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);
214 importance_[index++] = Math.min(1.0f, value);
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);
230 void write_result(String path) {
231 int width_result = width_ - ncuts_;
233 BufferedImage result =
234 new BufferedImage(width_result, height_, BufferedImage.TYPE_INT_RGB);
237 for (
int k=0; k<index_map_.length; ++k) {
238 if (index_map_[k] >= 0) {
239 int si = index_map_[k] % width_;
240 int sj = index_map_[k] / width_;
241 int di = index % width_result;
242 int dj = index / width_result;
245 result.setRGB(di, dj, image_.getRGB(si, sj));
249 write_image(result, path);
254 void dump_seams(String path) {
255 BufferedImage result =
256 new BufferedImage(width_, height_, BufferedImage.TYPE_INT_RGB);
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));
264 Color color = Color.RED;
265 for (
int index : seams_) {
267 int i = index % width_;
268 int j = index / width_;
269 result.setRGB(i, j, color.getRGB());
274 int r = color.getRed();
275 int g = color.getGreen();
276 int b = color.getBlue();
278 if (g == 63 && b > 63)
280 if (g == 63 && b == 0)
282 if (r == 63 && g > 63)
284 if (r == 63 && g == 0)
289 color =
new Color(r, g, b);
293 write_image(result, path);
296 void dump_importance(String path) {
298 new BufferedImage(width_, height_, BufferedImage.TYPE_INT_RGB);
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);
307 write_image(dump, path);
312 void write_image(BufferedImage image, String path) {
314 File ofile =
new File(path);
315 String format =
"png";
317 if (path.toLowerCase().endsWith(
".jpg"))
319 else if (path.toLowerCase().endsWith(
".gif"))
322 ImageIO.write(image, format, ofile);
323 }
catch (IOException e) {
324 System.err.println(e);
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"
343 public static void main(String[] args) {
348 BufferedImage image = ImageIO.read(
new File(args[0]));
349 int n = Integer.parseInt(args[1]);
351 int nmax = image.getWidth() - 1;
352 n = Math.max(0, Math.min(nmax, n));
354 seam_carving.apply(n);
355 seam_carving.write_result(args[2]);
358 seam_carving.dump_seams(args[3]);
361 seam_carving.dump_importance(args[4]);
363 }
catch(IOException e) {
364 System.err.println(e);
Implementation of an array-based vector.
void push_back(T obj)
insert new entry obj at the end [O(1) for sufficient capacity]
void reserve(int n)
Ensure capacity for n entries.
Simple implementation of seam carving.
static void usage()
print help message and exit
static void main(String[] args)
AuD lecture: Data structures, algorithms, examples.