1 /*
2 * metapixel.c
3 *
4 * metapixel
5 *
6 * Copyright (C) 1997-2006 Mark Probst
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include <sys/time.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <math.h>
30 #include <errno.h>
31 #include <float.h>
32
33 #include "getopt.h"
34
35 #include "vector.h"
36 #include "zoom.h"
37 #include "readimage.h"
38 #include "writeimage.h"
39 #include "lispreader.h"
40
41 #include "metapixel.h"
42
43 #ifndef MIN
44 #define MIN(a,b) ((a)<(b)?(a):(b))
45 #endif
46 #ifndef MAX
47 #define MAX(a,b) ((a)>(b)?(a):(b))
48 #endif
49
50 static int index_order[IMAGE_SIZE * IMAGE_SIZE];
51
52 static metapixel_t *first_pixel = 0;
53 static int num_metapixels = 0;
54
55 static float sqrt_of_two, sqrt_of_image_size;
56
57 static float index_weights[NUM_INDEXES];
58 static index_t weight_ordered_index_to_index[NUM_INDEXES];
59 static index_t index_to_weight_ordered_index[NUM_INDEXES];
60
61 /* default settings */
62
63 static char *default_prepare_directory = 0;
64 static int default_prepare_width = DEFAULT_PREPARE_WIDTH, default_prepare_height = DEFAULT_PREPARE_HEIGHT;
65 static string_list_t *default_library_directories = 0;
66 static int default_small_width = DEFAULT_WIDTH, default_small_height = DEFAULT_HEIGHT;
67 static float default_weight_factors[NUM_CHANNELS] = { 1.0, 1.0, 1.0 };
68 static int default_metric = METRIC_SUBPIXEL;
69 static int default_search = SEARCH_LOCAL;
70 static int default_classic_min_distance = DEFAULT_CLASSIC_MIN_DISTANCE;
71 static int default_collage_min_distance = DEFAULT_COLLAGE_MIN_DISTANCE;
72 static int default_cheat_amount = 0;
73 static int default_forbid_reconstruction_radius = 0;
74
75 /* actual settings */
76
77 static int small_width, small_height;
78 static float weight_factors[NUM_CHANNELS];
79 static int forbid_reconstruction_radius;
80
81 static int benchmark_rendering = 0;
82
83 static string_list_t*
string_list_prepend_copy(string_list_t * lst,const char * str)84 string_list_prepend_copy (string_list_t *lst, const char *str)
85 {
86 string_list_t *new = (string_list_t*)malloc(sizeof(string_list_t));
87
88 new->str = strdup(str);
89 new->next = lst;
90
91 return new;
92 }
93
94 static char*
strip_path(char * name)95 strip_path (char *name)
96 {
97 char *p = strrchr(name, '/');
98
99 if (p == 0)
100 return name;
101 return p + 1;
102 }
103
104 static metapixel_t*
new_metapixel(void)105 new_metapixel (void)
106 {
107 metapixel_t *pixel = (metapixel_t*)malloc(sizeof(metapixel_t));
108
109 assert(pixel != 0);
110
111 memset(pixel, 0, sizeof(metapixel_t));
112
113 return pixel;
114 }
115
116 static unsigned char*
scale_image(unsigned char * image,int image_width,int image_height,int x,int y,int width,int height,int new_width,int new_height)117 scale_image (unsigned char *image, int image_width, int image_height, int x, int y,
118 int width, int height, int new_width, int new_height)
119 {
120 unsigned char *new_image = (unsigned char*)malloc(new_width * new_height * NUM_CHANNELS);
121 unsigned char *image_start = image + (x + y * image_width) * NUM_CHANNELS;
122
123 zoom_image(new_image, image_start, get_filter(FILTER_MITCHELL), NUM_CHANNELS,
124 new_width, new_height, new_width * NUM_CHANNELS,
125 width, height, image_width * NUM_CHANNELS);
126
127 return new_image;
128 }
129
130 void
alpha_compose(unsigned char * dst,int width,int height,unsigned char * src,int perc)131 alpha_compose (unsigned char *dst, int width, int height, unsigned char *src, int perc)
132 {
133 int i;
134
135 for (i = 0; i < width * height * NUM_CHANNELS; ++i)
136 dst[i] = dst[i] * (100 - perc) / 100 + src[i] * perc / 100;
137 }
138
139 void
generate_index_order(void)140 generate_index_order (void)
141 {
142 int index = 0,
143 begin = 0,
144 row = 0,
145 col = 0,
146 first_half = 1;
147
148 do
149 {
150 index_order[index++] = col + IMAGE_SIZE * row;
151
152 if (first_half)
153 {
154 if (row == 0)
155 {
156 if (begin == IMAGE_SIZE - 1)
157 {
158 first_half = 0;
159 col = begin = 1;
160 row = IMAGE_SIZE - 1;
161 }
162 else
163 {
164 ++begin;
165 row = begin;
166 col = 0;
167 }
168 }
169 else
170 {
171 ++col;
172 --row;
173 }
174 }
175 else
176 {
177 if (col == IMAGE_SIZE - 1)
178 {
179 ++begin;
180 col = begin;
181 row = IMAGE_SIZE - 1;
182 }
183 else
184 {
185 ++col;
186 --row;
187 }
188 }
189 } while (index < IMAGE_SIZE * IMAGE_SIZE);
190 }
191
192 static int
compute_index(int real_index,int channel,int sign)193 compute_index (int real_index, int channel, int sign)
194 {
195 return real_index + (channel + (sign > 0 ? 1 : 0) * NUM_CHANNELS) * IMAGE_SIZE * IMAGE_SIZE;
196 }
197
198 static void
uncompute_index(int index,int * real_index,int * channel,int * sign)199 uncompute_index (int index, int *real_index, int *channel, int *sign)
200 {
201 *real_index = index % (IMAGE_SIZE * IMAGE_SIZE);
202 *channel = (index / (IMAGE_SIZE * IMAGE_SIZE)) % NUM_CHANNELS;
203 *sign = (index / (NUM_CHANNELS * IMAGE_SIZE * IMAGE_SIZE)) ? 1 : -1;
204 }
205
206 void
cut_last_coefficients(float * image,int channel,int howmany)207 cut_last_coefficients (float *image, int channel, int howmany)
208 {
209 int i;
210
211 for (i = IMAGE_SIZE * IMAGE_SIZE - howmany; i < IMAGE_SIZE * IMAGE_SIZE; ++i)
212 image[index_order[i] * NUM_CHANNELS + channel] = 0.0;
213 }
214
215 void
transform_rgb_to_yiq(float * image,int num_pixels)216 transform_rgb_to_yiq (float *image, int num_pixels)
217 {
218 const static Matrix3D conversion_matrix =
219 {
220 { 0.299, 0.587, 0.114 },
221 { 0.596, -0.275, -0.321 },
222 { 0.212, -0.528, 0.311 }
223 };
224
225 int i;
226
227 for (i = 0; i < num_pixels; ++i)
228 {
229 Vector3D rgb_vec,
230 yiq_vec;
231
232 InitVector3D(&rgb_vec,
233 image[NUM_CHANNELS * i + 0],
234 image[NUM_CHANNELS * i + 1],
235 image[NUM_CHANNELS * i + 2]);
236 MultMatrixVector3D(&yiq_vec, &conversion_matrix, &rgb_vec);
237 image[NUM_CHANNELS * i + 0] = yiq_vec.x;
238 image[NUM_CHANNELS * i + 1] = yiq_vec.y / 1.192 + 127.5;
239 image[NUM_CHANNELS * i + 2] = yiq_vec.z / 1.051 + 128.106565176;
240 }
241 }
242
243 void
transform_yiq_to_rgb(float * image)244 transform_yiq_to_rgb (float *image)
245 {
246 const static Matrix3D conversion_matrix =
247 {
248 { 1.00308929854, 0.954849063112, 0.61785970812 },
249 { 0.996776058337, -0.270706233074, -0.644788332692 },
250 { 1.00849783766, -1.1104851847, 1.69956753125 }
251 };
252
253 int i;
254
255 for (i = 0; i < IMAGE_SIZE * IMAGE_SIZE; ++i)
256 {
257 Vector3D rgb_vec,
258 yiq_vec;
259
260 InitVector3D(&yiq_vec,
261 image[NUM_CHANNELS * i + 0],
262 image[NUM_CHANNELS * i + 1] - 127.5,
263 image[NUM_CHANNELS * i + 2] - 127.5);
264 MultMatrixVector3D(&rgb_vec, &conversion_matrix, &yiq_vec);
265 image[NUM_CHANNELS * i + 0] = rgb_vec.x;
266 image[NUM_CHANNELS * i + 1] = rgb_vec.y;
267 image[NUM_CHANNELS * i + 2] = rgb_vec.z;
268 }
269 }
270
271 void
transpose_image(float * old_image,float * new_image)272 transpose_image (float *old_image, float *new_image)
273 {
274 int i,
275 j,
276 channel;
277
278 for (i = 0; i < IMAGE_SIZE; ++i)
279 for (j = 0; j < IMAGE_SIZE; ++j)
280 for (channel = 0; channel < NUM_CHANNELS; ++channel)
281 new_image[channel + (i + j * IMAGE_SIZE) * NUM_CHANNELS] =
282 old_image[channel + (j + i * IMAGE_SIZE) * NUM_CHANNELS];
283 }
284
285 void
decompose_row(float * row)286 decompose_row (float *row)
287 {
288 int h = IMAGE_SIZE,
289 i;
290 float new_row[NUM_CHANNELS * IMAGE_SIZE];
291
292 for (i = 0; i < NUM_CHANNELS * IMAGE_SIZE; ++i)
293 row[i] = row[i] / sqrt_of_image_size;
294
295 while (h > 1)
296 {
297 h = h / 2;
298 for (i = 0; i < h; ++i)
299 {
300 int channel;
301
302 for (channel = 0; channel < NUM_CHANNELS; ++channel)
303 {
304 float val1 = row[channel + 2 * i * NUM_CHANNELS],
305 val2 = row[channel + (2 * i + 1) * NUM_CHANNELS];
306
307 new_row[channel + i * NUM_CHANNELS] = (val1 + val2) / sqrt_of_two;
308 new_row[channel + (h + i) * NUM_CHANNELS] = (val1 - val2) / sqrt_of_two;
309 }
310 }
311 memcpy(row, new_row, sizeof(float) * NUM_CHANNELS * h * 2);
312 }
313 }
314
315 void
decompose_column(float * column)316 decompose_column (float *column)
317 {
318 int h = IMAGE_SIZE,
319 i,
320 channel;
321 float new_column[ROW_LENGTH];
322
323 for (i = 0; i < IMAGE_SIZE; ++i)
324 for (channel = 0; channel < NUM_CHANNELS; ++channel)
325 column[channel + i * ROW_LENGTH] =
326 column[channel + i * ROW_LENGTH] / sqrt_of_image_size;
327
328 while (h > 1)
329 {
330 h = h / 2;
331 for (i = 0; i < h; ++i)
332 {
333 for (channel = 0; channel < NUM_CHANNELS; ++channel)
334 {
335 float val1 = column[channel + (2 * i) * ROW_LENGTH],
336 val2 = column[channel + (2 * i + 1) * ROW_LENGTH];
337
338 new_column[channel + i * NUM_CHANNELS] = (val1 + val2) / sqrt_of_two;
339 new_column[channel + (h + i) * NUM_CHANNELS] = (val1 - val2) / sqrt_of_two;
340 }
341 }
342
343 for (i = 0; i < h * 2; ++i)
344 for (channel = 0; channel < NUM_CHANNELS; ++channel)
345 column[channel + i * ROW_LENGTH] = new_column[channel + i * NUM_CHANNELS];
346 }
347 }
348
349 void
decompose_image(float * image)350 decompose_image (float *image)
351 {
352 int row;
353
354 for (row = 0; row < IMAGE_SIZE; ++row)
355 decompose_row(image + NUM_CHANNELS * IMAGE_SIZE * row);
356 for (row = 0; row < IMAGE_SIZE; ++row)
357 decompose_column(image + NUM_CHANNELS * row);
358 }
359
360 void
compose_row(float * row)361 compose_row (float *row)
362 {
363 int h = 1,
364 i;
365 float new_row[NUM_CHANNELS * IMAGE_SIZE];
366
367 memcpy(new_row, row, sizeof(float) * NUM_CHANNELS * IMAGE_SIZE);
368 while (h < IMAGE_SIZE)
369 {
370 for (i = 0; i < h; ++i)
371 {
372 int channel;
373
374 for (channel = 0; channel < NUM_CHANNELS; ++channel)
375 {
376 float val1 = row[channel + i * NUM_CHANNELS],
377 val2 = row[channel + (h + i) * NUM_CHANNELS];
378
379 new_row[channel + 2 * i * NUM_CHANNELS] = (val1 + val2) / sqrt_of_two;
380 new_row[channel + (2 * i + 1) * NUM_CHANNELS] = (val1 - val2) / sqrt_of_two;
381 }
382 }
383 memcpy(row, new_row, sizeof(float) * NUM_CHANNELS * IMAGE_SIZE);
384 h = h * 2;
385 }
386
387 for (i = 0; i < NUM_CHANNELS * IMAGE_SIZE; ++i)
388 row[i] = row[i] * sqrt_of_image_size;
389 }
390
391 void
compose_image(float * image)392 compose_image (float *image)
393 {
394 int row;
395 float *transposed_image = (float*)malloc(sizeof(float) * 3 * IMAGE_SIZE * IMAGE_SIZE);
396
397 transpose_image(image, transposed_image);
398 for (row = 0; row < IMAGE_SIZE; ++row)
399 compose_row(transposed_image + NUM_CHANNELS * IMAGE_SIZE * row);
400 transpose_image(transposed_image, image);
401 for (row = 0; row < IMAGE_SIZE; ++row)
402 compose_row(image + NUM_CHANNELS * IMAGE_SIZE * row);
403
404 free(transposed_image);
405 }
406
407 int
compare_coeffs_with_index(const void * p1,const void * p2)408 compare_coeffs_with_index (const void *p1, const void *p2)
409 {
410 const coefficient_with_index_t *coeff1 = (const coefficient_with_index_t*)p1;
411 const coefficient_with_index_t *coeff2 = (const coefficient_with_index_t*)p2;
412
413 if (fabs(coeff1->coeff) < fabs(coeff2->coeff))
414 return 1;
415 else if (fabs(coeff1->coeff) == fabs(coeff2->coeff))
416 return 0;
417 return -1;
418 }
419
420 void
find_highest_coefficients(float * image,coefficient_with_index_t highest_coeffs[NUM_COEFFS])421 find_highest_coefficients (float *image, coefficient_with_index_t highest_coeffs[NUM_COEFFS])
422 {
423 int index, channel;
424
425 for (channel = 0; channel < NUM_CHANNELS; ++channel)
426 {
427 for (index = 1; index < SIGNIFICANT_COEFFS + 1; ++index)
428 {
429 float coeff = image[channel + NUM_CHANNELS * index];
430 int sign = coeff > 0.0 ? 1 : -1;
431
432 highest_coeffs[index - 1 + channel * SIGNIFICANT_COEFFS].index = compute_index(index, channel, sign);
433 highest_coeffs[index - 1 + channel * SIGNIFICANT_COEFFS].coeff = coeff;
434 }
435
436 qsort(highest_coeffs + channel * SIGNIFICANT_COEFFS, SIGNIFICANT_COEFFS,
437 sizeof(coefficient_with_index_t), compare_coeffs_with_index);
438 }
439
440 for (index = SIGNIFICANT_COEFFS + 1; index < IMAGE_SIZE * IMAGE_SIZE; ++index)
441 {
442 for (channel = 0; channel < NUM_CHANNELS; ++channel)
443 {
444 float coeff = image[channel + NUM_CHANNELS * index];
445
446 if (fabs(coeff) > fabs(highest_coeffs[(channel + 1) * SIGNIFICANT_COEFFS - 1].coeff))
447 {
448 int significance;
449 int sign = coeff > 0.0 ? 1 : -1;
450
451 for (significance = (channel + 1) * SIGNIFICANT_COEFFS - 2;
452 significance >= channel * SIGNIFICANT_COEFFS;
453 --significance)
454 if (fabs(coeff) <= fabs(highest_coeffs[significance].coeff))
455 break;
456 ++significance;
457 memmove(highest_coeffs + significance + 1,
458 highest_coeffs + significance,
459 sizeof(coefficient_with_index_t) * ((channel + 1) * SIGNIFICANT_COEFFS - 1 - significance));
460 highest_coeffs[significance].index = compute_index(index, channel, sign);
461 highest_coeffs[significance].coeff = coeff;
462 }
463 }
464 }
465 }
466
467 static float
weight_function(int index)468 weight_function (int index)
469 {
470 static float weight_table[NUM_CHANNELS][6] =
471 {
472 { 5.00, 0.83, 1.01, 0.52, 0.47, 0.30 },
473 { 19.21, 1.26, 0.44, 0.53, 0.28, 0.14 },
474 { 34, 0.36, 0.45, 0.14, 0.18, 0.27 }
475 };
476
477 int real_index, channel, sign;
478 int i, j, bin;
479
480 uncompute_index(index, &real_index, &channel, &sign);
481
482 i = real_index % IMAGE_SIZE;
483 j = real_index / IMAGE_SIZE;
484 bin = MIN(MAX(i, j), 5);
485
486 return weight_table[channel][bin] * weight_factors[channel];
487 }
488
489 static int
compare_indexes_by_weight_descending(const void * p1,const void * p2)490 compare_indexes_by_weight_descending (const void *p1, const void *p2)
491 {
492 const index_t *i1 = (const index_t*)p1, *i2 = (const index_t*)p2;
493
494 if (index_weights[*i1] < index_weights[*i2])
495 return 1;
496 else if (index_weights[*i1] == index_weights[*i2])
497 return 0;
498 return -1;
499 }
500
501 static void
compute_index_weights(void)502 compute_index_weights (void)
503 {
504 int i;
505
506 for (i = 0; i < NUM_INDEXES; ++i)
507 index_weights[i] = weight_function(i);
508
509 for (i = 0; i < NUM_INDEXES; ++i)
510 weight_ordered_index_to_index[i] = i;
511 qsort(weight_ordered_index_to_index, NUM_INDEXES, sizeof(index_t), compare_indexes_by_weight_descending);
512 for (i = 0; i < NUM_INDEXES; ++i)
513 index_to_weight_ordered_index[weight_ordered_index_to_index[i]] = i;
514 }
515
516 static float
wavelet_compare(coeffs_t * coeffs,metapixel_t * pixel,float best_score)517 wavelet_compare (coeffs_t *coeffs, metapixel_t *pixel, float best_score)
518 {
519 search_coefficients_t *query = &coeffs->wavelet.coeffs;
520 float *query_means = coeffs->wavelet.means;
521 float *sums = coeffs->wavelet.sums;
522 search_coefficients_t *target = &pixel->coeffs;
523 float *target_means = pixel->means;
524 float score = 0.0;
525 int i;
526 int j;
527 int channel;
528
529 for (channel = 0; channel < NUM_CHANNELS; ++channel)
530 score += index_weights[compute_index(0, channel, 0)]
531 * fabs(query_means[channel] - target_means[channel]) * 0.05;
532
533 j = 0;
534 for (i = 0; i < NUM_COEFFS; ++i)
535 {
536 if (score - sums[i] > best_score)
537 return FLT_MAX;
538
539 while (target->coeffs[j] < query->coeffs[i] && j < NUM_COEFFS)
540 ++j;
541
542 if (j >= NUM_COEFFS)
543 break;
544
545 if (target->coeffs[j] > query->coeffs[i])
546 continue;
547
548 score -= index_weights[weight_ordered_index_to_index[target->coeffs[j]]];
549 }
550
551 return score;
552 }
553
554 static float
subpixel_compare(coeffs_t * coeffs,metapixel_t * pixel,float best_score)555 subpixel_compare (coeffs_t *coeffs, metapixel_t *pixel, float best_score)
556 {
557 int channel;
558 float score = 0.0;
559
560 for (channel = 0; channel < NUM_CHANNELS; ++channel)
561 {
562 int i;
563
564 for (i = 0; i < NUM_SUBPIXELS; ++i)
565 {
566 float dist = (int)coeffs->subpixel.subpixels[channel * NUM_SUBPIXELS + i]
567 - (int)pixel->subpixels[channel * NUM_SUBPIXELS + i];
568
569 score += dist * dist * weight_factors[channel];
570
571 if (score >= best_score)
572 return FLT_MAX;
573 }
574 }
575
576 return score;
577 }
578
579 void
add_metapixel(metapixel_t * pixel)580 add_metapixel (metapixel_t *pixel)
581 {
582 pixel->next = first_pixel;
583 first_pixel = pixel;
584 ++num_metapixels;
585 }
586
587 static int
compare_indexes(const void * p1,const void * p2)588 compare_indexes (const void *p1, const void *p2)
589 {
590 index_t *i1 = (index_t*)p1;
591 index_t *i2 = (index_t*)p2;
592
593 return *i1 - *i2;
594 }
595
596 void
generate_search_coeffs(search_coefficients_t * search_coeffs,float sums[NUM_COEFFS],coefficient_with_index_t raw_coeffs[NUM_COEFFS])597 generate_search_coeffs (search_coefficients_t *search_coeffs, float sums[NUM_COEFFS],
598 coefficient_with_index_t raw_coeffs[NUM_COEFFS])
599 {
600 int i;
601 float sum;
602
603 for (i = 0; i < NUM_COEFFS; ++i)
604 search_coeffs->coeffs[i] = index_to_weight_ordered_index[raw_coeffs[i].index];
605
606 qsort(search_coeffs->coeffs, NUM_COEFFS, sizeof(index_t), compare_indexes);
607
608 sum = 0.0;
609 for (i = NUM_COEFFS - 1; i >= 0; --i)
610 {
611 sum += index_weights[weight_ordered_index_to_index[search_coeffs->coeffs[i]]];
612 sums[i] = sum;
613 }
614 }
615
616 void
generate_search_coeffs_for_subimage(coeffs_t * coeffs,unsigned char * image_data,int image_width,int image_height,int x,int y,int width,int height,int metric)617 generate_search_coeffs_for_subimage (coeffs_t *coeffs, unsigned char *image_data, int image_width, int image_height,
618 int x, int y, int width, int height, int metric)
619 {
620 static float *float_image = 0;
621
622 if (metric == METRIC_WAVELET)
623 {
624 coefficient_with_index_t raw_coeffs[NUM_COEFFS];
625 int i;
626
627 if (float_image == 0)
628 float_image = (float*)malloc(sizeof(float) * IMAGE_SIZE * IMAGE_SIZE * NUM_CHANNELS);
629
630 if (width != IMAGE_SIZE || height != IMAGE_SIZE)
631 {
632 unsigned char *scaled_data;
633
634 scaled_data = scale_image(image_data, image_width, image_height, x, y, width, height, IMAGE_SIZE, IMAGE_SIZE);
635 assert(scaled_data != 0);
636
637 for (i = 0; i < IMAGE_SIZE * IMAGE_SIZE * NUM_CHANNELS; ++i)
638 float_image[i] = scaled_data[i];
639
640 free(scaled_data);
641 }
642 else
643 {
644 int j, channel;
645
646 for (j = 0; j < IMAGE_SIZE; ++j)
647 for (i = 0; i < IMAGE_SIZE; ++i)
648 for (channel = 0; channel < NUM_CHANNELS; ++channel)
649 float_image[(j * IMAGE_SIZE + i) * NUM_CHANNELS + channel] =
650 image_data[((y + j) * image_width + (x + i)) * NUM_CHANNELS + channel];
651 }
652
653 transform_rgb_to_yiq(float_image, IMAGE_SIZE * IMAGE_SIZE);
654 decompose_image(float_image);
655 find_highest_coefficients(float_image, raw_coeffs);
656
657 generate_search_coeffs(&coeffs->wavelet.coeffs, coeffs->wavelet.sums, raw_coeffs);
658
659 for (i = 0; i < NUM_CHANNELS; ++i)
660 coeffs->wavelet.means[i] = float_image[i];
661 }
662 else if (metric == METRIC_SUBPIXEL)
663 {
664 unsigned char *scaled_data;
665 int i;
666 int channel;
667
668 if (float_image == 0)
669 float_image = (float*)malloc(sizeof(float) * NUM_SUBPIXELS * NUM_CHANNELS);
670
671 scaled_data = scale_image(image_data, image_width, image_height, x, y, width, height,
672 NUM_SUBPIXEL_ROWS_COLS, NUM_SUBPIXEL_ROWS_COLS);
673
674 for (i = 0; i < NUM_SUBPIXELS * NUM_CHANNELS; ++i)
675 float_image[i] = scaled_data[i];
676
677 free(scaled_data);
678
679 transform_rgb_to_yiq(float_image, NUM_SUBPIXELS);
680
681 for (channel = 0; channel < NUM_CHANNELS; ++channel)
682 for (i = 0; i < NUM_SUBPIXELS; ++i)
683 coeffs->subpixel.subpixels[channel * NUM_SUBPIXELS + i] = float_image[i * NUM_CHANNELS + channel];
684 }
685 else
686 assert(0);
687 }
688
689 static void
generate_metapixel_coefficients(metapixel_t * pixel,unsigned char * image_data,coefficient_with_index_t raw_coeffs[NUM_COEFFS])690 generate_metapixel_coefficients (metapixel_t *pixel, unsigned char *image_data,
691 coefficient_with_index_t raw_coeffs[NUM_COEFFS])
692 {
693 static float float_image[NUM_CHANNELS * IMAGE_SIZE * IMAGE_SIZE];
694 static float sums[NUM_COEFFS];
695
696 unsigned char *scaled_data;
697 int i, channel;
698
699 /* generate wavelet coefficients */
700 if (small_width != IMAGE_SIZE || small_height != IMAGE_SIZE)
701 {
702 scaled_data = scale_image(image_data, small_width, small_height,
703 0, 0, small_width, small_height, IMAGE_SIZE, IMAGE_SIZE);
704 assert(scaled_data != 0);
705 }
706 else
707 scaled_data = image_data;
708
709 for (i = 0; i < IMAGE_SIZE * IMAGE_SIZE * NUM_CHANNELS; ++i)
710 float_image[i] = scaled_data[i];
711
712 if (scaled_data != image_data)
713 free(scaled_data);
714
715 transform_rgb_to_yiq(float_image, IMAGE_SIZE * IMAGE_SIZE);
716 decompose_image(float_image);
717
718 find_highest_coefficients(float_image, raw_coeffs);
719
720 generate_search_coeffs(&pixel->coeffs, sums, raw_coeffs);
721
722 for (i = 0; i < NUM_CHANNELS; ++i)
723 pixel->means[i] = float_image[i];
724
725 /* generate subpixel coefficients */
726 if (small_width != NUM_SUBPIXEL_ROWS_COLS || small_height != NUM_SUBPIXEL_ROWS_COLS)
727 {
728 scaled_data = scale_image(image_data, small_width, small_height, 0, 0, small_width, small_height,
729 NUM_SUBPIXEL_ROWS_COLS, NUM_SUBPIXEL_ROWS_COLS);
730 assert(scaled_data != 0);
731 }
732 else
733 scaled_data = image_data;
734
735 assert(NUM_SUBPIXELS <= IMAGE_SIZE * IMAGE_SIZE);
736
737 for (i = 0; i < NUM_SUBPIXELS * NUM_CHANNELS; ++i)
738 float_image[i] = scaled_data[i];
739
740 transform_rgb_to_yiq(float_image, NUM_SUBPIXELS);
741
742 for (channel = 0; channel < NUM_CHANNELS; ++channel)
743 for (i = 0; i < NUM_SUBPIXELS; ++i)
744 pixel->subpixels[channel * NUM_SUBPIXELS + i] = (int)float_image[i * NUM_CHANNELS + channel];
745
746 if (scaled_data != image_data)
747 free(scaled_data);
748 }
749
750 static int
metapixel_in_array(metapixel_t * pixel,metapixel_t ** array,int size)751 metapixel_in_array (metapixel_t *pixel, metapixel_t **array, int size)
752 {
753 int i;
754
755 for (i = 0; i < size; ++i)
756 if (array[i] == pixel)
757 return 1;
758 return 0;
759 }
760
761 compare_func_t
compare_func_for_metric(int metric)762 compare_func_for_metric (int metric)
763 {
764 if (metric == METRIC_WAVELET)
765 return wavelet_compare;
766 else if (metric == METRIC_SUBPIXEL)
767 return subpixel_compare;
768 else
769 assert(0);
770 return 0;
771 }
772
773 static int
manhattan_distance(int x1,int y1,int x2,int y2)774 manhattan_distance (int x1, int y1, int x2, int y2)
775 {
776 return abs(x1 - x2) + abs(y1 - y2);
777 }
778
779 static match_t
metapixel_nearest_to(coeffs_t * coeffs,int metric,int x,int y,metapixel_t ** forbidden,int num_forbidden,int (* validity_func)(void *,metapixel_t *,int,int),void * validity_func_data)780 metapixel_nearest_to (coeffs_t *coeffs, int metric, int x, int y,
781 metapixel_t **forbidden, int num_forbidden,
782 int (*validity_func) (void*, metapixel_t*, int, int),
783 void *validity_func_data)
784 {
785 float best_score = FLT_MAX;
786 metapixel_t *best_fit = 0, *pixel;
787 compare_func_t compare_func = compare_func_for_metric(metric);
788 match_t match;
789
790 for (pixel = first_pixel; pixel != 0; pixel = pixel->next)
791 {
792 float score;
793
794 if (manhattan_distance(x, y, pixel->anti_x, pixel->anti_y)
795 < forbid_reconstruction_radius)
796 continue;
797
798 score = compare_func(coeffs, pixel, best_score);
799
800 if (score < best_score && !metapixel_in_array(pixel, forbidden, num_forbidden)
801 && (validity_func == 0 || validity_func(validity_func_data, pixel, x, y)))
802 {
803 best_score = score;
804 best_fit = pixel;
805 }
806 }
807
808 match.pixel = best_fit;
809 match.score = best_score;
810
811 return match;
812 }
813
814 static void
get_n_metapixel_nearest_to(int n,global_match_t * matches,coeffs_t * coeffs,int metric)815 get_n_metapixel_nearest_to (int n, global_match_t *matches, coeffs_t *coeffs, int metric)
816 {
817 compare_func_t compare_func = compare_func_for_metric(metric);
818 int i;
819 metapixel_t *pixel;
820
821 assert(num_metapixels >= n);
822
823 i = 0;
824 for (pixel = first_pixel; pixel != 0; pixel = pixel->next)
825 {
826 float score = compare_func(coeffs, pixel, (i < n) ? FLT_MAX : matches[n - 1].score);
827
828 if (i < n || score < matches[n - 1].score)
829 {
830 int j, m;
831
832 m = MIN(i, n);
833
834 for (j = 0; j < m; ++j)
835 if (matches[j].score > score)
836 break;
837
838 assert(j <= m && j < n);
839
840 memmove(matches + j + 1, matches + j, sizeof(global_match_t) * (MIN(n, m + 1) - (j + 1)));
841
842 matches[j].pixel = pixel;
843 matches[j].score = score;
844 }
845
846 ++i;
847 }
848
849 assert(i >= n);
850 }
851
852 static void
paste_metapixel(metapixel_t * pixel,unsigned char * data,int width,int height,int x,int y)853 paste_metapixel (metapixel_t *pixel, unsigned char *data, int width, int height, int x, int y)
854 {
855 int i;
856 int pixel_width, pixel_height;
857 unsigned char *pixel_data;
858
859 if (pixel->data != 0)
860 {
861 pixel_data = pixel->data;
862 pixel_width = pixel->width;
863 pixel_height = pixel->height;
864 }
865 else
866 {
867 pixel_data = read_image(pixel->filename, &pixel_width, &pixel_height);
868
869 if (pixel_data == 0)
870 {
871 fprintf(stderr, "Error: cannot read metapixel file `%s'\n", pixel->filename);
872 exit(1);
873 }
874 }
875
876 if (pixel_width != small_width || pixel_height != small_height)
877 {
878 unsigned char *scaled_data = scale_image(pixel_data, pixel_width, pixel_height,
879 0, 0, pixel_width, pixel_height,
880 small_width, small_height);
881
882 if (pixel->data == 0)
883 free(pixel_data);
884 pixel_data = scaled_data;
885 }
886
887 for (i = 0; i < small_height; ++i)
888 memcpy(data + NUM_CHANNELS * (x + (y + i) * width),
889 pixel_data + NUM_CHANNELS * i * small_width, NUM_CHANNELS * small_width);
890
891 if (pixel_data != pixel->data)
892 free(pixel_data);
893 }
894
895 static classic_reader_t*
init_classic_reader(char * input_name,float scale)896 init_classic_reader (char *input_name, float scale)
897 {
898 classic_reader_t *reader = (classic_reader_t*)malloc(sizeof(classic_reader_t));
899
900 assert(reader != 0);
901
902 reader->image_reader = open_image_reading(input_name);
903 if (reader->image_reader == 0)
904 {
905 fprintf(stderr, "cannot read image `%s'\n", input_name);
906 exit(1);
907 }
908
909 reader->in_image_width = reader->image_reader->width;
910 reader->in_image_height = reader->image_reader->height;
911
912 reader->out_image_width = (((int)((float)reader->in_image_width * scale) - 1) / small_width + 1) * small_width;
913 reader->out_image_height = (((int)((float)reader->in_image_height * scale) - 1) / small_height + 1) * small_height;
914
915 assert(reader->out_image_width % small_width == 0);
916 assert(reader->out_image_height % small_height == 0);
917
918 reader->metawidth = reader->out_image_width / small_width;
919 reader->metaheight = reader->out_image_height / small_height;
920
921 reader->in_image_data = 0;
922 reader->y = 0;
923
924 return reader;
925 }
926
927 static void
read_classic_row(classic_reader_t * reader)928 read_classic_row (classic_reader_t *reader)
929 {
930 if (reader->in_image_data != 0)
931 {
932 assert(reader->y > 0);
933 free(reader->in_image_data);
934 }
935 else
936 assert(reader->y == 0);
937
938 reader->num_lines = (reader->y + 1) * reader->in_image_height / reader->metaheight
939 - reader->y * reader->in_image_height / reader->metaheight;
940
941 reader->in_image_data = (unsigned char*)malloc(reader->num_lines * reader->in_image_width * NUM_CHANNELS);
942 assert(reader->in_image_data != 0);
943
944 read_lines(reader->image_reader, reader->in_image_data, reader->num_lines);
945
946 ++reader->y;
947 }
948
949 static void
compute_classic_column_coords(classic_reader_t * reader,int x,int * left_x,int * width)950 compute_classic_column_coords (classic_reader_t *reader, int x, int *left_x, int *width)
951 {
952 *left_x = x * reader->in_image_width / reader->metawidth;
953 *width = (x + 1) * reader->in_image_width / reader->metawidth - *left_x;
954 }
955
956 static void
generate_search_coeffs_for_classic_subimage(classic_reader_t * reader,int x,coeffs_t * coeffs,int metric)957 generate_search_coeffs_for_classic_subimage (classic_reader_t *reader, int x, coeffs_t *coeffs, int metric)
958 {
959 int left_x, width;
960
961 compute_classic_column_coords(reader, x, &left_x, &width);
962 generate_search_coeffs_for_subimage(coeffs, reader->in_image_data, reader->in_image_width, reader->num_lines,
963 left_x, 0, width, reader->num_lines, metric);
964 }
965
966 static void
free_classic_reader(classic_reader_t * reader)967 free_classic_reader (classic_reader_t *reader)
968 {
969 if (reader->in_image_data != 0)
970 free(reader->in_image_data);
971 free_image_reader(reader->image_reader);
972 free(reader);
973 }
974
975 static mosaic_t*
init_mosaic_from_reader(classic_reader_t * reader)976 init_mosaic_from_reader (classic_reader_t *reader)
977 {
978 mosaic_t *mosaic = (mosaic_t*)malloc(sizeof(mosaic_t));
979 int metawidth = reader->metawidth, metaheight = reader->metaheight;
980 int i;
981
982 assert(mosaic != 0);
983
984 mosaic->metawidth = metawidth;
985 mosaic->metaheight = metaheight;
986 mosaic->matches = (match_t*)malloc(sizeof(match_t) * metawidth * metaheight);
987
988 for (i = 0; i < metawidth * metaheight; ++i)
989 mosaic->matches[i].pixel = 0;
990
991 return mosaic;
992 }
993
994 static mosaic_t*
generate_local_classic(classic_reader_t * reader,int min_distance,int metric)995 generate_local_classic (classic_reader_t *reader, int min_distance, int metric)
996 {
997 mosaic_t *mosaic = init_mosaic_from_reader(reader);
998 int metawidth = reader->metawidth, metaheight = reader->metaheight;
999 int x, y;
1000 metapixel_t **neighborhood = 0;
1001 int neighborhood_diameter = min_distance * 2 + 1;
1002 int neighborhood_size = (neighborhood_diameter * neighborhood_diameter - 1) / 2;
1003
1004 if (min_distance > 0)
1005 neighborhood = (metapixel_t**)malloc(sizeof(metapixel_t*) * neighborhood_size);
1006
1007 for (y = 0; y < metaheight; ++y)
1008 {
1009 read_classic_row(reader);
1010
1011 for (x = 0; x < metawidth; ++x)
1012 {
1013 match_t match;
1014 int i;
1015 coeffs_t coeffs;
1016
1017 for (i = 0; i < neighborhood_size; ++i)
1018 {
1019 int nx = x + i % neighborhood_diameter - min_distance;
1020 int ny = y + i / neighborhood_diameter - min_distance;
1021
1022 if (nx < 0 || nx >= metawidth || ny < 0 || ny >= metaheight)
1023 neighborhood[i] = 0;
1024 else
1025 neighborhood[i] = mosaic->matches[ny * metawidth + nx].pixel;
1026 }
1027
1028 generate_search_coeffs_for_classic_subimage(reader, x, &coeffs, metric);
1029
1030 match = metapixel_nearest_to(&coeffs, metric, x, y, neighborhood, neighborhood_size, 0, 0);
1031
1032 if (match.pixel == 0)
1033 {
1034 fprintf(stderr, "Error: cannot find a matching image - try using a shorter minimum distance.\n");
1035 exit(1);
1036 }
1037
1038 mosaic->matches[y * metawidth + x] = match;
1039
1040 printf(".");
1041 fflush(stdout);
1042 }
1043 }
1044
1045 free(neighborhood);
1046
1047 printf("\n");
1048
1049 return mosaic;
1050 }
1051
1052 static int
compare_global_matches(const void * _m1,const void * _m2)1053 compare_global_matches (const void *_m1, const void *_m2)
1054 {
1055 global_match_t *m1 = (global_match_t*)_m1;
1056 global_match_t *m2 = (global_match_t*)_m2;
1057
1058 if (m1->score < m2->score)
1059 return -1;
1060 if (m1->score > m2->score)
1061 return 1;
1062 return 0;
1063 }
1064
1065 static mosaic_t*
generate_global_classic(classic_reader_t * reader,int metric)1066 generate_global_classic (classic_reader_t *reader, int metric)
1067 {
1068 mosaic_t *mosaic = init_mosaic_from_reader(reader);
1069 int metawidth = reader->metawidth, metaheight = reader->metaheight;
1070 int x, y;
1071 global_match_t *matches, *m;
1072 /* FIXME: this will overflow if metawidth and/or metaheight are large! */
1073 int num_matches = (metawidth * metaheight) * (metawidth * metaheight);
1074 int i, ignore_forbidden;
1075 int num_locations_filled;
1076 metapixel_t *pixel;
1077
1078 if (num_metapixels < metawidth * metaheight)
1079 {
1080 fprintf(stderr,
1081 "global search method needs at least as much\n"
1082 "metapixels as there are locations\n");
1083 exit(1);
1084 }
1085
1086 matches = (global_match_t*)malloc(sizeof(global_match_t) * num_matches);
1087 assert(matches != 0);
1088
1089 m = matches;
1090 for (y = 0; y < metaheight; ++y)
1091 {
1092 read_classic_row(reader);
1093
1094 for (x = 0; x < metawidth; ++x)
1095 {
1096 coeffs_t coeffs;
1097
1098 generate_search_coeffs_for_classic_subimage(reader, x, &coeffs, metric);
1099
1100 get_n_metapixel_nearest_to(metawidth * metaheight, m, &coeffs, metric);
1101 for (i = 0; i < metawidth * metaheight; ++i)
1102 {
1103 int j;
1104
1105 for (j = i + 1; j < metawidth * metaheight; ++j)
1106 assert(m[i].pixel != m[j].pixel);
1107
1108 m[i].x = x;
1109 m[i].y = y;
1110 }
1111
1112 m += metawidth * metaheight;
1113
1114 printf(".");
1115 fflush(stdout);
1116 }
1117 }
1118
1119 qsort(matches, num_matches, sizeof(global_match_t), compare_global_matches);
1120
1121 for (pixel = first_pixel; pixel != 0; pixel = pixel->next)
1122 pixel->flag = 0;
1123
1124 num_locations_filled = 0;
1125 for (ignore_forbidden = 0; ignore_forbidden < 2; ++ignore_forbidden)
1126 {
1127 for (i = 0; i < num_matches; ++i)
1128 {
1129 int index = matches[i].y * metawidth + matches[i].x;
1130
1131 if (!ignore_forbidden
1132 && manhattan_distance(matches[i].x, matches[i].y,
1133 matches[i].pixel->anti_x, matches[i].pixel->anti_y)
1134 < forbid_reconstruction_radius)
1135 continue;
1136
1137 if (matches[i].pixel->flag)
1138 continue;
1139
1140 if (num_locations_filled >= metawidth * metaheight)
1141 break;
1142
1143 if (mosaic->matches[index].pixel == 0)
1144 {
1145 if (forbid_reconstruction_radius > 0 && ignore_forbidden)
1146 {
1147 printf("!");
1148 fflush(stdout);
1149 }
1150 mosaic->matches[index].pixel = matches[i].pixel;
1151 mosaic->matches[index].score = matches[i].score;
1152
1153 matches[i].pixel->flag = 1;
1154
1155 ++num_locations_filled;
1156 }
1157 }
1158 if (forbid_reconstruction_radius == 0)
1159 break;
1160 }
1161 assert(num_locations_filled == metawidth * metaheight);
1162
1163 free(matches);
1164
1165 printf("\n");
1166
1167 return mosaic;
1168 }
1169
1170 static void
print_current_time(void)1171 print_current_time (void)
1172 {
1173 struct timeval tv;
1174
1175 gettimeofday(&tv, 0);
1176
1177 printf("time: %lu %lu\n", (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
1178 }
1179
1180 static void
paste_classic(mosaic_t * mosaic,char * input_name,char * output_name,int cheat)1181 paste_classic (mosaic_t *mosaic, char *input_name, char *output_name, int cheat)
1182 {
1183 image_reader_t *reader;
1184 image_writer_t *writer = 0;
1185 int out_image_width, out_image_height;
1186 int x, y;
1187 unsigned char *out_image_data;
1188 int in_image_width, in_image_height;
1189 int metawidth = mosaic->metawidth, metaheight = mosaic->metaheight;
1190
1191 if (cheat > 0)
1192 {
1193 reader = open_image_reading(input_name);
1194 if (reader == 0)
1195 {
1196 fprintf(stderr, "cannot read image `%s'\n", input_name);
1197 exit(1);
1198 }
1199
1200 in_image_width = reader->width;
1201 in_image_height = reader->height;
1202 }
1203 else
1204 {
1205 reader = 0;
1206 in_image_width = in_image_height = 0;
1207 }
1208
1209 out_image_width = mosaic->metawidth * small_width;
1210 out_image_height = mosaic->metaheight * small_height;
1211
1212 if (!benchmark_rendering)
1213 {
1214 writer = open_image_writing(output_name, out_image_width, out_image_height, 3, out_image_width * 3, IMAGE_FORMAT_AUTO);
1215 if (writer == 0)
1216 {
1217 fprintf(stderr, "Error: cannot write image `%s'\n", output_name);
1218 exit(1);
1219 }
1220 }
1221
1222 out_image_data = (unsigned char*)malloc(out_image_width * small_height * NUM_CHANNELS);
1223
1224 if (benchmark_rendering)
1225 print_current_time();
1226
1227 for (y = 0; y < metaheight; ++y)
1228 {
1229 for (x = 0; x < metawidth; ++x)
1230 {
1231 if (benchmark_rendering)
1232 assert(mosaic->matches[y * metawidth + x].pixel->data != 0);
1233
1234 paste_metapixel(mosaic->matches[y * metawidth + x].pixel, out_image_data, out_image_width,
1235 small_height, x * small_width, 0);
1236 if (!benchmark_rendering)
1237 {
1238 printf("X");
1239 fflush(stdout);
1240 }
1241 }
1242
1243 if (cheat > 0)
1244 {
1245 int num_lines = (y + 1) * in_image_height / metaheight - y * in_image_height / metaheight;
1246 unsigned char *in_image_data = (unsigned char*)malloc(num_lines * in_image_width * NUM_CHANNELS);
1247 unsigned char *source_data;
1248
1249 assert(in_image_data != 0);
1250
1251 read_lines(reader, in_image_data, num_lines);
1252
1253 if (in_image_width != out_image_width || num_lines != small_height)
1254 source_data = scale_image(in_image_data, in_image_width, num_lines,
1255 0, 0, in_image_width, num_lines,
1256 out_image_width, small_height);
1257 else
1258 source_data = in_image_data;
1259
1260 alpha_compose(out_image_data, out_image_width, small_height, source_data, cheat);
1261
1262 if (source_data != in_image_data)
1263 free(source_data);
1264
1265 free(in_image_data);
1266 }
1267
1268 if (!benchmark_rendering)
1269 write_lines(writer, out_image_data, small_height);
1270 }
1271
1272 if (benchmark_rendering)
1273 print_current_time();
1274
1275 free(out_image_data);
1276
1277 if (!benchmark_rendering)
1278 free_image_writer(writer);
1279 if (cheat > 0)
1280 free_image_reader(reader);
1281
1282 printf("\n");
1283 }
1284
1285 static void
pixel_add_collage_position(metapixel_t * pixel,int x,int y)1286 pixel_add_collage_position (metapixel_t *pixel, int x, int y)
1287 {
1288 position_t *position = (position_t*)malloc(sizeof(position_t));
1289
1290 assert(position != 0);
1291
1292 position->x = x;
1293 position->y = y;
1294
1295 position->next = pixel->collage_positions;
1296 pixel->collage_positions = position;
1297 }
1298
1299 static int
pixel_valid_for_collage_position(void * data,metapixel_t * pixel,int x,int y)1300 pixel_valid_for_collage_position (void *data, metapixel_t *pixel, int x, int y)
1301 {
1302 int min_distance = (int)(unsigned long)data;
1303 position_t *position;
1304
1305 if (min_distance <= 0)
1306 return 1;
1307
1308 for (position = pixel->collage_positions; position != 0; position = position->next)
1309 if (manhattan_distance(x, y, position->x, position->y) < min_distance)
1310 return 0;
1311
1312 return 1;
1313 }
1314
1315 static void
generate_collage(char * input_name,char * output_name,float scale,int min_distance,int metric,int cheat)1316 generate_collage (char *input_name, char *output_name, float scale, int min_distance, int metric, int cheat)
1317 {
1318 unsigned char *in_image_data, *out_image_data;
1319 int in_image_width, in_image_height;
1320 char *bitmap;
1321 int num_pixels_done = 0;
1322
1323 in_image_data = read_image(input_name, &in_image_width, &in_image_height);
1324 if (in_image_data == 0)
1325 {
1326 fprintf(stderr, "could not read image `%s'\n", input_name);
1327 exit(1);
1328 }
1329
1330 if (scale != 1.0)
1331 {
1332 int new_width = (float)in_image_width * scale;
1333 int new_height = (float)in_image_height * scale;
1334 unsigned char *scaled_data;
1335
1336 if (new_width < small_width || new_height < small_height)
1337 {
1338 fprintf(stderr, "source image or scaling factor too small\n");
1339 exit(1);
1340 }
1341
1342 printf("scaling source image to %dx%d\n", new_width, new_height);
1343
1344 scaled_data = scale_image(in_image_data, in_image_width, in_image_height,
1345 0, 0, in_image_width, in_image_height,
1346 new_width, new_height);
1347
1348 in_image_width = new_width;
1349 in_image_height = new_height;
1350
1351 free(in_image_data);
1352 in_image_data = scaled_data;
1353 }
1354
1355 out_image_data = (unsigned char*)malloc(in_image_width * in_image_height * NUM_CHANNELS);
1356
1357 bitmap = (char*)malloc(in_image_width * in_image_height);
1358 memset(bitmap, 0, in_image_width * in_image_height);
1359
1360 while (num_pixels_done < in_image_width * in_image_height)
1361 {
1362 int i, j;
1363 int x, y;
1364 coeffs_t coeffs;
1365 match_t match;
1366
1367 while (1)
1368 {
1369 x = random() % in_image_width - small_width / 2;
1370 y = random() % in_image_height - small_height / 2;
1371
1372 if (x < 0)
1373 x = 0;
1374 if (x + small_width > in_image_width)
1375 x = in_image_width - small_width;
1376
1377 if (y < 0)
1378 y = 0;
1379 if (y + small_height > in_image_height)
1380 y = in_image_height - small_height;
1381
1382 for (j = 0; j < small_height; ++j)
1383 for (i = 0; i < small_width; ++i)
1384 if (!bitmap[(y + j) * in_image_width + x + i])
1385 goto out;
1386 }
1387
1388 out:
1389 generate_search_coeffs_for_subimage(&coeffs, in_image_data, in_image_width, in_image_height,
1390 x, y, small_width, small_height, metric);
1391
1392 match = metapixel_nearest_to(&coeffs, metric, x, y, 0, 0,
1393 pixel_valid_for_collage_position, (void*)(unsigned long)min_distance);
1394
1395 if (match.pixel == 0)
1396 {
1397 fprintf(stderr, "Error: cannot find a matching image - try using a shorter minimum distance.\n");
1398 exit(1);
1399 }
1400
1401 paste_metapixel(match.pixel, out_image_data, in_image_width, in_image_height, x, y);
1402
1403 if (min_distance > 0)
1404 pixel_add_collage_position(match.pixel, x, y);
1405
1406 for (j = 0; j < small_height; ++j)
1407 for (i = 0; i < small_width; ++i)
1408 if (!bitmap[(y + j) * in_image_width + x + i])
1409 {
1410 bitmap[(y + j) * in_image_width + x + i] = 1;
1411 ++num_pixels_done;
1412 }
1413
1414 printf(".");
1415 fflush(stdout);
1416 }
1417
1418 write_image(output_name, in_image_width, in_image_height, out_image_data, 3, in_image_width * 3, IMAGE_FORMAT_PNG);
1419
1420 free(bitmap);
1421 free(out_image_data);
1422 free(in_image_data);
1423 }
1424
1425 static int
read_tables(const char * library_dir)1426 read_tables (const char *library_dir)
1427 {
1428 lisp_object_t *pattern;
1429 lisp_object_t *obj;
1430 lisp_stream_t stream;
1431 int num_subs;
1432 pools_t pools;
1433 allocator_t allocator;
1434 int dir_strlen = strlen(library_dir);
1435 char tables_name[dir_strlen + 1 + strlen(TABLES_FILENAME) + 1];
1436
1437 strcpy(tables_name, library_dir);
1438 strcat(tables_name, "/");
1439 strcat(tables_name, TABLES_FILENAME);
1440
1441 if (lisp_stream_init_path(&stream, tables_name) == 0)
1442 return 0;
1443
1444 pattern = lisp_read_from_string("(small-image #?(string) (size #?(integer) #?(integer))"
1445 " (wavelet (means #?(real) #?(real) #?(real)) (coeffs . #?(list)))"
1446 " (subpixel (y . #?(list)) (i . #?(list)) (q . #?(list))))");
1447 assert(pattern != 0
1448 && lisp_type(pattern) != LISP_TYPE_EOF
1449 && lisp_type(pattern) != LISP_TYPE_PARSE_ERROR);
1450 assert(lisp_compile_pattern(&pattern, &num_subs));
1451 assert(num_subs == 10);
1452
1453 init_pools(&pools);
1454 init_pools_allocator(&allocator, &pools);
1455
1456 for (;;)
1457 {
1458 int type;
1459
1460 reset_pools(&pools);
1461 obj = lisp_read_with_allocator(&allocator, &stream);
1462 type = lisp_type(obj);
1463 if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR)
1464 {
1465 lisp_object_t *vars[10];
1466
1467 if (lisp_match_pattern(pattern, obj, vars, num_subs))
1468 {
1469 metapixel_t *pixel = new_metapixel();
1470 coefficient_with_index_t coeffs[NUM_COEFFS];
1471 lisp_object_t *lst;
1472 int channel, i;
1473 char *filename = strip_path(lisp_string(vars[0]));
1474
1475 pixel->filename = (char*)malloc(dir_strlen + 1 + strlen(filename) + 1);
1476
1477 strcpy(pixel->filename, library_dir);
1478 strcat(pixel->filename, "/");
1479 strcat(pixel->filename, filename);
1480
1481 for (channel = 0; channel < NUM_CHANNELS; ++channel)
1482 pixel->means[channel] = lisp_real(vars[3 + channel]);
1483
1484 if (lisp_list_length(vars[6]) != NUM_COEFFS)
1485 fprintf(stderr, "wrong number of wavelet coefficients in `%s'\n", pixel->filename);
1486 else
1487 {
1488 static float sums[NUM_COEFFS];
1489
1490 lst = vars[6];
1491 for (i = 0; i < NUM_COEFFS; ++i)
1492 {
1493 coeffs[i].index = lisp_integer(lisp_car(lst));
1494 lst = lisp_cdr(lst);
1495 }
1496
1497 generate_search_coeffs(&pixel->coeffs, sums, coeffs);
1498 }
1499
1500 for (channel = 0; channel < NUM_CHANNELS; ++channel)
1501 {
1502 lst = vars[7 + channel];
1503
1504 if (lisp_list_length(lst) != NUM_SUBPIXELS)
1505 fprintf(stderr, "wrong number of subpixels in `%s'\n", pixel->filename);
1506 else
1507 for (i = 0; i < NUM_SUBPIXELS; ++i)
1508 {
1509 pixel->subpixels[channel * NUM_SUBPIXELS + i] = lisp_integer(lisp_car(lst));
1510 lst = lisp_cdr(lst);
1511 }
1512 }
1513
1514 pixel->data = 0;
1515 pixel->collage_positions = 0;
1516
1517 add_metapixel(pixel);
1518 }
1519 else
1520 {
1521 fprintf(stderr, "unknown expression ");
1522 lisp_dump(obj, stderr);
1523 fprintf(stderr, "\n");
1524 }
1525 }
1526 else if (type == LISP_TYPE_PARSE_ERROR)
1527 fprintf(stderr, "Error: parse error in tables file.\n");
1528
1529 if (type == LISP_TYPE_EOF)
1530 break;
1531 }
1532
1533 lisp_stream_free_path(&stream);
1534
1535 free_pools(&pools);
1536
1537 return 1;
1538 }
1539
1540 static metapixel_t*
find_metapixel(char * filename)1541 find_metapixel (char *filename)
1542 {
1543 metapixel_t *pixel;
1544
1545 for (pixel = first_pixel; pixel != 0; pixel = pixel->next)
1546 if (strcmp(pixel->filename, filename) == 0)
1547 return pixel;
1548
1549 return 0;
1550 }
1551
1552 static mosaic_t*
read_protocol(FILE * in)1553 read_protocol (FILE *in)
1554 {
1555 lisp_object_t *obj;
1556 lisp_stream_t stream;
1557 mosaic_t *mosaic = (mosaic_t*)malloc(sizeof(mosaic_t));
1558 int type;
1559
1560 lisp_stream_init_file(&stream, in);
1561
1562 obj = lisp_read(&stream);
1563 type = lisp_type(obj);
1564 if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR)
1565 {
1566 lisp_object_t *vars[3];
1567
1568 if (lisp_match_string("(mosaic (size #?(integer) #?(integer)) (metapixels . #?(list)))",
1569 obj, vars))
1570 {
1571 int i;
1572 int num_pixels;
1573 lisp_object_t *lst;
1574
1575 mosaic->metawidth = lisp_integer(vars[0]);
1576 mosaic->metaheight = lisp_integer(vars[1]);
1577 num_pixels = mosaic->metawidth * mosaic->metaheight;
1578 mosaic->matches = (match_t*)malloc(sizeof(match_t) * num_pixels);
1579
1580 for (i = 0; i < num_pixels; ++i)
1581 mosaic->matches[i].pixel = 0;
1582
1583 if (lisp_list_length(vars[2]) != num_pixels)
1584 {
1585 fprintf(stderr, "mosaic should have %d metapixels, not %d\n", num_pixels, lisp_list_length(vars[2]));
1586 exit(1);
1587 }
1588
1589 lst = vars[2];
1590 for (i = 0; i < num_pixels; ++i)
1591 {
1592 lisp_object_t *vars[5];
1593
1594 if (lisp_match_string("(#?(integer) #?(integer) #?(integer) #?(integer) #?(string))",
1595 lisp_car(lst), vars))
1596 {
1597 int x = lisp_integer(vars[0]);
1598 int y = lisp_integer(vars[1]);
1599 int width = lisp_integer(vars[2]);
1600 int height = lisp_integer(vars[3]);
1601 metapixel_t *pixel;
1602
1603 if (width != 1 || height != 1)
1604 {
1605 fprintf(stderr, "width and height in metapixel must both be 1\n");
1606 exit(1);
1607 }
1608
1609 if (mosaic->matches[y * mosaic->metawidth + x].pixel != 0)
1610 {
1611 fprintf(stderr, "location (%d,%d) is assigned to twice\n", x, y);
1612 exit(1);
1613 }
1614
1615 pixel = find_metapixel(lisp_string(vars[4]));
1616
1617 if (pixel == 0)
1618 {
1619 fprintf(stderr, "could not find metapixel `%s'\n", lisp_string(vars[4]));
1620 exit(1);
1621 }
1622
1623 mosaic->matches[y * mosaic->metawidth + x].pixel = pixel;
1624 }
1625 else
1626 {
1627 fprintf(stderr, "metapixel ");
1628 lisp_dump(lisp_car(lst), stderr);
1629 fprintf(stderr, " has wrong format\n");
1630 exit(1);
1631 }
1632
1633 lst = lisp_cdr(lst);
1634 }
1635 }
1636 else
1637 {
1638 fprintf(stderr, "malformed expression in protocol file\n");
1639 exit(1);
1640 }
1641 }
1642 else
1643 {
1644 fprintf(stderr, "error in protocol file\n");
1645 exit(1);
1646 }
1647 lisp_free(obj);
1648
1649 return mosaic;
1650 }
1651
1652 void
free_mosaic(mosaic_t * mosaic)1653 free_mosaic (mosaic_t *mosaic)
1654 {
1655 free(mosaic->matches);
1656 free(mosaic);
1657 }
1658
1659 int
make_classic_mosaic(char * in_image_name,char * out_image_name,int metric,float scale,int search,int min_distance,int cheat,char * in_protocol_name,char * out_protocol_name)1660 make_classic_mosaic (char *in_image_name, char *out_image_name,
1661 int metric, float scale, int search, int min_distance, int cheat,
1662 char *in_protocol_name, char *out_protocol_name)
1663 {
1664 mosaic_t *mosaic;
1665 int x, y;
1666
1667 if (in_protocol_name != 0)
1668 {
1669 FILE *protocol_in = fopen(in_protocol_name, "rb");
1670
1671 if (protocol_in == 0)
1672 {
1673 fprintf(stderr, "cannot open protocol file for reading `%s': %s\n", in_protocol_name, strerror(errno));
1674 return 0;
1675 }
1676
1677 mosaic = read_protocol(protocol_in);
1678
1679 fclose(protocol_in);
1680 }
1681 else
1682 {
1683 classic_reader_t *reader = init_classic_reader(in_image_name, scale);
1684
1685 if (search == SEARCH_LOCAL)
1686 mosaic = generate_local_classic(reader, min_distance, metric);
1687 else if (search == SEARCH_GLOBAL)
1688 mosaic = generate_global_classic(reader, metric);
1689 else
1690 assert(0);
1691
1692 free_classic_reader(reader);
1693 }
1694
1695 assert(mosaic != 0);
1696
1697 if (benchmark_rendering)
1698 {
1699 int i;
1700
1701 for (i = 0; i < mosaic->metawidth * mosaic->metaheight; ++i)
1702 {
1703 metapixel_t *pixel = mosaic->matches[i].pixel;
1704
1705 if (pixel->data == 0)
1706 {
1707 pixel->data = read_image(pixel->filename, &pixel->width, &pixel->height);
1708
1709 assert(pixel->data != 0);
1710 }
1711 }
1712 }
1713
1714 if (out_protocol_name != 0)
1715 {
1716 FILE *protocol_out = fopen(out_protocol_name, "wb");
1717
1718 if (protocol_out == 0)
1719 {
1720 fprintf(stderr, "cannot open protocol file `%s' for writing: %s\n", out_protocol_name, strerror(errno));
1721 /* FIXME: free stuff */
1722 return 0;
1723 }
1724 else
1725 {
1726 fprintf(protocol_out, "(mosaic (size %d %d)\n(metapixels\n", mosaic->metawidth, mosaic->metaheight);
1727 for (y = 0; y < mosaic->metaheight; ++y)
1728 {
1729 for (x = 0; x < mosaic->metawidth; ++x)
1730 {
1731 match_t *match = &mosaic->matches[y * mosaic->metawidth + x];
1732 lisp_object_t *obj = lisp_make_string(match->pixel->filename);
1733
1734 fprintf(protocol_out, "(%d %d 1 1 ", x, y);
1735 lisp_dump(obj, protocol_out);
1736 fprintf(protocol_out, ") ; %f\n", match->score);
1737
1738 lisp_free(obj);
1739 }
1740 }
1741 fprintf(protocol_out, "))\n");
1742 }
1743
1744 fclose(protocol_out);
1745 }
1746
1747 paste_classic(mosaic, in_image_name, out_image_name, cheat);
1748
1749 free_mosaic(mosaic);
1750
1751 return 1;
1752 }
1753
1754 #define RC_FILE_NAME ".metapixelrc"
1755
1756 static void
read_rc_file(void)1757 read_rc_file (void)
1758 {
1759 lisp_stream_t stream;
1760 char *homedir;
1761 char *filename;
1762
1763 homedir = getenv("HOME");
1764
1765 if (homedir == 0)
1766 {
1767 fprintf(stderr, "Warning: HOME is not in environment - cannot find rc file.\n");
1768 return;
1769 }
1770
1771 filename = (char*)malloc(strlen(homedir) + 1 + strlen(RC_FILE_NAME) + 1);
1772 strcpy(filename, homedir);
1773 strcat(filename, "/");
1774 strcat(filename, RC_FILE_NAME);
1775
1776 if (access(filename, R_OK) == 0)
1777 {
1778 if (lisp_stream_init_path(&stream, filename) == 0)
1779 fprintf(stderr, "Warning: could not open rc file `%s'.", filename);
1780 else
1781 {
1782 for (;;)
1783 {
1784 lisp_object_t *obj;
1785 int type;
1786
1787 obj = lisp_read(&stream);
1788 type = lisp_type(obj);
1789
1790 if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR)
1791 {
1792 lisp_object_t *vars[3];
1793
1794 if (lisp_match_string("(prepare-directory #?(string))", obj, vars))
1795 default_prepare_directory = strdup(lisp_string(vars[0]));
1796 else if (lisp_match_string("(prepare-dimensions #?(integer) #?(integer))", obj, vars))
1797 {
1798 default_prepare_width = lisp_integer(vars[0]);
1799 default_prepare_height = lisp_integer(vars[1]);
1800 }
1801 else if (lisp_match_string("(library-directory #?(string))", obj, vars))
1802 default_library_directories = string_list_prepend_copy(default_library_directories,
1803 lisp_string(vars[0]));
1804 else if (lisp_match_string("(small-image-dimensions #?(integer) #?(integer))", obj, vars))
1805 {
1806 default_small_width = lisp_integer(vars[0]);
1807 default_small_height = lisp_integer(vars[1]);
1808 }
1809 else if (lisp_match_string("(yiq-weights #?(number) #?(number) #?(number))", obj, vars))
1810 {
1811 int i;
1812
1813 for (i = 0; i < 3; ++i)
1814 default_weight_factors[i] = lisp_real(vars[i]);
1815 }
1816 else if (lisp_match_string("(metric #?(or wavelet subpixel))", obj, vars))
1817 {
1818 if (strcmp(lisp_symbol(vars[0]), "wavelet") == 0)
1819 default_metric = METRIC_WAVELET;
1820 else
1821 default_metric = METRIC_SUBPIXEL;
1822 }
1823 else if (lisp_match_string("(search-method #?(or local global))", obj, vars))
1824 {
1825 if (strcmp(lisp_symbol(vars[0]), "local") == 0)
1826 default_search = SEARCH_LOCAL;
1827 else
1828 default_search = SEARCH_GLOBAL;
1829 }
1830 else if (lisp_match_string("(minimum-classic-distance #?(integer))", obj, vars))
1831 default_classic_min_distance = lisp_integer(vars[0]);
1832 else if (lisp_match_string("(minimum-collage-distance #?(integer))", obj, vars))
1833 default_collage_min_distance = lisp_integer(vars[0]);
1834 else if (lisp_match_string("(cheat-amount #?(integer))", obj, vars))
1835 default_cheat_amount = lisp_integer(vars[0]);
1836 else if (lisp_match_string("(forbid-reconstruction-distance #?(integer))", obj, vars))
1837 default_forbid_reconstruction_radius = lisp_integer(vars[0]);
1838 else
1839 {
1840 fprintf(stderr, "Warning: unknown rc file option ");
1841 lisp_dump(obj, stderr);
1842 fprintf(stderr, "\n");
1843 }
1844 }
1845 else if (type == LISP_TYPE_PARSE_ERROR)
1846 fprintf(stderr, "Error: parse error in rc file.\n");
1847
1848 lisp_free(obj);
1849
1850 if (type == LISP_TYPE_EOF || type == LISP_TYPE_PARSE_ERROR)
1851 break;
1852 }
1853
1854 lisp_stream_free_path(&stream);
1855 }
1856 }
1857
1858 free(filename);
1859 }
1860
1861 static void
usage(void)1862 usage (void)
1863 {
1864 printf("Usage:\n"
1865 " metapixel --version\n"
1866 " print out version number\n"
1867 " metapixel --help\n"
1868 " print this help text\n"
1869 " metapixel [option ...] --prepare <inimage> <outimage> <tablefile>\n"
1870 " calculate and output tables for <file>\n"
1871 " metapixel [option ...] --metapixel <in> <out>\n"
1872 " transform <in> to <out>\n"
1873 " metapixel [option ...] --batch <batchfile>\n"
1874 " perform all the tasks in <batchfile>\n"
1875 "Options:\n"
1876 " -l, --library=DIR add the library in DIR\n"
1877 " -x, --antimosaic=PIC use PIC as an antimosaic\n"
1878 " -w, --width=WIDTH set width for small images\n"
1879 " -h, --height=HEIGHT set height for small images\n"
1880 " -y, --y-weight=WEIGHT assign relative weight for the Y-channel\n"
1881 " -i, --i-weight=WEIGHT assign relative weight for the I-channel\n"
1882 " -q, --q-weight=WEIGHT assign relative weight for the Q-channel\n"
1883 " -s --scale=SCALE scale input image by specified factor\n"
1884 " -m, --metric=METRIC choose metric (subpixel or wavelet)\n"
1885 " -e, --search=SEARCH choose search method (local or global)\n"
1886 " -c, --collage collage mode\n"
1887 " -d, --distance=DIST minimum distance between two instances of\n"
1888 " the same constituent image\n"
1889 " -a, --cheat=PERC cheat with specified percentage\n"
1890 " -f, --forbid-reconstruction=DIST\n"
1891 " forbid placing antimosaic images on their\n"
1892 " original locations or locations around it\n"
1893 " --out=FILE write protocol to file\n"
1894 " --in=FILE read protocol from file and use it\n"
1895 "\n"
1896 "Report bugs and suggestions to schani@complang.tuwien.ac.at\n");
1897 }
1898
1899 #define OPT_VERSION 256
1900 #define OPT_HELP 257
1901 #define OPT_PREPARE 258
1902 #define OPT_METAPIXEL 259
1903 #define OPT_BATCH 260
1904 #define OPT_OUT 261
1905 #define OPT_IN 262
1906 #define OPT_BENCHMARK_RENDERING 263
1907 #define OPT_PRINT_PREPARE_SETTINGS 264
1908
1909 #define MODE_NONE 0
1910 #define MODE_PREPARE 1
1911 #define MODE_METAPIXEL 2
1912 #define MODE_BATCH 3
1913
1914 int
main(int argc,char * argv[])1915 main (int argc, char *argv[])
1916 {
1917 int mode = MODE_NONE;
1918 int metric;
1919 int search;
1920 int collage = 0;
1921 int classic_min_distance, collage_min_distance;
1922 int cheat = 0;
1923 float scale = 1.0;
1924 char *out_filename = 0;
1925 char *in_filename = 0;
1926 char *antimosaic_filename = 0;
1927 string_list_t *library_directories = 0;
1928 int prepare_width = 0, prepare_height = 0;
1929
1930 read_rc_file();
1931
1932 small_width = default_small_width;
1933 small_height = default_small_height;
1934 prepare_width = default_prepare_width;
1935 prepare_height = default_prepare_height;
1936 memcpy(weight_factors, default_weight_factors, sizeof(weight_factors));
1937 metric = default_metric;
1938 search = default_search;
1939 classic_min_distance = default_classic_min_distance;
1940 collage_min_distance = default_collage_min_distance;
1941 cheat = default_cheat_amount;
1942 forbid_reconstruction_radius = default_forbid_reconstruction_radius + 1;
1943
1944 while (1)
1945 {
1946 static struct option long_options[] =
1947 {
1948 { "version", no_argument, 0, OPT_VERSION },
1949 { "help", no_argument, 0, OPT_HELP },
1950 { "prepare", no_argument, 0, OPT_PREPARE },
1951 { "metapixel", no_argument, 0, OPT_METAPIXEL },
1952 { "batch", no_argument, 0, OPT_BATCH },
1953 { "out", required_argument, 0, OPT_OUT },
1954 { "in", required_argument, 0, OPT_IN },
1955 { "benchmark-rendering", no_argument, 0, OPT_BENCHMARK_RENDERING },
1956 { "print-prepare-settings", no_argument, 0, OPT_PRINT_PREPARE_SETTINGS },
1957 { "library", required_argument, 0, 'l' },
1958 { "width", required_argument, 0, 'w' },
1959 { "height", required_argument, 0, 'h' },
1960 { "y-weight", required_argument, 0, 'y' },
1961 { "i-weight", required_argument, 0, 'i' },
1962 { "q-weight", required_argument, 0, 'q' },
1963 { "scale", required_argument, 0, 's' },
1964 { "collage", no_argument, 0, 'c' },
1965 { "distance", required_argument, 0, 'd' },
1966 { "cheat", required_argument, 0, 'a' },
1967 { "metric", required_argument, 0, 'm' },
1968 { "search", required_argument, 0, 'e' },
1969 { "antimosaic", required_argument, 0, 'x' },
1970 { "forbid-reconstruction", required_argument, 0, 'f' },
1971 { 0, 0, 0, 0 }
1972 };
1973
1974 int option, option_index;
1975
1976 option = getopt_long(argc, argv, "l:m:e:w:h:y:i:q:s:cd:a:x:f:", long_options, &option_index);
1977
1978 if (option == -1)
1979 break;
1980
1981 switch (option)
1982 {
1983 case OPT_PREPARE :
1984 mode = MODE_PREPARE;
1985 break;
1986
1987 case OPT_METAPIXEL :
1988 mode = MODE_METAPIXEL;
1989 break;
1990
1991 case OPT_BATCH :
1992 mode = MODE_BATCH;
1993 break;
1994
1995 case OPT_OUT :
1996 if (out_filename != 0)
1997 {
1998 fprintf(stderr, "the --out option can be used at most once\n");
1999 return 1;
2000 }
2001 out_filename = strdup(optarg);
2002 assert(out_filename != 0);
2003 break;
2004
2005 case OPT_IN :
2006 if (in_filename != 0)
2007 {
2008 fprintf(stderr, "the --in option can be used at most once\n");
2009 return 1;
2010 }
2011 in_filename = strdup(optarg);
2012 assert(in_filename != 0);
2013 break;
2014
2015 case OPT_BENCHMARK_RENDERING :
2016 benchmark_rendering = 1;
2017 break;
2018
2019 case OPT_PRINT_PREPARE_SETTINGS :
2020 printf("%d %d %s\n", default_prepare_width, default_prepare_height,
2021 default_prepare_directory != 0 ? default_prepare_directory : "");
2022 exit(0);
2023 break;
2024
2025 case 'm' :
2026 if (strcmp(optarg, "wavelet") == 0)
2027 metric = METRIC_WAVELET;
2028 else if (strcmp(optarg, "subpixel") == 0)
2029 metric = METRIC_SUBPIXEL;
2030 else
2031 {
2032 fprintf(stderr, "metric must either be subpixel or wavelet\n");
2033 return 1;
2034 }
2035 break;
2036
2037 case 'e' :
2038 if (strcmp(optarg, "local") == 0)
2039 search = SEARCH_LOCAL;
2040 else if (strcmp(optarg, "global") == 0)
2041 search = SEARCH_GLOBAL;
2042 else
2043 {
2044 fprintf(stderr, "search method must either be local or global\n");
2045 return 1;
2046 }
2047 break;
2048
2049 case 'w' :
2050 small_width = prepare_width = atoi(optarg);
2051 break;
2052
2053 case 'h' :
2054 small_height = prepare_height = atoi(optarg);
2055 break;
2056
2057 case 'y' :
2058 weight_factors[0] = atof(optarg);
2059 break;
2060
2061 case 'i' :
2062 weight_factors[1] = atof(optarg);
2063 break;
2064
2065 case 'q' :
2066 weight_factors[2] = atof(optarg);
2067 break;
2068
2069 case 's':
2070 scale = atof(optarg);
2071 break;
2072
2073 case 'c' :
2074 collage = 1;
2075 break;
2076
2077 case 'd' :
2078 classic_min_distance = collage_min_distance = atoi(optarg);
2079 break;
2080
2081 case 'a' :
2082 cheat = atoi(optarg);
2083 break;
2084
2085 case 'l' :
2086 if (antimosaic_filename != 0)
2087 {
2088 fprintf(stderr, "Error: --library and --antimosaic cannot be used together.\n");
2089 return 1;
2090 }
2091
2092 library_directories = string_list_prepend_copy(library_directories, optarg);
2093 break;
2094
2095 case 'x' :
2096 if (antimosaic_filename != 0)
2097 {
2098 fprintf(stderr, "Error: at most one antimosaic picture can be specified.\n");
2099 return 1;
2100 }
2101 else if (library_directories != 0)
2102 {
2103 fprintf(stderr, "Error: --library and --antimosaic cannot be used together.\n");
2104 return 1;
2105 }
2106 antimosaic_filename = strdup(optarg);
2107 break;
2108
2109 case 'f' :
2110 forbid_reconstruction_radius = atoi(optarg) + 1;
2111 break;
2112
2113 case OPT_VERSION :
2114 printf("metapixel " METAPIXEL_VERSION "\n"
2115 "\n"
2116 "Copyright (C) 1997-2006 Mark Probst\n"
2117 "\n"
2118 "This program is free software; you can redistribute it and/or modify\n"
2119 "it under the terms of the GNU General Public License as published by\n"
2120 "the Free Software Foundation; either version 2 of the License, or\n"
2121 "(at your option) any later version.\n"
2122 "\n"
2123 "This program is distributed in the hope that it will be useful,\n"
2124 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2125 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2126 "GNU General Public License for more details.\n"
2127 "\n"
2128 "You should have received a copy of the GNU General Public License\n"
2129 "along with this program; if not, write to the Free Software\n"
2130 "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
2131 exit(0);
2132
2133 case OPT_HELP :
2134 usage();
2135 return 0;
2136
2137 default :
2138 assert(0);
2139 }
2140 }
2141
2142 /* check settings for soundness */
2143 if (small_height <= 0)
2144 {
2145 fprintf(stderr, "Error: height of small images must be positive.\n");
2146 return 1;
2147 }
2148 if (small_width <= 0)
2149 {
2150 fprintf(stderr, "Error: width of small images must be positive.\n");
2151 return 1;
2152 }
2153 if (scale <= 0.0)
2154 {
2155 fprintf(stderr, "Error: scale factor must be positive.\n");
2156 return 1;
2157 }
2158 if (classic_min_distance < 0)
2159 {
2160 fprintf(stderr, "Error: classic minimum distance must be non-negative.\n");
2161 return 1;
2162 }
2163 if (collage_min_distance < 0)
2164 {
2165 fprintf(stderr, "Error: collage minimum distance must be non-negative.\n");
2166 return 1;
2167 }
2168 if (cheat < 0 || cheat > 100)
2169 {
2170 fprintf(stderr, "Error: cheat amount must be in the range from 0 to 100.\n");
2171 return 1;
2172 }
2173 /* the value in forbid_reconstruction_radius is always one more
2174 than the user specified */
2175 if (forbid_reconstruction_radius <= 0)
2176 {
2177 fprintf(stderr, "Error: forbid reconstruction distance must be non-negative.\n");
2178 return 1;
2179 }
2180
2181 if (in_filename != 0 || out_filename != 0)
2182 {
2183 if (mode != MODE_METAPIXEL)
2184 {
2185 fprintf(stderr, "the --in and --out options can only be used in metapixel mode\n");
2186 return 1;
2187 }
2188 if (collage)
2189 {
2190 fprintf(stderr, "the --in and --out options can only be used for classic mosaics\n");
2191 return 1;
2192 }
2193 }
2194
2195 sqrt_of_two = sqrt(2);
2196 sqrt_of_image_size = sqrt(IMAGE_SIZE);
2197
2198 compute_index_weights();
2199
2200 if (mode == MODE_PREPARE)
2201 {
2202 static coefficient_with_index_t highest_coeffs[NUM_COEFFS];
2203
2204 int i, channel;
2205 unsigned char *image_data;
2206 unsigned char *scaled_data;
2207 char *inimage_name, *outimage_name, *tables_name;
2208 FILE *tables_file;
2209 int in_width, in_height;
2210 metapixel_t pixel;
2211 lisp_object_t *obj;
2212
2213 if (argc - optind != 3)
2214 {
2215 usage();
2216 return 1;
2217 }
2218
2219 assert(prepare_width > 0 && prepare_height > 0);
2220
2221 inimage_name = argv[optind + 0];
2222 outimage_name = argv[optind + 1];
2223 tables_name = argv[optind + 2];
2224
2225 image_data = read_image(inimage_name, &in_width, &in_height);
2226
2227 if (image_data == 0)
2228 {
2229 fprintf(stderr, "could not read image `%s'\n", inimage_name);
2230 return 1;
2231 }
2232
2233 tables_file = fopen(tables_name, "ab");
2234 if (tables_file == 0)
2235 {
2236 fprintf(stderr, "could not open file `%s' for writing\n", tables_name);
2237 return 1;
2238 }
2239
2240 /* generate small image */
2241 scaled_data = scale_image(image_data, in_width, in_height, 0, 0,
2242 in_width, in_height, prepare_width, prepare_height);
2243 assert(scaled_data != 0);
2244
2245 write_image(outimage_name, prepare_width, prepare_height, scaled_data, 3, prepare_width * 3, IMAGE_FORMAT_PNG);
2246
2247 generate_metapixel_coefficients(&pixel, scaled_data, highest_coeffs);
2248
2249 free(scaled_data);
2250
2251 fprintf(tables_file, "(small-image ");
2252 obj = lisp_make_string(strip_path(outimage_name));
2253 lisp_dump(obj, tables_file);
2254 lisp_free(obj);
2255
2256 fprintf(tables_file, " (size %d %d) (wavelet (means %f %f %f) (coeffs",
2257 prepare_width, prepare_height,
2258 pixel.means[0], pixel.means[1], pixel.means[2]);
2259 for (i = 0; i < NUM_COEFFS; ++i)
2260 fprintf(tables_file, " %d", highest_coeffs[i].index);
2261
2262 fprintf(tables_file, ")) (subpixel");
2263 for (channel = 0; channel < NUM_CHANNELS; ++channel)
2264 {
2265 static char *channel_names[] = { "y", "i", "q" };
2266
2267 fprintf(tables_file, " (%s", channel_names[channel]);
2268 for (i = 0; i < NUM_SUBPIXELS; ++i)
2269 fprintf(tables_file, " %d", (int)pixel.subpixels[channel * NUM_SUBPIXELS + i]);
2270 fprintf(tables_file, ")");
2271 }
2272 fprintf(tables_file, "))\n");
2273
2274 fclose(tables_file);
2275 }
2276 else if (mode == MODE_METAPIXEL
2277 || mode == MODE_BATCH)
2278 {
2279 if ((mode == MODE_METAPIXEL && argc - optind != 2)
2280 || (mode == MODE_BATCH && argc - optind != 1))
2281 {
2282 usage();
2283 return 1;
2284 }
2285
2286 if (antimosaic_filename == 0 && library_directories == 0)
2287 library_directories = default_library_directories;
2288
2289 if (antimosaic_filename != 0)
2290 {
2291 classic_reader_t *reader = init_classic_reader(antimosaic_filename, scale);
2292 int x, y;
2293
2294 for (y = 0; y < reader->metaheight; ++y)
2295 {
2296 read_classic_row(reader);
2297
2298 for (x = 0; x < reader->metawidth; ++x)
2299 {
2300 static coefficient_with_index_t highest_coeffs[NUM_COEFFS];
2301
2302 unsigned char *scaled_data;
2303 metapixel_t *pixel = new_metapixel();
2304 int left_x, width;
2305
2306 compute_classic_column_coords(reader, x, &left_x, &width);
2307 scaled_data = scale_image(reader->in_image_data, reader->in_image_width, reader->num_lines,
2308 left_x, 0, width, reader->num_lines, small_width, small_height);
2309 assert(scaled_data != 0);
2310
2311 generate_metapixel_coefficients(pixel, scaled_data, highest_coeffs);
2312
2313 pixel->data = scaled_data;
2314 pixel->width = small_width;
2315 pixel->height = small_height;
2316 pixel->anti_x = x;
2317 pixel->anti_y = y;
2318 pixel->collage_positions = 0;
2319
2320 pixel->filename = (char*)malloc(64);
2321 sprintf(pixel->filename, "(%d,%d)", x, y);
2322
2323 add_metapixel(pixel);
2324
2325 printf(":");
2326 fflush(stdout);
2327 }
2328 }
2329
2330 printf("\n");
2331
2332 free_classic_reader(reader);
2333 }
2334 else if (library_directories != 0)
2335 {
2336 string_list_t *lst;
2337
2338 for (lst = library_directories; lst != 0; lst = lst->next)
2339 if (!read_tables(lst->str))
2340 {
2341 fprintf(stderr, "Error: cannot read library table `%s/%s'.\n", lst->str, TABLES_FILENAME);
2342 return 1;
2343 }
2344
2345 forbid_reconstruction_radius = 0;
2346 }
2347 else
2348 {
2349 fprintf(stderr, "Error: you must give one of the option --library and --antimosaic.\n");
2350 return 1;
2351 }
2352
2353 if (mode == MODE_METAPIXEL)
2354 {
2355 if (collage)
2356 generate_collage(argv[optind], argv[optind + 1], scale, collage_min_distance,
2357 metric, cheat);
2358 else
2359 make_classic_mosaic(argv[optind], argv[optind + 1],
2360 metric, scale, search, classic_min_distance, cheat,
2361 in_filename, out_filename);
2362 }
2363 else if (mode == MODE_BATCH)
2364 {
2365 FILE *in = fopen(argv[optind], "rb");
2366 lisp_stream_t stream;
2367
2368 if (in == 0)
2369 {
2370 fprintf(stderr, "cannot open batch file `%s': %s\n", argv[optind], strerror(errno));
2371 return 1;
2372 }
2373
2374 lisp_stream_init_file(&stream, in);
2375
2376 for (;;)
2377 {
2378 lisp_object_t *obj = lisp_read(&stream);
2379 int type = lisp_type(obj);
2380
2381 if (type != LISP_TYPE_EOF && type != LISP_TYPE_PARSE_ERROR)
2382 {
2383 lisp_object_t *vars[4];
2384
2385 if (lisp_match_string("(classic (#?(or image protocol) #?(string)) #?(string) . #?(list))",
2386 obj, vars))
2387 {
2388 float this_scale = scale;
2389 int this_search = search;
2390 int this_min_distance = classic_min_distance;
2391 int this_cheat = cheat;
2392 int this_metric = metric;
2393 char *this_prot_in_filename = in_filename;
2394 char *this_prot_out_filename = out_filename;
2395 char *this_image_out_filename = lisp_string(vars[2]);
2396 char *this_image_in_filename = 0;
2397 lisp_object_t *lst;
2398 lisp_object_t *var;
2399
2400 if (strcmp(lisp_symbol(vars[0]), "image") == 0)
2401 this_image_in_filename = lisp_string(vars[1]);
2402 else
2403 this_prot_in_filename = lisp_string(vars[1]);
2404
2405 for (lst = vars[3]; lisp_type(lst) != LISP_TYPE_NIL; lst = lisp_cdr(lst))
2406 {
2407 if (lisp_match_string("(scale #?(real))",
2408 lisp_car(lst), &var))
2409 {
2410 float val = lisp_real(var);
2411
2412 if (val <= 0.0)
2413 fprintf(stderr, "scale must be larger than 0\n");
2414 else
2415 this_scale = val;
2416 }
2417 else if (lisp_match_string("(search #?(or local global))",
2418 lisp_car(lst), &var))
2419 {
2420 if (strcmp(lisp_symbol(var), "local") == 0)
2421 this_search = SEARCH_LOCAL;
2422 else
2423 this_search = SEARCH_GLOBAL;
2424 }
2425 else if (lisp_match_string("(min-distance #?(integer))",
2426 lisp_car(lst), &var))
2427 {
2428 int val = lisp_integer(var);
2429
2430 if (val < 0)
2431 fprintf(stderr, "min-distance cannot be negative\n");
2432 else
2433 this_min_distance = val;
2434 }
2435 else if (lisp_match_string("(cheat #?(integer))",
2436 lisp_car(lst), &var))
2437 {
2438 int val = lisp_integer(var);
2439
2440 if (val < 0 || val > 100)
2441 fprintf(stderr, "cheat must be between 0 and 100, inclusively\n");
2442 else
2443 this_cheat = val;
2444
2445 }
2446 else if (lisp_match_string("(metric #?(or subpixel wavelet))",
2447 lisp_car(lst), &var))
2448 {
2449 if (strcmp(lisp_symbol(var), "subpixel") == 0)
2450 this_metric = METRIC_SUBPIXEL;
2451 else
2452 this_metric = METRIC_WAVELET;
2453 }
2454 else if (lisp_match_string("(protocol #?(string))",
2455 lisp_car(lst), &var))
2456 this_prot_out_filename = lisp_string(var);
2457 else
2458 {
2459 fprintf(stderr, "unknown expression ");
2460 lisp_dump(lisp_car(lst), stderr);
2461 fprintf(stderr, "\n");
2462 }
2463 }
2464
2465 make_classic_mosaic(this_image_in_filename, this_image_out_filename,
2466 this_metric, this_scale, this_search, this_min_distance, this_cheat,
2467 this_prot_in_filename, this_prot_out_filename);
2468 }
2469 else
2470 {
2471 fprintf(stderr, "unknown expression ");
2472 lisp_dump(obj, stderr);
2473 fprintf(stderr, "\n");
2474 }
2475 }
2476 else if (type == LISP_TYPE_PARSE_ERROR)
2477 fprintf(stderr, "parse error in batch file\n");
2478 lisp_free(obj);
2479
2480 if (type == LISP_TYPE_EOF)
2481 break;
2482 }
2483 }
2484 else
2485 assert(0);
2486 }
2487 else
2488 {
2489 usage();
2490 return 1;
2491 }
2492
2493 return 0;
2494 }
2495