1 /* Parse ".desc" files from mosaiced images to generate (x,y) offsets for
2  * every sub-image. Find all overlap stats and solve balancing with LMS.
3  * Regenerate mosaic, with balancing fixed.
4  *
5  * 1/12/93 JC
6  *	- first version, unfinished!
7  * 6/9/95 JC
8  *	- LMS fixed, now works, more or less
9  * 12/9/95 JC
10  *	- now does positions correctly too
11  *	- ignores trivial overlaps
12  * 19/9/95 JC
13  *	- prints correct number of balance factors!
14  * 10/11/95 JC
15  *	- now tracks im_copy() calls too, so you can save sub-images
16  * 12/1/96 JC
17  *	- slightly clearer diagnostics
18  *	- better centre of factors around 1.0 with log() average
19  * 1/3/96 JC
20  *	- new im_global_balance_float variant lets our caller adjust factor
21  *	  range if output has burn-out
22  *	- im_global_balance_search uses the above to produce scaled output ...
23  *	  very slow!
24  * 11/3/96 JC
25  *	- now tries current directory too for input files
26  * 22/3/96 JC
27  *	- horrible bug in position finding! now fixed
28  * 1/8/97 JC
29  *	- revised for new mosaic functions and non-square images
30  * 12/9/97 JC
31  *	- code for im_lrmosaic1() support
32  *	- output type == input type, so works for short images too
33  * 6/1/99 JC
34  *	- new gamma parameter, do scale in linear space
35  *	- removed _search version, as can now be done with ip
36  *	- renamed _float to f suffix, in line with im_conv()/im_convf()
37  * 15/2/00 JC
38  *	- balancef() did not scale in linear space
39  * 2/2/01 JC
40  *	- added tunable max blend width
41  * 7/11/01 JC
42  *	- global_balance.h broken out for im_remosaic()
43  * 25/02/02 JC
44  *	- better transform function scheme
45  * 21/3/01 JC
46  *	- quicker bailout on error
47  * 8/11/02 JC
48  * 	- add <> around file names so you can have spaces :(
49  * 9/12/02 JC
50  *	- track original params and always reuse them ... makes us proof
51  *	  against geo reconstruct errors
52  * 10/3/03 JC
53  *	- weed out overlaps which contain only transparent pixels
54  * 4/1/07
55  * 	- switch to new history thing, switch im_errormsg() too
56  * 24/1/11
57  * 	- gtk-doc
58  * 12/7/12
59  * 	- always allocate local to an output descriptor ... stops ref cycles
60  * 	  with the new base class
61  * 18/6/20 kleisauke
62  * 	- convert to vips8
63  */
64 
65 /*
66 
67     This file is part of VIPS.
68 
69     VIPS is free software; you can redistribute it and/or modify
70     it under the terms of the GNU Lesser General Public License as published by
71     the Free Software Foundation; either version 2 of the License, or
72     (at your option) any later version.
73 
74     This program is distributed in the hope that it will be useful,
75     but WITHOUT ANY WARRANTY; without even the implied warranty of
76     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
77     GNU Lesser General Public License for more details.
78 
79     You should have received a copy of the GNU Lesser General Public License
80     along with this program; if not, write to the Free Software
81     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
82     02110-1301  USA
83 
84  */
85 
86 /*
87 
88     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
89 
90  */
91 
92 /* Strategy: build a tree describing the file
93  * relationships in the desc file, then walk that passing constraints
94  * back up to the root. Look up file names in symbol_table.
95  */
96 
97 /* Define for debug output.
98 #define DEBUG
99  */
100 
101 #ifdef HAVE_CONFIG_H
102 #include <config.h>
103 #endif /*HAVE_CONFIG_H*/
104 #include <vips/intl.h>
105 
106 #include <stdio.h>
107 #include <stdlib.h>
108 #include <string.h>
109 #include <stdarg.h>
110 #include <math.h>
111 
112 #include <vips/vips.h>
113 #include <vips/transform.h>
114 #include <vips/internal.h>
115 
116 #include "pmosaicing.h"
117 #include "global_balance.h"
118 
119 #define MAX_ITEMS (50)
120 
121 /* How pix an overlap has to be (in pixels) before we think it's trivial and
122  * we ignore it.
123  */
124 #define TRIVIAL (20 * 20)
125 
126 /* Break a string into a list of strings. Write '\0's into the string. out
127  * needs to be MAX_FILES long. -1 for error, otherwise number of args found.
128 
129 	"<fred> <jim poop> <sn aff le>"
130 
131 	out[0] = "fred"
132 	out[1] = "jim poop"
133 	out[2] = "sn aff le"
134 
135  */
136 static int
break_items(char * line,char ** out)137 break_items( char *line, char **out )
138 {
139 	int i;
140 	char *p;
141 
142 	for( i = 0; i < MAX_ITEMS; i++ ) {
143 		/* Skip to first '<'.
144 		 */
145 		if( !(p = strchr( line, '<' )) )
146 			break;
147 
148 		out[i] = line = p + 1;
149 
150 		if( !(p = strchr( line, '>' )) ) {
151 			vips_error( "break_files", "%s", _( "no matching '>'" ) );
152 			return( -1 );
153 		}
154 
155 		*p = '\0';
156 		line = p + 1;
157 	}
158 
159 	if( i == MAX_ITEMS ) {
160 		vips_error( "break_files", "%s", _( "too many items" ) );
161 		return( -1 );
162 	}
163 
164 	return( i );
165 }
166 
167 /* Try to open a file. If full path fails, try the current directory.
168  */
169 VipsImage *
vips__global_open_image(SymbolTable * st,char * name)170 vips__global_open_image( SymbolTable *st, char *name )
171 {
172 	char *basename;
173 	VipsImage *image;
174 
175 	if( !(image = vips_image_new_from_file( name, NULL ))) {
176 		/* TODO(kleisauke): Is this behavior the same as im_skip_dir?
177 		 * i.e. could we open a filename which came
178 		 * from a win32 (`\\`) on a *nix machine?
179 		 */
180 		basename = g_path_get_basename( name );
181 
182 		if( !(image = vips_image_new_from_file( basename, NULL ))) {
183 			g_free( basename );
184 			return( NULL );
185 		}
186 
187 		g_free( basename );
188 	}
189 
190 	vips_object_local( st->im, image );
191 
192 	return( image );
193 }
194 
195 static void
junk_node(VipsImage * image,JoinNode * node)196 junk_node( VipsImage *image, JoinNode *node )
197 {
198 	VIPS_FREEF( g_slist_free, node->overlaps );
199 }
200 
201 /* Hash from a filename to an index into symbol_table.
202  */
203 static int
hash(char * n)204 hash( char *n )
205 {
206 	int i;
207 	int r = 0;
208 	int l = strlen( n );
209 
210 	for( i = 0; i < l; i++ )
211 		r = ((r + n[i]) * 43) & 0xffffff;
212 
213 	return( r % SYM_TAB_SIZE );
214 }
215 
216 /* Make a leaf for a file.
217  */
218 static JoinNode *
build_node(SymbolTable * st,char * name)219 build_node( SymbolTable *st, char *name )
220 {
221 	JoinNode *node = VIPS_NEW( st->im, JoinNode );
222 	int n = hash( name );
223 
224 	/* Fill fields.
225 	 */
226 	if( !node || !(node->name =
227 		vips_strdup( VIPS_OBJECT( st->im ), name )) )
228 		return( NULL );
229 
230 	node->type = JOIN_LEAF;
231 	node->dirty = 0;
232 	node->mwidth = -2;
233 	node->st = st;
234 	vips__transform_init( &node->cumtrn );
235 	node->trnim = NULL;
236 	node->arg1 = NULL;
237 	node->arg2 = NULL;
238 	node->overlaps = NULL;
239 	node->im = NULL;
240 	node->index = 0;
241 
242 	g_signal_connect( st->im, "close",
243 		G_CALLBACK( junk_node ), node );
244 
245 	/* Try to open.
246 	 */
247 	if( (node->im = vips__global_open_image( st, name )) ) {
248 		/* There is a file there - set width and height.
249 		 */
250 		node->cumtrn.oarea.width = node->im->Xsize;
251 		node->cumtrn.oarea.height = node->im->Ysize;
252 	}
253 	else {
254 		/* Clear the error buffer to lessen confusion.
255 		 */
256 		vips_error_clear();
257 	}
258 
259 	st->table[n] = g_slist_prepend( st->table[n], node );
260 
261 	return( node );
262 }
263 
264 /* Make a new overlap struct.
265  */
266 static OverlapInfo *
build_overlap(JoinNode * node,JoinNode * other,VipsRect * overlap)267 build_overlap( JoinNode *node, JoinNode *other, VipsRect *overlap )
268 {
269 	OverlapInfo *lap = VIPS_NEW( node->st->im, OverlapInfo );
270 
271 	if( !lap )
272 		return( NULL );
273 
274 	lap->node = node;
275 	lap->other = other;
276 	lap->overlap = *overlap;
277 	lap->nstats = NULL;
278 	lap->ostats = NULL;
279 	node->overlaps = g_slist_prepend( node->overlaps, lap );
280 	node->st->novl++;
281 
282 	return( lap );
283 }
284 
285 static void
overlap_destroy(OverlapInfo * lap)286 overlap_destroy( OverlapInfo *lap )
287 {
288 	JoinNode *node = lap->node;
289 
290 	node->overlaps = g_slist_remove( node->overlaps, lap );
291 	g_assert( node->st->novl > 0 );
292 	node->st->novl--;
293 }
294 
295 static void
junk_table(VipsImage * image,SymbolTable * st)296 junk_table( VipsImage *image, SymbolTable *st ) {
297 	int i;
298 
299 	for( i = 0; i < st->sz; i++ )
300 		VIPS_FREEF( g_slist_free, st->table[i] );
301 }
302 
303 /* Build a new symbol table.
304  */
305 SymbolTable *
vips__build_symtab(VipsImage * out,int sz)306 vips__build_symtab( VipsImage *out, int sz )
307 {
308 	SymbolTable *st = VIPS_NEW( out, SymbolTable );
309 	int i;
310 
311 	if( !st ||
312 		!(st->table = VIPS_ARRAY( out, sz, GSList * )) )
313 		return( NULL );
314 	st->sz = sz;
315 	st->im = out;
316 	st->novl = 0;
317 	st->nim = 0;
318 	st->njoin = 0;
319 	st->root = NULL;
320 	st->leaf = NULL;
321 	st->fac = NULL;
322 
323 	g_signal_connect( out, "close",
324 		G_CALLBACK( junk_table ), st );
325 
326 	for( i = 0; i < sz; i++ )
327 		st->table[i] = NULL;
328 
329 	return( st );
330 }
331 
332 /* Does this node have this file name?
333  */
334 static JoinNode *
test_name(JoinNode * node,char * name,void * b)335 test_name( JoinNode *node, char *name, void *b )
336 {
337 	if( strcmp( node->name, name ) == 0 )
338 		return( node );
339 	else
340 		return( NULL );
341 }
342 
343 /* Look up a filename in the symbol_table.
344  */
345 static JoinNode *
find_node(SymbolTable * st,char * name)346 find_node( SymbolTable *st, char *name )
347 {
348 	return( vips_slist_map2( st->table[hash( name )],
349 		(VipsSListMap2Fn) test_name, name, NULL ) );
350 }
351 
352 /* Given a name: return either the existing node for that name, or a new node
353  * we have made.
354  */
355 static JoinNode *
add_node(SymbolTable * st,char * name)356 add_node( SymbolTable *st, char *name )
357 {
358 	JoinNode *node;
359 
360 	if( !(node = find_node( st, name )) &&
361 		!(node = build_node( st, name )) )
362 		return( NULL );
363 
364 	return( node );
365 }
366 
367 /* Map a user function over the whole of the symbol table.
368  */
369 void *
vips__map_table(SymbolTable * st,VipsSListMap2Fn fn,void * a,void * b)370 vips__map_table( SymbolTable *st, VipsSListMap2Fn fn, void *a, void *b )
371 {
372 	int i;
373 	void *r;
374 
375 	for( i = 0; i < st->sz; i++ )
376 		if( (r = vips_slist_map2( st->table[i], fn, a, b )) )
377 			return( r );
378 
379 	return( NULL );
380 }
381 
382 /* Set the dirty field on a join.
383  */
384 static void *
set_dirty(JoinNode * node,int state,void * b)385 set_dirty( JoinNode *node, int state, void *b )
386 {
387 	node->dirty = state;
388 
389 	return( NULL );
390 }
391 
392 /* Clean the whole table.
393  */
394 static void
clean_table(SymbolTable * st)395 clean_table( SymbolTable *st )
396 {
397 	(void) vips__map_table( st,
398 		(VipsSListMap2Fn) set_dirty, (void *) 0, NULL );
399 }
400 
401 /* Do geometry calculations on a node, assuming geo is up to date for any
402  * children.
403  */
404 static void
calc_geometry(JoinNode * node)405 calc_geometry( JoinNode *node )
406 {
407 	VipsRect um;
408 
409 	switch( node->type ) {
410 	case JOIN_LR:
411 	case JOIN_TB:
412 	case JOIN_LRROTSCALE:
413 	case JOIN_TBROTSCALE:
414 		/* Join two areas.
415 		 */
416 		vips_rect_unionrect( &node->arg1->cumtrn.oarea,
417 			&node->arg2->cumtrn.oarea, &um );
418 		node->cumtrn.iarea.left = 0;
419 		node->cumtrn.iarea.top = 0;
420 		node->cumtrn.iarea.width = um.width;
421 		node->cumtrn.iarea.height = um.height;
422 		vips__transform_set_area( &node->cumtrn );
423 		break;
424 
425 	case JOIN_CP:
426 		/* Copy from child.
427 		 */
428 		node->cumtrn = node->arg1->cumtrn;
429 		break;
430 
431 	case JOIN_LEAF:
432 		/* Just use leaf dimensions, if there are any.
433 		 */
434 		if( node->im ) {
435 			node->cumtrn.iarea.left = 0;
436 			node->cumtrn.iarea.top = 0;
437 			node->cumtrn.iarea.width = node->im->Xsize;
438 			node->cumtrn.iarea.height = node->im->Ysize;
439 			vips__transform_set_area( &node->cumtrn );
440 		}
441 		break;
442 
443 	default:
444 		vips_error_exit( "internal error #98356" );
445 		/*NOTREACHED*/
446 	}
447 }
448 
449 /* Propagate a transform down a tree. If dirty is set, we've been here before,
450  * so there is a doubling up of this node. If this is a leaf, then we have the
451  * same leaf twice (which, in fact, we can cope with); if this is a node, we
452  * have circularity.
453  */
454 static int
propagate_transform(JoinNode * node,VipsTransformation * trn)455 propagate_transform( JoinNode *node, VipsTransformation *trn )
456 {
457 	if( !node )
458 		return( 0 );
459 
460 	if( node->dirty && node->arg1 && node->arg2 ) {
461 		vips_error( "vips_global_balance",
462 			"%s", _( "circularity detected" ) );
463 		return( -1 );
464 	}
465 	node->dirty = 1;
466 
467 	/* Transform our children.
468 	 */
469 	if( propagate_transform( node->arg1, trn ) ||
470 		propagate_transform( node->arg2, trn ) )
471 		return( -1 );
472 
473 	/* Transform us, and recalculate our position and size.
474 	 */
475 	vips__transform_add( &node->cumtrn, trn, &node->cumtrn );
476 	calc_geometry( node );
477 
478 	return( 0 );
479 }
480 
481 /* Ah ha! A leaf is actually made up of two smaller files with an lr or a tb
482  * merge. Turn a leaf node into a join node. Propagate the transform down
483  * arg2's side of the tree.
484  */
485 static int
make_join(SymbolTable * st,JoinType type,JoinNode * arg1,JoinNode * arg2,JoinNode * out,double a,double b,double dx,double dy,int mwidth)486 make_join( SymbolTable *st, JoinType type,
487 	JoinNode *arg1, JoinNode *arg2, JoinNode *out,
488 	double a, double b, double dx, double dy, int mwidth )
489 {
490 	VipsTransformation trn;
491 
492 	/* Check output is ok.
493 	 */
494 	if( out->type != JOIN_LEAF ) {
495 		vips_error( "vips_global_balance",
496 			_( "image \"%s\" used twice as output" ), out->name );
497 		return( -1 );
498 	}
499 
500 	/* Fill fields.
501 	 */
502 	out->type = type;
503 	out->mwidth = mwidth;
504 	out->a = a;
505 	out->b = b;
506 	out->dx = dx;
507 	out->dy = dy;
508 	out->arg1 = arg1;
509 	out->arg2 = arg2;
510 	out->thistrn.a = a;
511 	out->thistrn.b = -b;
512 	out->thistrn.c = b;
513 	out->thistrn.d = a;
514 	out->thistrn.idx = 0;
515 	out->thistrn.idy = 0;
516 	out->thistrn.odx = dx;
517 	out->thistrn.ody = dy;
518 
519 	/* Clean the table and propagate the transform down the RHS of the
520 	 * graph.
521 	 */
522 	clean_table( st );
523 	if( propagate_transform( arg2, &out->thistrn ) )
524 		return( -1 );
525 
526 	/* Find the position and size of our output.
527 	 */
528 	calc_geometry( out );
529 
530 	/* Now normalise the result, so that out is at (0,0) again.
531 	 */
532 	trn.a = 1.0;
533 	trn.b = 0.0;
534 	trn.c = 0.0;
535 	trn.d = 1.0;
536 	trn.idx = 0;
537 	trn.idy = 0;
538 	trn.odx = -out->cumtrn.oarea.left;
539 	trn.ody = -out->cumtrn.oarea.top;
540 	clean_table( st );
541 	if( propagate_transform( out, &trn ) )
542 		return( -1 );
543 
544 	return( 0 );
545 }
546 
547 /* Make a copy node.
548  */
549 static int
make_copy(SymbolTable * st,JoinNode * before,JoinNode * after)550 make_copy( SymbolTable *st, JoinNode *before, JoinNode *after )
551 {
552 	/* Check output is ok.
553 	 */
554 	if( after->type != JOIN_LEAF ) {
555 		vips_error( "vips_global_balance",
556 			_( "image \"%s\" used twice as output" ), after->name );
557 		return( -1 );
558 	}
559 
560 	/* Fill fields.
561 	 */
562 	after->type = JOIN_CP;
563 	after->arg1 = before;
564 	after->arg2 = NULL;
565 
566 	/* Copy over the position and size from the before to the after.
567 	 */
568 	calc_geometry( after );
569 
570 	return( 0 );
571 }
572 
573 /* Process a single .desc line.
574  */
575 static int
process_line(SymbolTable * st,const char * text)576 process_line( SymbolTable *st, const char *text )
577 {
578 	char line[1024];
579 
580 #ifdef DEBUG
581 	printf( "read: %s\n", text );
582 #endif /*DEBUG*/
583 
584 	/* We destroy line during the parse.
585 	 */
586 	vips_strncpy( line, text, 1024 );
587 
588 	if( vips_isprefix( "#LRJOIN ", line ) ||
589 		vips_isprefix( "#TBJOIN ", line ) ) {
590 		/* Yes: magic join command. Break into tokens. Format is eg.
591 
592 			#LRJOIN <left> <right> <out> <x> <y> [<mwidth>]
593 
594 		 */
595 		char *item[MAX_ITEMS];
596 		int nitems;
597 		JoinType type;
598 		JoinNode *arg1, *arg2, *join;
599 		int dx, dy, mwidth;
600 
601 		if( (nitems = break_items( line, item )) < 0 )
602 			return( -1 );
603 		if( nitems != 5 && nitems != 6 ) {
604 			vips_error( "global_balance",
605 				"%s", _( "bad number of args in join line" ) );
606 			return( -1 );
607 		}
608 
609 		if( !(arg1 = add_node( st, item[0] )) ||
610 			!(arg2 = add_node( st, item[1] )) ||
611 			!(join = add_node( st, item[2] )) )
612 			return( -1 );
613 		dx = atoi( item[3] );
614 		dy = atoi( item[4] );
615 		if( nitems == 6 )
616 			mwidth = atoi( item[5] );
617 		else
618 			mwidth = -1;
619 		if( vips_isprefix( "#LRJOIN ", line ) )
620 			type = JOIN_LR;
621 		else
622 			type = JOIN_TB;
623 
624 		if( make_join( st, type, arg1, arg2,
625 			join, 1.0, 0.0, dx, dy, mwidth ) )
626 			return( -1 );
627 	}
628 	else if( vips_isprefix( "#LRROTSCALE ", line ) ||
629 		vips_isprefix( "#TBROTSCALE ", line ) ) {
630 		/* Rot + scale. Format is eg.
631 
632 			#LRROTSCALE <left> <right> <out> \
633 				<a> <b> <x> <y> [<mwidth>]
634 
635 		 */
636 		char *item[MAX_ITEMS];
637 		int nitems;
638 		JoinType type;
639 		JoinNode *arg1, *arg2, *join;
640 		double a, b, dx, dy;
641 		int mwidth;
642 
643 		if( (nitems = break_items( line, item )) < 0 )
644 			return( -1 );
645 		if( nitems != 7 && nitems != 8 ) {
646 			vips_error( "global_balance",
647 				"%s", _( "bad number of args in join1 line" ) );
648 			return( -1 );
649 		}
650 
651 		if( !(arg1 = add_node( st, item[0] )) ||
652 			!(arg2 = add_node( st, item[1] )) ||
653 			!(join = add_node( st, item[2] )) )
654 			return( -1 );
655 		a = g_ascii_strtod( item[3], NULL );
656 		b = g_ascii_strtod( item[4], NULL );
657 		dx = g_ascii_strtod( item[5], NULL );
658 		dy = g_ascii_strtod( item[6], NULL );
659 		if( nitems == 8 )
660 			mwidth = atoi( item[7] );
661 		else
662 			mwidth = -1;
663 		if( vips_isprefix( "#LRROTSCALE ", line ) )
664 			type = JOIN_LRROTSCALE;
665 		else
666 			type = JOIN_TBROTSCALE;
667 
668 		if( make_join( st, type, arg1, arg2,
669 			join, a, b, dx, dy, mwidth ) )
670 			return( -1 );
671 	}
672 	else if( vips_isprefix( "copy ", line ) ) {
673 		/* vips_copy() call ... make a JOIN_CP node.
674 		 */
675 		char *item[MAX_ITEMS];
676 		int nitems;
677 		JoinNode *before, *after;
678 
679 		if( (nitems = break_items( line, item )) < 0 )
680 			return( -1 );
681 		if( nitems != 2 ) {
682 			vips_error( "global_balance",
683 				"%s", _( "bad number of args in copy line" ) );
684 			return( -1 );
685 		}
686 
687 		if( !(before = add_node( st, item[0] )) ||
688 			!(after = add_node( st, item[1] )) ||
689 			make_copy( st, before, after ) )
690 			return( -1 );
691 	}
692 
693 	return( 0 );
694 }
695 
696 /* Set the dirty flag on any nodes we reference.
697  */
698 static void *
set_referenced(JoinNode * node,void * a,void * b)699 set_referenced( JoinNode *node, void *a, void *b )
700 {
701 	if( node->arg1 )
702 		node->arg1->dirty = 1;
703 	if( node->arg2 )
704 		node->arg2->dirty = 1;
705 
706 	return( NULL );
707 }
708 
709 /* Is this a root node? Should be clean.
710  */
711 static void *
is_root(JoinNode * node,void * a,void * b)712 is_root( JoinNode *node, void *a, void *b )
713 {
714 	if( !node->dirty )
715 		return( (void *) node );
716 	else
717 		return( NULL );
718 }
719 
720 /* Scan the symbol table, looking for a node which no node references.
721  */
722 static JoinNode *
find_root(SymbolTable * st)723 find_root( SymbolTable *st )
724 {
725 	JoinNode *root;
726 
727 	/* Clean the table, then scan it, setting all pointed-to nodes dirty.
728 	 */
729 	clean_table( st );
730 	vips__map_table( st, (VipsSListMap2Fn) set_referenced, NULL, NULL );
731 
732 	/* Look for the first clean symbol.
733 	 */
734 	root = (JoinNode *) vips__map_table( st,
735 		(VipsSListMap2Fn) is_root, NULL, NULL );
736 
737 	/* No root? Hot dang!
738 	 */
739 	if( !root ) {
740 		vips_error( "vips_global_balance",
741 			"%s", _( "mosaic root not found in desc file\n"
742 			"is this really a mosaiced image?" ) );
743 		return( NULL );
744 	}
745 
746 	/* Now dirty that - then if there are any more clean symbols, we have
747 	 * more than one root.
748 	 */
749 	root->dirty = 1;
750 	if( vips__map_table( st, (VipsSListMap2Fn) is_root, NULL, NULL ) ) {
751 		vips_error( "vips_global_balance",
752 			"%s", _( "more than one root" ) );
753 		return( NULL );
754 	}
755 
756 	return( root );
757 }
758 
759 /* Walk history_list and parse each line.
760  */
761 int
vips__parse_desc(SymbolTable * st,VipsImage * in)762 vips__parse_desc( SymbolTable *st, VipsImage *in )
763 {
764 	GSList *p;
765 
766 	for( p = in->history_list; p; p = p->next ) {
767 		GValue *value = (GValue *) p->data;
768 
769 		g_assert( G_VALUE_TYPE( value ) == VIPS_TYPE_REF_STRING );
770 
771 		if( process_line( st, vips_value_get_ref_string( value, NULL ) ) )
772 			return( -1 );
773 	}
774 
775 	/* Find root.
776 	 */
777 	if( !(st->root = find_root( st )) )
778 		return( -1 );
779 
780 	return( 0 );
781 }
782 
783 /* Count and index all leaf images.
784  */
785 static void *
count_leaves(JoinNode * node,void * a,void * b)786 count_leaves( JoinNode *node, void *a, void *b )
787 {
788 	if( node->type == JOIN_LEAF ) {
789 		node->index = node->st->nim;
790 		node->st->nim++;
791 	}
792 
793 	return( NULL );
794 }
795 
796 #ifdef DEBUG
797 /* Print a JoinNode.
798  */
799 static void
print_node(JoinNode * node)800 print_node( JoinNode *node )
801 {
802 	char *basename = g_path_get_basename( node->name );
803 	printf( "%s, position %dx%d, size %dx%d, index %d\n",
804 		basename,
805 		node->cumtrn.oarea.left, node->cumtrn.oarea.top,
806 		node->cumtrn.oarea.width, node->cumtrn.oarea.height,
807 		node->index );
808 	g_free( basename );
809 }
810 #endif /*DEBUG*/
811 
812 #ifdef DEBUG
813 /* Print a leaf.
814  */
815 static void *
print_leaf(JoinNode * node,void * a,void * b)816 print_leaf( JoinNode *node, void *a, void *b )
817 {
818 	if( node->type == JOIN_LEAF )
819 		print_node( node );
820 
821 	return( NULL );
822 }
823 #endif /*DEBUG*/
824 
825 /* Count all join nodes.
826  */
827 static void *
count_joins(JoinNode * node,void * a,void * b)828 count_joins( JoinNode *node, void *a, void *b )
829 {
830 	if( node->type == JOIN_TB ||
831 		node->type == JOIN_LR ||
832 		node->type == JOIN_LRROTSCALE ||
833 		node->type == JOIN_TBROTSCALE )
834 		node->st->njoin++;
835 
836 	return( NULL );
837 }
838 
839 #ifdef DEBUG
840 /* Print a few spaces.
841  */
842 static void
spc(int n)843 spc( int n )
844 {
845 	int i;
846 
847 	for( i = 0; i < n; i++ )
848 		printf( " " );
849 }
850 #endif /*DEBUG*/
851 
852 #ifdef DEBUG
853 static char *
JoinType2char(JoinType type)854 JoinType2char( JoinType type )
855 {
856 	switch( type ) {
857 	case JOIN_LR: 		return( "JOIN_LR" );
858 	case JOIN_TB: 		return( "JOIN_TB" );
859 	case JOIN_LRROTSCALE: 	return( "JOIN_LRROTSCALE" );
860 	case JOIN_TBROTSCALE: 	return( "JOIN_TBROTSCALE" );
861 	case JOIN_CP: 		return( "JOIN_CP" );
862 	case JOIN_LEAF: 	return( "JOIN_LEAF" );
863 
864 	default:
865 		vips_error_exit( "internal error #9275" );
866 		/*NOTEACHED*/
867 
868 		return( NULL );
869 	}
870 }
871 #endif /*DEBUG*/
872 
873 #ifdef DEBUG
874 /* Print a join node.
875  */
876 static void *
print_joins(JoinNode * node,int indent)877 print_joins( JoinNode *node, int indent )
878 {
879 	char *basename = g_path_get_basename( node->name );
880 
881 	switch( node->type ) {
882 	case JOIN_TB:
883 	case JOIN_LR:
884 	case JOIN_TBROTSCALE:
885 	case JOIN_LRROTSCALE:
886 		spc( indent );
887 		printf( "%s to make %s, size %dx%d, pos. %dx%d, of:\n",
888 			JoinType2char( node->type ),
889 			basename,
890 			node->cumtrn.oarea.width, node->cumtrn.oarea.height,
891 			node->cumtrn.oarea.left, node->cumtrn.oarea.top );
892 		spc( indent );
893 		printf( "reference:\n" );
894 		print_joins( node->arg1, indent + 2 );
895 		spc( indent );
896 		printf( "secondary:\n" );
897 		print_joins( node->arg2, indent + 2 );
898 		break;
899 
900 	case JOIN_CP:
901 		spc( indent );
902 		printf( "copy to make %s of:\n", basename );
903 		print_joins( node->arg1, indent + 2 );
904 		break;
905 
906 	case JOIN_LEAF:
907 		spc( indent );
908 		printf( "input image %s\n", basename );
909 		break;
910 	}
911 
912 	g_free( basename );
913 
914 	return( NULL );
915 }
916 #endif /*DEBUG*/
917 
918 #ifdef DEBUG
919 /* Print an overlap.
920  */
921 static void *
print_overlap(OverlapInfo * lap,void * a,void * b)922 print_overlap( OverlapInfo *lap, void *a, void *b )
923 {
924 	char *basename_node = g_path_get_basename( lap->node->name );
925 	char *basename_other = g_path_get_basename( lap->other->name );
926 
927 	printf( "-> %s overlaps with %s; (this, other) = (%.4G, %.4G)\n",
928 		basename_node,
929 		basename_other,
930 		*VIPS_MATRIX( lap->nstats, 4, 0 ),
931 		*VIPS_MATRIX( lap->ostats, 4, 0 ) );
932 
933 	g_free( basename_node );
934 	g_free( basename_other );
935 
936 	return( NULL );
937 }
938 #endif /*DEBUG*/
939 
940 #ifdef DEBUG
941 /* Print the overlaps on a leaf.
942  */
943 static void *
print_overlaps(JoinNode * node,void * a,void * b)944 print_overlaps( JoinNode *node, void *a, void *b )
945 {
946 	char *basename;
947 
948 	if( node->type == JOIN_LEAF && g_slist_length( node->overlaps ) > 0 ) {
949 		basename = g_path_get_basename( node->name );
950 		printf( "overlap of %s with:\n", basename );
951 		g_free( basename );
952 		vips_slist_map2( node->overlaps,
953 			(VipsSListMap2Fn) print_overlap, NULL, NULL );
954 	}
955 
956 	return( NULL );
957 }
958 #endif /*DEBUG*/
959 
960 #ifdef DEBUG
961 /* Print and accumulate the error on an overlap.
962  */
963 static void *
print_overlap_error(OverlapInfo * lap,double * fac,double * total)964 print_overlap_error( OverlapInfo *lap, double *fac, double *total )
965 {
966 	char *basename_other = g_path_get_basename( lap->other->name );
967 	double na = *VIPS_MATRIX( lap->nstats, 4, 0 );
968 	double oa = *VIPS_MATRIX( lap->ostats, 4, 0 );
969 	double err;
970 
971 	if( fac ) {
972 		na *= fac[lap->node->index];
973 		oa *= fac[lap->other->index];
974 	}
975 
976 	err = na - oa;
977 
978 	printf( "-> file %s, error = %g\n",
979 		basename_other, err );
980 	*total += err * err;
981 
982 	g_free( basename_other );
983 
984 	return( NULL );
985 }
986 #endif /*DEBUG*/
987 
988 #ifdef DEBUG
989 /* Print and accumulate the overlap errors on a leaf.
990  */
991 static void *
print_overlap_errors(JoinNode * node,double * fac,double * total)992 print_overlap_errors( JoinNode *node, double *fac, double *total )
993 {
994 	char *basename;
995 
996 	if( node->type == JOIN_LEAF && g_slist_length( node->overlaps ) > 0 ) {
997 		basename = g_path_get_basename( node->name );
998 		printf( "overlap of %s (index %d) with:\n", basename,
999 			node->index );
1000 		g_free( basename );
1001 		vips_slist_map2( node->overlaps,
1002 			(VipsSListMap2Fn) print_overlap_error, fac, total );
1003 	}
1004 
1005 	return( NULL );
1006 }
1007 #endif /*DEBUG*/
1008 
1009 /* Extract a rect.
1010  */
1011 static int
extract_rect(VipsImage * in,VipsImage ** out,VipsRect * r)1012 extract_rect( VipsImage *in, VipsImage **out, VipsRect *r )
1013 {
1014 	return( vips_extract_area( in, out,
1015 		r->left, r->top, r->width, r->height, NULL ) );
1016 }
1017 
1018 /* Two images overlap in an area ... make a mask the size of the area, which
1019  * has 255 for every pixel where both images are non-zero.
1020  */
1021 static int
make_overlap_mask(VipsImage * mem,VipsImage * ref,VipsImage * sec,VipsImage ** mask,VipsRect * rarea,VipsRect * sarea)1022 make_overlap_mask( VipsImage *mem,
1023 	VipsImage *ref, VipsImage *sec, VipsImage **mask,
1024 	VipsRect *rarea, VipsRect *sarea )
1025 {
1026 	VipsImage **t = (VipsImage **)
1027 		vips_object_local_array( VIPS_OBJECT( mem ), 6 );
1028 
1029 	if( extract_rect( ref, &t[0], rarea ) ||
1030 		extract_rect( sec, &t[1], sarea ) ||
1031 		vips_extract_band( t[0], &t[2], 0, NULL ) ||
1032 		vips_extract_band( t[1], &t[3], 0, NULL ) ||
1033 		vips_notequal_const1( t[2], &t[4], 0.0, NULL ) ||
1034 		vips_notequal_const1( t[3], &t[5], 0.0, NULL ) ||
1035 		vips_andimage( t[4], t[5], mask, NULL ) )
1036 		return( -1 );
1037 
1038 	return( 0 );
1039 }
1040 
1041 /* Find the number of non-zero pixels in a mask image.
1042  */
1043 static int
count_nonzero(VipsImage * in,gint64 * count)1044 count_nonzero( VipsImage *in, gint64 *count )
1045 {
1046 	double avg;
1047 
1048 	if( vips_avg( in, &avg, NULL ) )
1049 		return( -1 );
1050 	*count = (avg * VIPS_IMAGE_N_PELS( in )) / 255.0;
1051 
1052 	return( 0 );
1053 }
1054 
1055 /* Find stats on an area of an IMAGE ... consider only pixels for which the
1056  * mask is true.
1057  */
1058 static VipsImage *
find_image_stats(VipsImage * mem,VipsImage * in,VipsImage * mask,VipsRect * area)1059 find_image_stats( VipsImage *mem,
1060 	VipsImage *in, VipsImage *mask, VipsRect *area )
1061 {
1062 	VipsImage **t = (VipsImage **)
1063 		vips_object_local_array( VIPS_OBJECT( mem ), 5 );
1064 
1065 	gint64 count;
1066 
1067 	/* Extract area, build black image, mask out pixels we want.
1068 	 */
1069 	if( extract_rect( in, &t[0], area ) ||
1070 		vips_black( &t[1], t[0]->Xsize, t[0]->Ysize,
1071 			"bands", t[0]->Bands,
1072 			NULL ) ||
1073 		vips_cast( t[1], &t[2], t[0]->BandFmt, NULL ) ||
1074 		vips_ifthenelse( mask, t[0], t[2], &t[3], NULL ) )
1075 		return( NULL );
1076 
1077 	/* Get stats from masked image.
1078 	 */
1079 	if( vips_stats( t[3], &t[4], NULL ) )
1080 		return( NULL );
1081 
1082 	/* Number of non-zero pixels in mask.
1083 	 */
1084 	if( count_nonzero( mask, &count ) )
1085 		return( NULL );
1086 
1087 	/* And scale masked average to match.
1088 	 */
1089 	*VIPS_MATRIX( t[4], 4, 0 ) *=
1090 		(double) count / VIPS_IMAGE_N_PELS( mask );
1091 
1092 	/* Yuk! Zap the deviation column with the pixel count. Used later to
1093 	 * determine if this is likely to be a significant overlap.
1094 	 */
1095 	*VIPS_MATRIX( t[4], 5, 0 )  = count;
1096 
1097 #ifdef DEBUG
1098 	if( count == 0 )
1099 		g_warning( "global_balance %s", _( "empty overlap!" ) );
1100 #endif /*DEBUG*/
1101 
1102 	return( t[4] );
1103 }
1104 
1105 /* Find the stats for an overlap struct.
1106  */
1107 static int
find_overlap_stats(OverlapInfo * lap)1108 find_overlap_stats( OverlapInfo *lap )
1109 {
1110 	VipsImage *mem = lap->node->st->im;
1111 	VipsImage **t = (VipsImage **)
1112 		vips_object_local_array( VIPS_OBJECT( mem ), 1 );
1113 
1114 	VipsRect rarea, sarea;
1115 
1116 	/* Translate the overlap area into the coordinate scheme for the main
1117 	 * node.
1118 	 */
1119 	rarea = lap->overlap;
1120 	rarea.left -= lap->node->cumtrn.oarea.left;
1121 	rarea.top -= lap->node->cumtrn.oarea.top;
1122 
1123 	/* Translate the overlap area into the coordinate scheme for the other
1124 	 * node.
1125 	 */
1126 	sarea = lap->overlap;
1127 	sarea.left -= lap->other->cumtrn.oarea.left;
1128 	sarea.top -= lap->other->cumtrn.oarea.top;
1129 
1130 	/* Make a mask for the overlap.
1131 	 */
1132 	if( make_overlap_mask( mem,
1133 		lap->node->trnim, lap->other->trnim, &t[0], &rarea, &sarea ) )
1134 		return( -1 );
1135 
1136 	/* Find stats for that area.
1137 	 */
1138 	if( !(lap->nstats = find_image_stats( mem,
1139 		lap->node->trnim, t[0], &rarea )) )
1140 		return( -1 );
1141 	if( !(lap->ostats = find_image_stats( mem,
1142 		lap->other->trnim, t[0], &sarea )) )
1143 		return( -1 );
1144 
1145 	return( 0 );
1146 }
1147 
1148 /* Sub-fn. of below.
1149  */
1150 static void *
overlap_eq(OverlapInfo * this,JoinNode * node,void * b)1151 overlap_eq( OverlapInfo *this, JoinNode *node, void *b )
1152 {
1153 	if( this->other == node )
1154 		return( this );
1155 	else
1156 		return( NULL );
1157 }
1158 
1159 /* Is this an overlapping leaf? If yes, add to overlap list.
1160  */
1161 static void *
test_overlap(JoinNode * other,JoinNode * node,void * b)1162 test_overlap( JoinNode *other, JoinNode *node, void *b )
1163 {
1164 	VipsRect overlap;
1165 	OverlapInfo *lap;
1166 
1167 	/* Is other a suitable leaf to overlap with node?
1168 	 */
1169 	if( other->type != JOIN_LEAF || node == other )
1170 		return( NULL );
1171 
1172 	/* Is there an overlap?
1173 	 */
1174 	vips_rect_intersectrect( &node->cumtrn.oarea, &other->cumtrn.oarea,
1175 		&overlap );
1176 	if( vips_rect_isempty( &overlap ) )
1177 		return( NULL );
1178 
1179 	/* Is this a trivial overlap? Ignore it if it is.
1180 	 */
1181 	if( overlap.width * overlap.height < TRIVIAL )
1182 		/* Too few pixels.
1183 		 */
1184 		return( NULL );
1185 
1186 	/* Have we already added this overlap the other way around? ie. is
1187 	 * node on other's overlap list?
1188 	 */
1189 	if( vips_slist_map2( other->overlaps,
1190 		(VipsSListMap2Fn) overlap_eq, node, NULL ) )
1191 		return( NULL );
1192 
1193 	/* A new overlap - add to overlap list.
1194 	 */
1195 	if( !(lap = build_overlap( node, other, &overlap )) )
1196 		return( node );
1197 
1198 	/* Calculate overlap statistics. Open stuff relative to this, and
1199 	 * free quickly.
1200 	 */
1201 	if( find_overlap_stats( lap ) )
1202 		return( node );
1203 
1204 	/* If the pixel count either masked overlap is trivial, ignore this
1205 	 * overlap.
1206 	 */
1207 	if( *VIPS_MATRIX( lap->nstats, 5, 0 ) < TRIVIAL ||
1208 		*VIPS_MATRIX( lap->ostats, 5, 0 ) < TRIVIAL ) {
1209 #ifdef DEBUG
1210 		printf( "trivial overlap ... junking\n" );
1211 		printf( "nstats count = %g, ostats count = %g\n",
1212 			*VIPS_MATRIX( lap->nstats, 5, 0 ), *VIPS_MATRIX( lap->ostats, 5, 0 ) );
1213 		print_overlap( lap, NULL, NULL );
1214 #endif /*DEBUG*/
1215 		overlap_destroy( lap );
1216 	}
1217 
1218 	return( NULL );
1219 }
1220 
1221 /* If this is a leaf, look at all other joins for a leaf that overlaps. Aside:
1222  * If this is a leaf, there should be an IMAGE. Flag an error if there is
1223  * not.
1224  */
1225 static void *
find_overlaps(JoinNode * node,SymbolTable * st,void * b)1226 find_overlaps( JoinNode *node, SymbolTable *st, void *b )
1227 {
1228 	if( node->type == JOIN_LEAF ) {
1229 		/* Check for image.
1230 		 */
1231 		if( !node->im ) {
1232 			vips_error( "vips_global_balance",
1233 				_( "unable to open \"%s\"" ), node->name );
1234 			return( node );
1235 		}
1236 		if( !node->trnim )
1237 			vips_error_exit( "global_balance: sanity failure #9834" );
1238 
1239 		return( vips__map_table( st,
1240 			(VipsSListMap2Fn) test_overlap, node, NULL ) );
1241 	}
1242 
1243 	return( NULL );
1244 }
1245 
1246 /* Bundle of variables for matrix creation.
1247  */
1248 typedef struct {
1249 	SymbolTable *st;		/* Main table */
1250 	JoinNode *leaf;			/* Leaf to be 1.000 */
1251 	VipsImage *K;			/* LHS */
1252 	VipsImage *M;			/* RHS */
1253 	int row;			/* Current row */
1254 } MatrixBundle;
1255 
1256 /* Add a new row for the nominated overlap to the matrices.
1257  */
1258 static void *
add_nominated(OverlapInfo * ovl,MatrixBundle * bun,double * gamma)1259 add_nominated( OverlapInfo *ovl, MatrixBundle *bun, double *gamma )
1260 {
1261 	double ns = pow( *VIPS_MATRIX( ovl->nstats, 4, 0 ), 1.0 / (*gamma) );
1262 	double os = pow( *VIPS_MATRIX( ovl->ostats, 4, 0 ), 1.0 / (*gamma) );
1263 
1264 	*VIPS_MATRIX( bun->K, 0, bun->row ) = ns;
1265 	*VIPS_MATRIX( bun->M, ovl->other->index - 1, bun->row ) = os;
1266 
1267 	bun->row++;
1268 
1269 	return( NULL );
1270 }
1271 
1272 /* Add a new row for an ordinary overlap to the matrices.
1273  */
1274 static void *
add_other(OverlapInfo * ovl,MatrixBundle * bun,double * gamma)1275 add_other( OverlapInfo *ovl, MatrixBundle *bun, double *gamma )
1276 {
1277 	double ns = -pow( *VIPS_MATRIX( ovl->nstats, 4, 0 ), 1.0 / (*gamma) );
1278 	double os = pow( *VIPS_MATRIX( ovl->ostats, 4, 0 ), 1.0 / (*gamma) );
1279 
1280 	*VIPS_MATRIX( bun->M, ovl->node->index - 1, bun->row ) = ns;
1281 	*VIPS_MATRIX( bun->M, ovl->other->index - 1, bun->row ) = os;
1282 
1283 	bun->row++;
1284 
1285 	return( NULL );
1286 }
1287 
1288 /* Add stuff for node to matrix.
1289  */
1290 static void *
add_row(JoinNode * node,MatrixBundle * bun,double * gamma)1291 add_row( JoinNode *node, MatrixBundle *bun, double *gamma )
1292 {
1293 	if( node == bun->leaf )
1294 		vips_slist_map2( node->overlaps,
1295 			(VipsSListMap2Fn) add_nominated, bun, gamma );
1296 	else
1297 		vips_slist_map2( node->overlaps,
1298 			(VipsSListMap2Fn) add_other, bun, gamma );
1299 
1300 	return( NULL );
1301 }
1302 
1303 /* Fill K and M. leaf is image selected to have factor of 1.000.
1304  */
1305 static void
fill_matrices(SymbolTable * st,double gamma,VipsImage * K,VipsImage * M)1306 fill_matrices( SymbolTable *st, double gamma, VipsImage *K, VipsImage *M )
1307 {
1308 	MatrixBundle bun;
1309 
1310 	bun.st = st;
1311 	bun.leaf = st->leaf;
1312 	bun.K = K;
1313 	bun.M = M;
1314 	bun.row = 0;
1315 
1316 	/* Build matrices.
1317 	 */
1318 	vips__map_table( st, (VipsSListMap2Fn) add_row, &bun, &gamma );
1319 }
1320 
1321 /* Used to select the leaf whose coefficient we set to 1.
1322  */
1323 static void *
choose_leaf(JoinNode * node,void * a,void * b)1324 choose_leaf( JoinNode *node, void *a, void *b )
1325 {
1326 	if( node->type == JOIN_LEAF )
1327 		return( node );
1328 
1329 	return( NULL );
1330 }
1331 
1332 /* Make an image from a node.
1333  */
1334 static VipsImage *
make_mos_image(SymbolTable * st,JoinNode * node,transform_fn tfn,void * a)1335 make_mos_image( SymbolTable *st, JoinNode *node, transform_fn tfn, void *a )
1336 {
1337 	VipsImage *im1, *im2, *out;
1338 
1339 	switch( node->type ) {
1340 	case JOIN_LR:
1341 	case JOIN_TB:
1342 		if( !(im1 = make_mos_image( st, node->arg1, tfn, a )) ||
1343 			!(im2 = make_mos_image( st, node->arg2, tfn, a )) )
1344 			return( NULL );
1345 
1346 		if( vips_merge( im1, im2, &out,
1347 			node->type == JOIN_LR ?
1348 				VIPS_DIRECTION_HORIZONTAL :
1349 				VIPS_DIRECTION_VERTICAL,
1350 			-node->dx, -node->dy,
1351 			"mblend", node->mwidth,
1352 			NULL ) )
1353 			return( NULL );
1354 		vips_object_local( st->im, out );
1355 		vips_image_set_string( out, "mosaic-name", node->name );
1356 
1357 		break;
1358 
1359 	case JOIN_LRROTSCALE:
1360 	case JOIN_TBROTSCALE:
1361 		if( !(im1 = make_mos_image( st, node->arg1, tfn, a )) ||
1362 			!(im2 = make_mos_image( st, node->arg2, tfn, a )) )
1363 			return( NULL );
1364 
1365 		out = vips_image_new();
1366 		vips_object_local( st->im, out );
1367 
1368 		vips_image_set_string( out, "mosaic-name", node->name );
1369 
1370 		if( node->type == JOIN_LRROTSCALE ) {
1371 			if( vips__lrmerge1( im1, im2, out,
1372 				node->a, node->b, node->dx, node->dy,
1373 				node->mwidth ) )
1374 				return( NULL );
1375 		}
1376 		else {
1377 			if( vips__tbmerge1( im1, im2, out,
1378 				node->a, node->b, node->dx, node->dy,
1379 				node->mwidth ) )
1380 				return( NULL );
1381 		}
1382 
1383 		break;
1384 
1385 	case JOIN_LEAF:
1386 		/* Trivial case!
1387 		 */
1388 		if( !(out = tfn( node, a )) )
1389 			return( NULL );
1390 
1391 		break;
1392 
1393 	case JOIN_CP:
1394 		/* Very trivial case.
1395 		 */
1396 		out = make_mos_image( st, node->arg1, tfn, a );
1397 
1398 		break;
1399 
1400 	default:
1401 		vips_error_exit( "internal error #982369824375987" );
1402 		/*NOTEACHED*/
1403 		return( NULL );
1404 	}
1405 
1406 	return( out );
1407 }
1408 
1409 /* Re-build mosaic.
1410  */
1411 int
vips__build_mosaic(SymbolTable * st,VipsImage * out,transform_fn tfn,void * a)1412 vips__build_mosaic( SymbolTable *st, VipsImage *out, transform_fn tfn, void *a )
1413 {
1414 	JoinNode *root = st->root;
1415 	VipsImage *im1, *im2;
1416 	VipsImage *x;
1417 
1418 	switch( root->type ) {
1419 	case JOIN_LR:
1420 	case JOIN_TB:
1421 		if( !(im1 = make_mos_image( st, root->arg1, tfn, a )) ||
1422 			!(im2 = make_mos_image( st, root->arg2, tfn, a )) )
1423 			return( -1 );
1424 
1425 		if( vips_merge( im1, im2, &x,
1426 			root->type == JOIN_LR ?
1427 				VIPS_DIRECTION_HORIZONTAL :
1428 				VIPS_DIRECTION_VERTICAL,
1429 			-root->dx, -root->dy,
1430 			"mblend", root->mwidth,
1431 			NULL ) )
1432 			return( -1 );
1433 		if( vips_image_write( x, out ) ) {
1434 			g_object_unref( x );
1435 			return( -1 );
1436 		}
1437 		g_object_unref( x );
1438 
1439 		break;
1440 
1441 	case JOIN_LRROTSCALE:
1442 	case JOIN_TBROTSCALE:
1443 		if( !(im1 = make_mos_image( st, root->arg1, tfn, a )) ||
1444 			!(im2 = make_mos_image( st, root->arg2, tfn, a )) )
1445 			return( -1 );
1446 
1447 		if( root->type == JOIN_LRROTSCALE ) {
1448 			if( vips__lrmerge1( im1, im2, out,
1449 				root->a, root->b, root->dx, root->dy,
1450 				root->mwidth ) )
1451 				return( -1 );
1452 		}
1453 		else {
1454 			if( vips__tbmerge1( im1, im2, out,
1455 				root->a, root->b, root->dx, root->dy,
1456 				root->mwidth ) )
1457 				return( -1 );
1458 		}
1459 
1460 		break;
1461 
1462 	case JOIN_LEAF:
1463 		/* Trivial case! Just one file in our mosaic.
1464 		 */
1465 		if( !(im1 = tfn( root, a )) ||
1466 			vips_image_write( im1, out ) )
1467 			return( -1 );
1468 
1469 		break;
1470 
1471 	case JOIN_CP:
1472 		/* Very trivial case.
1473 		 */
1474 		if( !(im1 = make_mos_image( st, root->arg1, tfn, a )) ||
1475 			vips_image_write( im1, out ) )
1476 			return( -1 );
1477 
1478 		break;
1479 
1480 	default:
1481 		vips_error_exit( "internal error #982369824375987" );
1482 		/*NOTEACHED*/
1483 	}
1484 
1485 	return( 0 );
1486 }
1487 
1488 static int
vips__matrixtranspose(VipsImage * in,VipsImage ** out)1489 vips__matrixtranspose( VipsImage *in, VipsImage **out )
1490 {
1491 	int yc, xc;
1492 
1493 	/* Allocate output matrix.
1494 	 */
1495 	if( !(*out = vips_image_new_matrix( in->Ysize, in->Xsize )) )
1496 		return( -1 );
1497 
1498 	/* Transpose.
1499 	 */
1500 	for( yc = 0; yc < (*out)->Ysize; ++yc )
1501 		for( xc = 0; xc < (*out)->Xsize; ++xc )
1502 			*VIPS_MATRIX( *out, xc, yc ) = *VIPS_MATRIX( in, yc, xc );
1503 
1504 	return( 0 );
1505 }
1506 
1507 static int
vips__matrixmultiply(VipsImage * in1,VipsImage * in2,VipsImage ** out)1508 vips__matrixmultiply( VipsImage *in1, VipsImage *in2, VipsImage **out )
1509 {
1510 	int xc, yc, col;
1511 	double sum;
1512 	double *mat, *a, *b;
1513 	double *s1, *s2;
1514 
1515 	/* Check matrix sizes.
1516 	 */
1517 	if( in1->Xsize != in2->Ysize ) {
1518 		vips_error( "vips__matrixmultiply", "%s", _( "bad sizes" ) );
1519 		return( -1 );
1520 	}
1521 
1522 	/* Allocate output matrix.
1523 	 */
1524 	if( !(*out = vips_image_new_matrix( in2->Xsize, in1->Ysize  )) )
1525 		return( -1 );
1526 
1527 	/* Multiply.
1528 	 */
1529 	mat = VIPS_MATRIX( *out, 0, 0 );
1530 	s1 = VIPS_MATRIX( in1, 0, 0 );
1531 
1532 	for( yc = 0; yc < in1->Ysize; yc++ ) {
1533 		s2 = VIPS_MATRIX( in2, 0, 0 );
1534 
1535 		for( col = 0; col < in2->Xsize; col++ ) {
1536 			/* Get ready to sweep a row.
1537 			 */
1538 			a = s1;
1539 			b = s2;
1540 
1541 			for( sum = 0.0, xc = 0; xc < in1->Xsize; xc++ ) {
1542 				sum += *a++ * *b;
1543 				b += in2->Xsize;
1544 			}
1545 
1546 			*mat++ = sum;
1547 			s2++;
1548 		}
1549 
1550 		s1 += in1->Xsize;
1551 	}
1552 
1553 	return( 0 );
1554 }
1555 
1556 /* Find correction factors.
1557  */
1558 static int
find_factors(SymbolTable * st,double gamma)1559 find_factors( SymbolTable *st, double gamma )
1560 {
1561 	VipsImage **t = (VipsImage **)
1562 		vips_object_local_array( VIPS_OBJECT( st->im ), 7 );
1563 
1564 	double total;
1565 	double avg;
1566 	int i;
1567 
1568 	/* Make output matrices.
1569 	 */
1570 	if( !(t[0] = vips_image_new_matrix( 1, st->novl )) ||
1571 		!(t[1] = vips_image_new_matrix( st->nim - 1, st->novl )) )
1572 		return( -1 );
1573 
1574 	fill_matrices( st, gamma, t[0], t[1] );
1575 
1576 #ifdef DEBUG
1577 	vips_image_write_to_file( t[0], "K.mat", NULL );
1578 	vips_image_write_to_file( t[1], "M.mat", NULL );
1579 #endif /*DEBUG*/
1580 
1581 	/* Calculate LMS.
1582 	 */
1583 	if( vips__matrixtranspose( t[1], &t[2] ) ||
1584 		vips__matrixmultiply( t[2], t[1], &t[3] ) ||
1585 		vips_matrixinvert( t[3], &t[4], NULL ) ||
1586 		vips__matrixmultiply( t[4], t[2], &t[5] ) ||
1587 		vips__matrixmultiply( t[5], t[0], &t[6] ) )
1588 		return( -1 );
1589 
1590 	/* Make array of correction factors.
1591 	 */
1592 	if( !(st->fac = VIPS_ARRAY( st->im, st->nim, double )) )
1593 		return( -1 );
1594 	for( i = 0; i < t[6]->Ysize; i++ )
1595 		st->fac[i + 1] = *VIPS_MATRIX( t[6], 0, i );
1596 	st->fac[0] = 1.0;
1597 
1598 	/* Find average balance factor, normalise to that average.
1599 	 */
1600 	total = 0.0;
1601 	for( i = 0; i < st->nim; i++ )
1602 		total += st->fac[i];
1603 	avg = total / st->nim;
1604 	for( i = 0; i < st->nim; i++ )
1605 		st->fac[i] /= avg;
1606 
1607 #ifdef DEBUG
1608 	/* Diagnostics!
1609 	 */
1610 	printf( "debugging output for vips_global_balance():\n" );
1611 	for( i = 0; i < st->nim; i++ )
1612 		printf( "balance factor %d = %g\n", i, st->fac[i] );
1613 	total = 0.0;
1614 	printf( "Overlap errors:\n" );
1615 	vips__map_table( st,
1616 		(VipsSListMap2Fn) print_overlap_errors, NULL, &total );
1617 	printf( "RMS error = %g\n", sqrt( total / st->novl ) );
1618 
1619 	total = 0.0;
1620 	printf( "Overlap errors after adjustment:\n" );
1621 	vips__map_table( st,
1622 		(VipsSListMap2Fn) print_overlap_errors, st->fac, &total );
1623 	printf( "RMS error = %g\n", sqrt( total / st->novl ) );
1624 #endif /*DEBUG*/
1625 
1626 	return( 0 );
1627 }
1628 
1629 /* TODO(kleisauke): Copied from im__affinei */
1630 /* Shared with vips_mosaic1(), so not static. */
1631 int
vips__affinei(VipsImage * in,VipsImage * out,VipsTransformation * trn)1632 vips__affinei( VipsImage *in, VipsImage *out, VipsTransformation *trn )
1633 {
1634 	VipsImage **t = (VipsImage **)
1635 		vips_object_local_array( VIPS_OBJECT( out ), 2 );
1636 	VipsArea *oarea;
1637 	gboolean repack;
1638 
1639 	oarea = VIPS_AREA( vips_array_int_newv( 4,
1640 		trn->oarea.left, trn->oarea.top,
1641 		trn->oarea.width, trn->oarea.height ) );
1642 
1643 	/* vips7 affine would repack labq and im_benchmark() depends upon
1644 	 * this.
1645 	 */
1646 	repack = in->Coding == VIPS_CODING_LABQ;
1647 
1648 	if( vips_affine( in, &t[0],
1649 		trn->a, trn->b, trn->c, trn->d,
1650 		"oarea", oarea,
1651 		"odx", trn->odx,
1652 		"ody", trn->ody,
1653 		NULL ) ) {
1654 		vips_area_unref( oarea );
1655 		return( -1 );
1656 	}
1657 	vips_area_unref( oarea );
1658 	in = t[0];
1659 
1660 	if( repack ) {
1661 		if (vips_colourspace( in, &t[1],
1662 			VIPS_INTERPRETATION_LABQ, NULL ) )
1663 			return ( -1 );
1664 		in = t[1];
1665 	}
1666 
1667 	if( vips_image_write( in, out ) )
1668 		return( -1 );
1669 
1670 	return( 0 );
1671 }
1672 
1673 /* Look for all leaves, make sure we have a transformed version of each.
1674  */
1675 static void *
generate_trn_leaves(JoinNode * node,SymbolTable * st,void * b)1676 generate_trn_leaves( JoinNode *node, SymbolTable *st, void *b )
1677 {
1678 	if( node->type == JOIN_LEAF ) {
1679 		/* Check for image.
1680 		 */
1681 		if( !node->im ) {
1682 			vips_error( "vips_global_balance",
1683 				_( "unable to open \"%s\"" ), node->name );
1684 			return( node );
1685 		}
1686 		if( node->trnim )
1687 			vips_error_exit( "global_balance: sanity failure #765" );
1688 
1689 		/* Special case: if this is an untransformed leaf (there will
1690 		 * always be at least one), then skip the affine.
1691 		 */
1692 		if( vips__transform_isidentity( &node->cumtrn ) )
1693 			node->trnim = node->im;
1694 		else {
1695 			node->trnim = vips_image_new();
1696 			vips_object_local( node->st->im, node->trnim );
1697 
1698 			if ( vips__affinei( node->im, node->trnim, &node->cumtrn ) )
1699 				return( node );
1700 		}
1701 	}
1702 
1703 	return( NULL );
1704 }
1705 
1706 /* Analyse mosaic.
1707  */
1708 static int
analyse_mosaic(SymbolTable * st,VipsImage * in)1709 analyse_mosaic( SymbolTable *st, VipsImage *in )
1710 {
1711 	/* Parse Hist on in.
1712 	 */
1713 	if( vips__parse_desc( st, in ) )
1714 		return( -1 );
1715 
1716 	/* Print parsed data.
1717 	 */
1718 #ifdef DEBUG
1719 	printf( "Input files:\n" );
1720 	vips__map_table( st, (VipsSListMap2Fn) print_leaf, NULL, NULL );
1721 	printf( "\nOutput file:\n" );
1722 	print_node( st->root );
1723 	printf( "\nJoin commands:\n" );
1724 	print_joins( st->root, 0 );
1725 #endif /*DEBUG*/
1726 
1727 	/* Generate transformed leaves.
1728 	 */
1729 	if( vips__map_table( st,
1730 		(VipsSListMap2Fn) generate_trn_leaves, st, NULL ) )
1731 		return( -1 );
1732 
1733 	/* Find overlaps.
1734 	 */
1735 	if( vips__map_table( st, (VipsSListMap2Fn) find_overlaps, st, NULL ) )
1736 		return( -1 );
1737 
1738 	/* Scan table, counting and indexing input images and joins.
1739 	 */
1740 	vips__map_table( st, (VipsSListMap2Fn) count_leaves, NULL, NULL );
1741 	vips__map_table( st, (VipsSListMap2Fn) count_joins, NULL, NULL );
1742 
1743 	/* Select leaf to be 1.000.
1744 	 * This must be index == 0, unless you change stuff above!
1745 	 */
1746 	st->leaf = vips__map_table( st,
1747 		(VipsSListMap2Fn) choose_leaf, NULL, NULL );
1748 
1749 	/* And print overlaps.
1750 	 */
1751 #ifdef DEBUG
1752 	printf( "\nLeaf to be 1.000:\n" );
1753 	print_node( st->leaf );
1754 	printf( "\nOverlaps:\n" );
1755 	vips__map_table( st, (VipsSListMap2Fn) print_overlaps, NULL, NULL );
1756 	printf( "\n%d input files, %d unique overlaps, %d joins\n",
1757 		st->nim, st->novl, st->njoin );
1758 #endif /*DEBUG*/
1759 
1760 	return( 0 );
1761 }
1762 
1763 /* Scale im by fac --- if it's uchar/ushort, use a lut. If we can use a lut,
1764  * transform in linear space. If we can't, don't bother for efficiency.
1765  */
1766 static VipsImage *
transform(JoinNode * node,double * gamma)1767 transform( JoinNode *node, double *gamma )
1768 {
1769 	SymbolTable *st = node->st;
1770 	VipsImage *in = node->im;
1771 	double fac = st->fac[node->index];
1772 	VipsImage **t = (VipsImage **)
1773 		vips_object_local_array( VIPS_OBJECT( st->im ), 8 );
1774 
1775 	VipsImage *out;
1776 
1777 	if( fac == 1.0 ) {
1778 		/* Easy!
1779 		 */
1780 		out = in;
1781 	}
1782 	/* TODO(kleisauke): Could we call vips_gamma instead?
1783 	 */
1784 	else if( in->BandFmt == VIPS_FORMAT_UCHAR ||
1785 		in->BandFmt == VIPS_FORMAT_USHORT ) {
1786 		if( vips_identity( &t[0],
1787 				"bands", 1,
1788 				"ushort", in->BandFmt == VIPS_FORMAT_USHORT,
1789 				//"size", 65535,
1790 				NULL ) ||
1791 			vips_pow_const1( t[0], &t[1],
1792 				1.0 / (*gamma), NULL ) ||
1793 			vips_linear1( t[1], &t[2], fac, 0.0, NULL ) ||
1794 			vips_pow_const1( t[2], &t[3], *gamma, NULL ) ||
1795 			vips_cast( t[3], &t[4], in->BandFmt, NULL ) ||
1796 			vips_maplut( in, &t[5], t[4], NULL ) )
1797 			return( NULL );
1798 		out = t[5];
1799 	}
1800 	else {
1801 		/* Just vips_linear1 it.
1802 		 */
1803 		if( vips_linear1( in, &t[6], fac, 0.0, NULL ) ||
1804 			vips_cast( t[6], &t[7], in->BandFmt, NULL ) )
1805 			return( NULL );
1806 		out = t[7];
1807 	}
1808 
1809 	vips_image_set_string( out, "mosaic-name", node->name );
1810 
1811 	return( out );
1812 }
1813 
1814 /* As above, but output as float, not matched to input.
1815  */
1816 static VipsImage *
transformf(JoinNode * node,double * gamma)1817 transformf( JoinNode *node, double *gamma )
1818 {
1819 	SymbolTable *st = node->st;
1820 	VipsImage *in = node->im;
1821 	double fac = node->st->fac[node->index];
1822 	VipsImage **t = (VipsImage **)
1823 		vips_object_local_array( VIPS_OBJECT( st->im ), 6 );
1824 
1825 	VipsImage *out;
1826 
1827 	if( fac == 1.0 ) {
1828 		/* Easy!
1829 		 */
1830 		out = in;
1831 	}
1832 	else if( in->BandFmt == VIPS_FORMAT_UCHAR ||
1833 		in->BandFmt == VIPS_FORMAT_USHORT ) {
1834 		if( vips_identity( &t[0],
1835 				"bands", 1,
1836 				"ushort", in->BandFmt == VIPS_FORMAT_USHORT,
1837 				//"size", 65535,
1838 				NULL ) ||
1839 			vips_pow_const1( t[0], &t[1],
1840 				1.0 / (*gamma), NULL ) ||
1841 			vips_linear1( t[1], &t[2], fac, 0.0, NULL ) ||
1842 			vips_pow_const1( t[2], &t[3], *gamma, NULL ) ||
1843 			vips_maplut( in, &t[4], t[3], NULL ) )
1844 			return( NULL );
1845 		out = t[4];
1846 	}
1847 	else {
1848 		/* Just vips_linear1 it.
1849 		 */
1850 		if( vips_linear1( in, &t[5], fac, 0.0, NULL ) )
1851 			return( NULL );
1852 		out = t[5];
1853 	}
1854 
1855 	vips_image_set_string( out, "mosaic-name", node->name );
1856 
1857 	return( out );
1858 }
1859 
1860 typedef struct {
1861 	VipsOperation parent_instance;
1862 
1863 	VipsImage *in;
1864 	VipsImage *out;
1865 
1866 	gboolean int_output;
1867 	double gamma;
1868 
1869 } VipsGlobalbalance;
1870 
1871 typedef VipsOperationClass VipsGlobalbalanceClass;
1872 
1873 G_DEFINE_TYPE( VipsGlobalbalance, vips_globalbalance, VIPS_TYPE_OPERATION );
1874 
1875 static int
vips_globalbalance_build(VipsObject * object)1876 vips_globalbalance_build( VipsObject *object )
1877 {
1878 	VipsGlobalbalance *globalbalance = (VipsGlobalbalance *) object;
1879 
1880 	SymbolTable *st;
1881 	transform_fn trn;
1882 
1883 	g_object_set( globalbalance, "out", vips_image_new(), NULL );
1884 
1885 	if( VIPS_OBJECT_CLASS( vips_globalbalance_parent_class )->
1886 		build( object ) )
1887 		return( -1 );
1888 
1889 	if( !(st = vips__build_symtab( globalbalance->out, SYM_TAB_SIZE )) ||
1890 		analyse_mosaic( st, globalbalance->in ) ||
1891 		find_factors( st, globalbalance->gamma ) )
1892 		return( -1 );
1893 
1894 	trn = globalbalance->int_output ?
1895 		(transform_fn) transform : (transform_fn) transformf;
1896 	if( vips__build_mosaic( st, globalbalance->out,
1897 		trn, &globalbalance->gamma ) )
1898 		return( -1 );
1899 
1900 	return( 0 );
1901 }
1902 
1903 static void
vips_globalbalance_class_init(VipsGlobalbalanceClass * class)1904 vips_globalbalance_class_init( VipsGlobalbalanceClass *class )
1905 {
1906 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
1907 	VipsObjectClass *object_class = (VipsObjectClass *) class;
1908 
1909 	gobject_class->set_property = vips_object_set_property;
1910 	gobject_class->get_property = vips_object_get_property;
1911 
1912 	object_class->nickname = "globalbalance";
1913 	object_class->description = _( "global balance an image mosaic" );
1914 	object_class->build = vips_globalbalance_build;
1915 
1916 	VIPS_ARG_IMAGE( class, "in", 1,
1917 		_( "Input" ),
1918 		_( "Input image" ),
1919 		VIPS_ARGUMENT_REQUIRED_INPUT,
1920 		G_STRUCT_OFFSET( VipsGlobalbalance, in ) );
1921 
1922 	VIPS_ARG_IMAGE( class, "out", 2,
1923 		_( "Output" ),
1924 		_( "Output image" ),
1925 		VIPS_ARGUMENT_REQUIRED_OUTPUT,
1926 		G_STRUCT_OFFSET( VipsGlobalbalance, out ) );
1927 
1928 	VIPS_ARG_DOUBLE( class, "gamma", 5,
1929 		_( "gamma" ),
1930 		_( "Image gamma" ),
1931 		VIPS_ARGUMENT_OPTIONAL_INPUT,
1932 		G_STRUCT_OFFSET( VipsGlobalbalance, gamma ),
1933 		0.00001, 10, 1.6 );
1934 
1935 	VIPS_ARG_BOOL( class, "int_output", 7,
1936 		_( "Int output" ),
1937 		_( "Integer output" ),
1938 		VIPS_ARGUMENT_OPTIONAL_INPUT,
1939 		G_STRUCT_OFFSET( VipsGlobalbalance, int_output ),
1940 		FALSE );
1941 
1942 }
1943 
1944 static void
vips_globalbalance_init(VipsGlobalbalance * globalbalance)1945 vips_globalbalance_init( VipsGlobalbalance *globalbalance )
1946 {
1947 	globalbalance->gamma = 1.6;
1948 }
1949 
1950 /**
1951  * vips_globalbalance: (method)
1952  * @in: mosaic to rebuild
1953  * @out: (out): output image
1954  * @...: %NULL-terminated list of optional named arguments
1955  *
1956  * Optional arguments:
1957  *
1958  * * @gamma: gamma of source images
1959  * * @int_output: %TRUE for integer image output
1960  *
1961  * vips_globalbalance() can be used to remove contrast differences in
1962  * an assembled mosaic.
1963  *
1964  * It reads the History field attached to @in and builds a list of the source
1965  * images that were used to make the mosaic and the position that each ended
1966  * up at in the final image.
1967  *
1968  * It opens each of the source images in turn and extracts all parts which
1969  * overlap with any of the other images. It finds the average values in the
1970  * overlap areas and uses least-mean-square to find a set of correction
1971  * factors which will minimise overlap differences. It uses @gamma to
1972  * gamma-correct the source images before calculating the factors. A value of
1973  * 1.0 will stop this.
1974  *
1975  * Each of the source images is transformed with the appropriate correction
1976  * factor, then the mosaic is reassembled. @out is #VIPS_FORMAT_FLOAT, but
1977  * if @int_output is set, the output image is the same format as the input
1978  * images.
1979  *
1980  * There are some conditions that must be met before this operation can work:
1981  * the source images must all be present under the filenames recorded in the
1982  * history on @in, and the mosaic must have been built using only operations in
1983  * this package.
1984  *
1985  * See also: vips_remosaic().
1986  *
1987  * Returns: 0 on success, -1 on error
1988  */
1989 int
vips_globalbalance(VipsImage * in,VipsImage ** out,...)1990 vips_globalbalance( VipsImage *in, VipsImage **out, ... )
1991 {
1992 	va_list ap;
1993 	int result;
1994 
1995 	va_start( ap, out );
1996 	result = vips_call_split( "globalbalance", ap, in, out );
1997 	va_end( ap );
1998 
1999 	return( result );
2000 }
2001