1 /*
2 A texture synthesizing engine for bitmapped images.
3
4 The algorithm is due to Paul Harrison and others.
5
6 Copyright (C) 2010, 2011 Lloyd Konneker
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 /*
24 Inner engine.
25 Parameters include target and corpus pixmaps.
26 Pixmaps have internal pixel format, which includes mask, color, alpha, and map.
27 (where map means an additional e.g. grayscale value for mapping corpus to target.)
28 Target and corpus pixmaps have the same pixel format.
29 (An adapter can relax the restriction that both have the same format,
30 by adding e.g. an alpha channel to one.)
31 */
32
33 /*
34 Notes:
35
36 The selection:
37
38 A caller of the engine may be an application supporting "selection."
39 Then a caller should adapt the selection mask to separate masks for the target and corpus.
40 Generally, in such a case, the masks should generally be mutually exclusive,
41 especially regarding partial selection.
42 But this is not a concern of the engine.
43
44 The alpha:
45
46 In prior versions the alpha was treated like a color channel, and matched during synthesis.
47 Transparent pixels (which Gimp arbitrarily gives the color black in some circumstances)
48 were not distinguished. In certain cases with transparency, transparent pixels were synthesized
49 into the target, as good matches for black.
50
51 Here, we don't match the alpha channel between target and corpus.
52 We don't generate any alpha in the target, instead we leave the target alpha unaltered.
53 We use the alpha to determine what pixels are in the target and corpus,
54 (similar to a selection mask.)
55 Any totally transparent pixel in the target selection IS synthesized,
56 I.E. a color is generated (but since it is totally transparent, you don't see it.)
57 Any partially transparent target pixel is also synthesized, except as stated,
58 the alpha is not matched (so colors from opaque areas of the corpus
59 could be synthesized into partially transparent areas of the target.)
60 Any totally transparent pixel in the corpus is not in the corpus, i.e. never matched.
61 Any partially transparent pixel in the corpus is a candidate for matching.
62 A color from a partially transparent pixel in the corpus could be synthesized
63 into an opaque area of the target.
64 Again, the transparency of the target is retained even as new colors are synthesized.
65
66 Tiling: (see parameters horizontal and vertical tiling)
67 This means we synthesize a target that is *seamlessly* tileable.
68 We treat the target as a sphere, wrapping a coord outside the target around
69 to the opposite side. See wrapOrClipTarget.
70 It doesn't make tiles in the target, it makes a target that is suitable as a tile.
71 */
72
73 // Compiling switch #defines
74 #include "buildSwitches.h"
75
76 #include <math.h>
77
78 #ifdef SYNTH_USE_GLIB
79 #include "../config.h" // GNU buildtools local configuration
80 // Use glib via gimp.h
81 // #include <libgimp/gimp.h>
82 #include <glib.h>
83 #endif
84
85
86 #ifdef USE_GLIB_PROXY
87 #include <stddef.h> // size_t
88 #include "glibProxy.h" // Redefines the glib structs and routines used here
89 #include <math.h> // atan2(), log()
90 /*
91 More proxy. Redefine GRand routines
92 On platform Linux, used Glib g_rand
93 On platform OSX (when using stdc but not Glib), proxy calls stdc rand()
94 */
95 #define g_rand_new_with_seed(s) s_rand_new_with_seed(s)
96 #define g_rand_int_range(r,u,l) s_rand_int_range(r,u,l)
97 #endif
98
99 /* Shared with resynth-gui, engine plugin, and engine */
100 #include "imageSynthConstants.h"
101
102 // True header files
103 #include "imageFormat.h"
104 #include "imageFormatIndicies.h"
105
106 #include "map.h"
107 #include "engineParams.h"
108 #include "engine.h"
109
110 /*
111 Source not compiled separately. Is separate to reduce file sizes and coupling.
112 Also, some functions are inlined.
113 */
114
115 #include "engineTypes.h"
116 #include "mapIndex.h" // inlined, used in innermost loop
117 #include "mapOps.h" // definitions for map.h
118 #include "matchWeighting.h"
119 #include "orderTarget.h"
120
121
122 #ifdef STATS
123 /* For development */
124 guint countSourceTries = 0;
125 guint countTargetTries = 0;
126 guint total_targets = 0; /* Total target attempts over all passes, barring short circuit. */
127
128 // remember the most recent kind of corpus point that bettered the previous best
129 guint bettermentStats[MAX_BETTERMENT_KIND];
130 #endif
131
132
133 /*
134 Class hasValue
135
136 Whether a pixel in the image is ready to be matched.
137 Value more or less means a color; not an undefined color.
138 Pixels in the context: if they are not clipped, not transparent, etc.
139 Pixels in the target: if they have been synthesized.
140
141 TODO
142 Alternate way of computing hasValue from targetMask, alpha channel, and whether synthesized (has_source.)
143 Might use less memory and have better locality.
144 But hasValue is only called in prepare_neighbors, not as costly as rest of search.
145
146 TODO hasValue array is larger than it needs to be?
147 It could it be just the size of the target plus a band, since it is only used for neighbors.
148 Would require different wrapOrClipTarget().
149 Might affect performance of cache or memory swapping
150 */
151
152 static inline void
setHasValue(Coordinates * coords,guchar value,Map * hasValueMap)153 setHasValue( Coordinates *coords, guchar value, Map* hasValueMap)
154 {
155 *bytemap_index(hasValueMap, *coords) = value;
156 }
157
158 static inline gboolean
getHasValue(Coordinates coords,Map * hasValueMap)159 getHasValue(Coordinates coords, Map* hasValueMap)
160 {
161 return (* bytemap_index(hasValueMap, coords));
162 }
163
164 static inline void
prepareHasValue(Map * targetMap,Map * hasValueMap)165 prepareHasValue(Map* targetMap, Map* hasValueMap)
166 {
167 new_bytemap(hasValueMap, targetMap->width, targetMap->height);
168 }
169
170
171 /*
172 Class sourceOfMap
173
174 Whether a target pixel has a source in the corpus (from synthesis).
175 TODO Possibly we can use index into corpusPoints instead of coordinates.
176 TODO The map only needs to be the size of the target?
177 But we are calling getSourceOf(neighbor_point), which can be points outside
178 of the target (context), whose source is always themselves.
179 However, the extra memory is probably not a resource problem,
180 and probably not a performance problem because it is only used in prepare_neighbors,
181 the source are copied to a dense structure neighbor_sources for the inner search.
182 */
183
184
185 static inline void
setSourceOf(Coordinates target_point,Coordinates source_corpus_point,Map * sourceOfMap)186 setSourceOf (
187 Coordinates target_point,
188 Coordinates source_corpus_point,
189 Map* sourceOfMap
190 )
191 {
192 *coordmap_index(sourceOfMap, target_point) = source_corpus_point;
193 }
194
195
196 static inline Coordinates
getSourceOf(Coordinates target_point,Map * sourceOfMap)197 getSourceOf (
198 Coordinates target_point,
199 Map* sourceOfMap
200 )
201 {
202 return *coordmap_index(sourceOfMap, target_point);
203 }
204
205
206 /* Initially, no target points have source in corpus, i.e. none synthesized. */
207 static void
prepare_target_sources(Map * targetMap,Map * sourceOfMap)208 prepare_target_sources(
209 Map* targetMap,
210 Map* sourceOfMap)
211 {
212 guint x;
213 guint y;
214 Coordinates null_coords = {-1, -1};
215
216 new_coordmap(sourceOfMap, targetMap->width, targetMap->height);
217
218 for(y=0; y<targetMap->height; y++)
219 for(x=0; x<targetMap->width; x++)
220 {
221 Coordinates coords = {x,y};
222 setSourceOf(coords, null_coords, sourceOfMap);
223 }
224 }
225
226 static inline gboolean
has_source(Coordinates target_point,Map * sourceOfMap)227 has_source (
228 Coordinates target_point,
229 Map* sourceOfMap
230 )
231 {
232 return (getSourceOf(target_point, sourceOfMap).x != -1) ;
233 }
234
235
236
237
238 /*
239 Is the pixel selected in the corpus?
240 !!! Note dithered, partial selection: only one value is totally unselected or selected.
241 Here, only pixels fully selected return True.
242 This is because when target/corpus are differentiated by the same selection,
243 partially selected will be in the target,
244 only fully selected (the inverse) will be the corpus.
245 !!! Note this is called from the bottleneck.
246 */
247 static inline gboolean
isSelectedCorpus(const Coordinates coords,const Map * const corpusMap)248 isSelectedCorpus (
249 const Coordinates coords,
250 const Map* const corpusMap
251 )
252 {
253 /*
254 Was: != MASK_UNSELECTED); i.e. partially selected was included.
255 Now: if partially selected, excluded from corpus.
256 */
257 return (pixmap_index(corpusMap, coords)[MASK_PIXELEL_INDEX] == MASK_TOTALLY_SELECTED);
258 }
259
260
261 /*
262 Is the pixel selected in the image?
263 The selection is the mask, created by user to distinguish.
264 In the target map, distinguishes target(what is synthesized) from context.
265 In the corpus map, distinguishes undesired corpus from desired corpus.
266 */
267 static inline gboolean
isSelectedTarget(Coordinates coords,Map * imageMap)268 isSelectedTarget(
269 Coordinates coords,
270 Map * imageMap )
271 {
272 return (pixmap_index(imageMap, coords)[MASK_PIXELEL_INDEX] != MASK_UNSELECTED);
273 }
274
275
276 /*
277 Return whether this pixel has any opacity.
278 If it has some opacity (not totally transparent) than it contributes to the visible.
279 Our strategy is to synthesize target pixels with any opacity,
280 and use context pixels with any opacity.
281 */
282 static inline gboolean
not_transparent_image(Coordinates coords,TFormatIndices * indices,Map * targetMap)283 not_transparent_image(
284 Coordinates coords,
285 TFormatIndices* indices,
286 Map * targetMap
287 )
288 {
289 return ( indices->isAlphaTarget ? pixmap_index(targetMap, coords)[indices->alpha_bip] != ALPHA_TOTAL_TRANSPARENCY : TRUE);
290 }
291
292 static inline gboolean
not_transparent_corpus(Coordinates coords,TFormatIndices * indices,Map * corpusMap)293 not_transparent_corpus(
294 Coordinates coords,
295 TFormatIndices* indices,
296 Map* corpusMap
297 )
298 {
299 return ( indices->isAlphaSource ? pixmap_index(corpusMap, coords)[indices->alpha_bip] != ALPHA_TOTAL_TRANSPARENCY : TRUE);
300 }
301
302
303 /* Included here because it depends on some routines above. */
304 // If STATS is not defined, it redefines stat function calls to nil
305 #include "stats.h"
306
307
308 /*
309 Array of index of most recent target point that probed this corpus point
310 (recentProberMap[corpus x,y] = target)
311 !!! Larger than necessary if the corpus has holes in it. TODO very minor.
312 !!! Note recentProberMap is unsigned, -1 == 0xFFFFFF should not match any target index.
313 */
314 static void
prepareRecentProber(Map * corpusMap,Map * recentProberMap)315 prepareRecentProber(Map* corpusMap, Map* recentProberMap)
316 {
317 guint x;
318 guint y;
319
320 new_intmap(recentProberMap, corpusMap->width, corpusMap->height);
321 for(y=0; y< (guint) corpusMap->height; y++)
322 for(x=0; x< (guint) corpusMap->width; x++)
323 {
324 Coordinates coords = {x,y};
325 *intmap_index(recentProberMap, coords) = -1;
326 }
327 }
328
329
330 /*
331 Prepare target AND initialize hasValueMap.
332 This is misnamed and is really two concerns: the target (what is synthesized)
333 and the context (the surroundings.)
334 Both come from the target image. But the *target* is not *target image*.
335 Prepare a vector of target points.
336 Initialize hasValueMap for all target points.
337 */
338 static void
prepareTargetPoints(gboolean is_use_context,TFormatIndices * indices,Map * targetMap,Map * hasValueMap,pointVector * targetPoints)339 prepareTargetPoints(
340 gboolean is_use_context,
341 TFormatIndices* indices,
342 Map* targetMap,
343 Map* hasValueMap,
344 pointVector* targetPoints
345 )
346 {
347 guint x;
348 guint y;
349
350 /* Count selected pixels in the image, for sizing a vector */
351 guint size = 0;
352 for(y=0; y<targetMap->height; y++)
353 for(x=0; x<targetMap->width; x++)
354 {
355 Coordinates coords = {x,y};
356 if (isSelectedTarget(coords, targetMap))
357 size++;
358 }
359
360 *targetPoints = g_array_sized_new (FALSE, TRUE, sizeof(Coordinates), size); /* reserve */
361
362 prepareHasValue(targetMap, hasValueMap); /* reserve, initialize to value: unknown */
363
364 for(y=0; y<targetMap->height; y++)
365 for(x=0; x<targetMap->width; x++)
366 {
367 Coordinates coords = {x,y};
368
369 /*
370 Remember whether use this image point for matching target neighbors.
371 Initially, no target points have value, and some context points will have value.
372 Later, synthesized target points will have values also.
373 */
374 setHasValue(&coords,
375 (
376 is_use_context // ie use_border ie match image neighbors outside the selection (the context)
377 && ! isSelectedTarget(coords, targetMap) // outside the target
378 /* !!! and if the point is not transparent (e.g. background layer) which is arbitrarily black !!! */
379 && not_transparent_image(coords, indices, targetMap)
380 ),
381 hasValueMap);
382
383 /*
384 Make vector targetPoints
385 !!! Note we do NOT exclude transparent. Will synthesize color (but not alpha)
386 for all selected pixels in target, regardless of transparency.
387 */
388 if (isSelectedTarget(coords, targetMap))
389 g_array_append_val(*targetPoints, coords);
390 }
391 }
392
393
394
395
396 /*
397 Scan corpus pixmap for selected && nottransparent pixels, create vector of coords.
398 Used to sample corpus.
399 */
400 void
prepareCorpusPoints(TFormatIndices * indices,Map * corpusMap,pointVector * corpusPoints)401 prepareCorpusPoints (
402 TFormatIndices* indices,
403 Map* corpusMap,
404 pointVector* corpusPoints
405 )
406 {
407 /* Reserve size of pixmap, but excess, includes unselected. */
408 *corpusPoints = g_array_sized_new (FALSE, TRUE, sizeof(Coordinates),
409 corpusMap->height*corpusMap->width);
410
411 {
412 guint x;
413 guint y;
414
415 for(y=0; y<corpusMap->height; y++)
416 for(x=0; x<corpusMap->width; x++)
417 {
418 Coordinates coords = {x, y};
419 /* In prior versions, the user's mask was inverted to establish the corpus,
420 I.E. this was "not is_selected"
421 */
422 if (isSelectedCorpus(coords, corpusMap)
423 && not_transparent_corpus(coords, indices, corpusMap) /* Exclude transparent from corpus */
424 )
425 {
426 g_array_append_val(*corpusPoints, coords);
427 }
428 }
429 }
430 // Size is checked by caller.
431 }
432
433
434 static inline Coordinates
randomCorpusPoint(pointVector corpusPoints,GRand * prng)435 randomCorpusPoint (
436 pointVector corpusPoints,
437 GRand * prng
438 )
439 {
440 /* Was rand()%corpusPoints_size but thats not uniform. */
441 gint index = g_rand_int_range(prng, 0, corpusPoints->len);
442 return g_array_index(corpusPoints, Coordinates, index);
443 }
444
445
446
447
448 /*
449 Vector of offsets to surrounding points of a point, i.e. to a patch around a point.
450 Used as candidates to compute neighbors vector (nearby points that are selected and with values.)
451 Which is used in two places: 1) neighbor heuristic 2) try_point.
452
453 Sorted ascending on distance from (0,0) (see the < operator for class Coordinates).
454
455 !!! Note that offset 0,0 included, is the first element in sorted vector.
456 That makes a point it's own neighbor, i.e. part of the patch for (surrounding) a point.
457
458 Spans twice the min of corpus and image (target).
459 Why? So from one corner, the offsets will reach fully across.
460
461 TODO, for uncropping, where the target surrounds the corpus,
462 this might be vastly many more offsets than are needed for good synthesis.
463 But at worst, if not used they get paged out from virtual memory.
464 */
465 static void
prepareSortedOffsets(Map * targetMap,Map * corpusMap,pointVector * sortedOffsets)466 prepareSortedOffsets(
467 Map* targetMap,
468 Map* corpusMap,
469 pointVector* sortedOffsets
470 )
471 {
472 // Minimum(). Use smaller dimension of corpus and target.
473 gint width = (corpusMap->width < targetMap->width ? corpusMap->width : targetMap->width);
474 gint height = (corpusMap->height < targetMap->height ? corpusMap->height : targetMap->height);
475 guint allocatedSize = (2*width-1)*(2*height-1); // eg for width==3, [-2,-1,0,1,2], size==5
476
477 *sortedOffsets = g_array_sized_new (FALSE, TRUE, sizeof(Coordinates), allocatedSize); //Reserve
478
479 {
480 gint x; // !!! Signed offsets
481 gint y;
482
483 for(y=-height+1; y<height; y++)
484 for(x=-width+1; x<width; x++)
485 {
486 Coordinates coords = {x,y};
487 g_array_append_val(*sortedOffsets, coords);
488 }
489 }
490 g_assert((*sortedOffsets)->len == allocatedSize); // Completely filled
491 g_array_sort(*sortedOffsets, (gint (*)(const void*, const void*)) lessCartesian);
492
493 /* lkk An experiment to sort the offsets in row major order for better memory
494 locality didn't help performance.
495 Apparently the cpu cache holds many rows of the corpus.
496 */
497 }
498
499
500 /*
501 Return True if point is clipped or masked (not selected) in the corpus.
502 Point created by coordinate arithmetic, and can be negative or clipped.
503 !!! Note this is called in the bottleneck of try_point, crucial to speed.
504 */
505 static inline gboolean
clippedOrMaskedCorpus(const Coordinates point,const Map * const corpusMap)506 clippedOrMaskedCorpus(
507 const Coordinates point,
508 const Map * const corpusMap)
509 {
510 return (
511 point.x < 0
512 || point.y < 0
513 || point.x >= (gint) corpusMap->width
514 || point.y >= (gint) corpusMap->height /* Clipped */
515 || ! isSelectedCorpus(point, corpusMap) /* Masked */
516 );
517 }
518
519
520 // Included source (function declarations, not just definitions.)
521 // Descending levels of the engine
522 // imageSynth()->engine()->refiner()->synthesize
523 #include "passes.h"
524 #include "progress.h"
525 #include "synthesize.h"
526 // Both files define the same function refiner()
527 #ifdef SYNTH_THREADED
528 #include "refinerThreaded.h"
529 #else
530 #include "refiner.h"
531 #endif
532
533 /*
534 The engine.
535 Independent of platform, calling app, and graphics libraries.
536 This is mostly preparation: real work done by refiner() and synthesize().
537 */
538
539 int
engine(TImageSynthParameters parameters,TFormatIndices * indices,Map * targetMap,Map * corpusMap,void (* progressCallback)(int,void *),void * contextInfo,int * cancelFlag)540 engine(
541 TImageSynthParameters parameters,
542 TFormatIndices* indices,
543 Map* targetMap,
544 Map* corpusMap,
545 void (*progressCallback)(int, void*),
546 void *contextInfo,
547 int *cancelFlag
548 )
549 {
550 // Engine private data. On stack (and heap), not global, so engine is reentrant.
551
552 /*
553 A map on the corpus yielding indexes of target points.
554 For a point in the corpus, which target point (index!) most recently probed the corpus point.
555 recentProbe[coords corpus point] -> index of target_point that most recently probed corpus point
556 Heuristic#2.
557
558 2-D array of int, addressable by Coordinates.
559 */
560 Map recentProberMap;
561
562 /*
563 Flags for state of synthesis of image pixels.
564
565 Does source pixel have value yet, to match (depends on selection and state of algorithm.)
566 Map over entire target image (target selection and context.)
567 */
568 Map hasValueMap;
569
570 /*
571 Does this target pixel have a source yet: yields corpus coords.
572 (-1,-1) indicates no source.
573 */
574 Map sourceOfMap;
575
576 /*
577 1-D array (vector) of Coordinates.
578 Subsets of image and corpus, subsetted by selection and alpha.
579 */
580 pointVector targetPoints; // For synthesizing target in an order (ie random)
581 pointVector corpusPoints; // For sampling corpus randomly.
582 pointVector sortedOffsets; // offsets (signed coordinates) for finding neighbors.
583
584 GRand *prng; // pseudo random number generator
585
586 // Arrays, lookup tables for quantized functions
587 TPixelelMetricFunc corpusTargetMetric;
588 TMapPixelelMetricFunc mapMetric;
589
590 // check parameters in range
591 if ( parameters.patchSize > IMAGE_SYNTH_MAX_NEIGHBORS)
592 return IMAGE_SYNTH_ERROR_PATCH_SIZE_EXCEEDED;
593
594 // target prep
595 prepareTargetPoints(parameters.matchContextType, indices, targetMap,
596 &hasValueMap,
597 &targetPoints);
598 #ifdef ANIMATE
599 clear_target_pixels(indices->color_end_bip); // For debugging, blacken so new colors sparkle
600 #endif
601 /*
602 Rare user error: no target selected (mask empty.)
603 This error NOT occur in GIMP if selection does not intersect, since then we use the whole drawable.
604 */
605 if ( !targetPoints->len )
606 {
607 g_array_free(targetPoints, TRUE);
608 free_map(&hasValueMap);
609 return IMAGE_SYNTH_ERROR_EMPTY_TARGET;
610 }
611 prepare_target_sources(targetMap, &sourceOfMap);
612
613
614 // source prep
615 prepareCorpusPoints(indices, corpusMap, &corpusPoints);
616 /*
617 Rare user error: all corpus pixels transparent or not selected (mask empty.) Which means we can't synthesize.
618 This error NOT occur in GIMP if selection does not intersect, since then we use the whole drawable.
619 */
620 if (!corpusPoints->len )
621 {
622 g_array_free(targetPoints, TRUE);
623 free_map(&hasValueMap);
624 free_map(&sourceOfMap);
625 g_array_free(corpusPoints, TRUE);
626 return IMAGE_SYNTH_ERROR_EMPTY_CORPUS;
627 }
628
629 // prep things not images
630 prepareSortedOffsets(targetMap, corpusMap, &sortedOffsets); // Depends on image size
631 quantizeMetricFuncs(
632 parameters.sensitivityToOutliers,
633 parameters.mapWeight,
634 corpusTargetMetric,
635 mapMetric
636 );
637
638 // Now we need a prng, before order_targetPoints
639 /* Originally: srand(time(0)); But then testing is non-repeatable.
640 TODO the seed should be a hash of the input or a user parameter.
641 Then it would be repeatable, but changeable by the user.
642 */
643 prng = g_rand_new_with_seed(1198472);
644
645 int error = orderTargetPoints(¶meters, targetPoints, prng);
646 // A programming error that we don't clean up.
647 if (error) return error;
648
649 prepareRecentProber(corpusMap, &recentProberMap); // Must follow prepare_corpus
650
651 // Preparations done, begin actual synthesis
652 print_processor_time();
653
654 // progress(_("Resynthesizer: synthesizing"));
655
656 refiner(
657 parameters,
658 indices,
659 targetMap,
660 corpusMap,
661 &recentProberMap,
662 &hasValueMap,
663 &sourceOfMap,
664 targetPoints,
665 corpusPoints,
666 sortedOffsets,
667 prng,
668 corpusTargetMetric,
669 mapMetric,
670 progressCallback,
671 contextInfo,
672 cancelFlag
673 );
674
675 // Free internal mallocs.
676 // Caller must free the IN pixmaps since the targetMap holds synthesis results
677 free_map(&recentProberMap);
678 free_map(&hasValueMap);
679 free_map(&sourceOfMap);
680
681 g_array_free(targetPoints, TRUE);
682 g_array_free(corpusPoints, TRUE);
683 g_array_free(sortedOffsets, TRUE);
684
685 #ifdef SYNTH_USE_GLIB
686 g_rand_free(prng);
687 #endif
688
689 return 0; // Success, even if canceled
690 }
691
692
693