1 /* join left-right with an approximate overlap
2  *
3  * Copyright: 1990, N. Dessipris.
4  *
5  * Author: Nicos Dessipris
6  * Written on: 07/11/1989
7  * Modified on : 29/11/1989, 18/04/1991
8  *
9  *
10  * Modified and debugged by Ahmed Abbood . 1995
11  * 14/6/95 JC
12  *	- rewritten for new balance ideas
13  *	- more bug-fixes
14  * 1/11/95 JC
15  *	- frees memory used by analysis phase as soon as possible
16  *	- means large mosaics use significantly less peak memory
17  * 26/3/96 JC
18  *	- now calls im_lrmerge() rather than im__lrmerge()
19  * 2/2/01 JC
20  *	- added tunable max blend width
21  * 24/2/05
22  *	- im_scale() makes it work for any image type
23  * 25/1/11
24  * 	- gtk-doc
25  * 	- remove balance stuff
26  * 	- any mix of types and bands
27  * 	- cleanups
28  * 18/6/20 kleisauke
29  * 	- convert to vips8
30  */
31 
32 /*
33 
34     This file is part of VIPS.
35 
36     VIPS is free software; you can redistribute it and/or modify
37     it under the terms of the GNU Lesser General Public License as published by
38     the Free Software Foundation; either version 2 of the License, or
39     (at your option) any later version.
40 
41     This program is distributed in the hope that it will be useful,
42     but WITHOUT ANY WARRANTY; without even the implied warranty of
43     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
44     GNU Lesser General Public License for more details.
45 
46     You should have received a copy of the GNU Lesser General Public License
47     along with this program; if not, write to the Free Software
48     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
49     02110-1301  USA
50 
51  */
52 
53 /*
54 
55     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
56 
57  */
58 
59 /* Define for debug output.
60 #define DEBUG
61  */
62 
63 #ifdef HAVE_CONFIG_H
64 #include <config.h>
65 #endif /*HAVE_CONFIG_H*/
66 #include <vips/intl.h>
67 
68 #include <stdio.h>
69 #include <string.h>
70 
71 #include <vips/vips.h>
72 #include <vips/internal.h>
73 
74 #include "pmosaicing.h"
75 
76 #ifdef DEBUG
77 static void
vips__print_mdebug(TiePoints * points)78 vips__print_mdebug( TiePoints *points )
79 {
80 	int i;
81 	double adx = 0.0;
82 	double ady = 0.0;
83 	double acor = 0.0;
84 
85 	for( i = 0; i < points->nopoints; i++ ) {
86 		adx += points->dx[i];
87 		ady += points->dy[i];
88 		acor += points->correlation[i];
89 	}
90 	adx = adx / (double) points->nopoints;
91 	ady = ady / (double) points->nopoints;
92 	acor = acor / (double) points->nopoints;
93 
94 	printf( "points: %d\n", points->nopoints );
95 	printf( "average dx, dy: %g %g\n", adx, ady );
96 	printf( "average correlation: %g\n", acor );
97 	printf( "deltax, deltay: %g %g\n", points->l_deltax, points->l_deltay );
98 }
99 #endif /*DEBUG*/
100 
101 int
vips__find_lroverlap(VipsImage * ref_in,VipsImage * sec_in,VipsImage * out,int bandno_in,int xref,int yref,int xsec,int ysec,int halfcorrelation,int halfarea,int * dx0,int * dy0,double * scale1,double * angle1,double * dx1,double * dy1)102 vips__find_lroverlap( VipsImage *ref_in, VipsImage *sec_in, VipsImage *out,
103 	int bandno_in,
104 	int xref, int yref, int xsec, int ysec,
105 	int halfcorrelation, int halfarea,
106 	int *dx0, int *dy0,
107 	double *scale1, double *angle1, double *dx1, double *dy1 )
108 {
109 	VipsImage **t = (VipsImage **)
110 		vips_object_local_array( VIPS_OBJECT( out ), 6 );
111 
112 	VipsRect left, right, overlap;
113 	TiePoints points, *p_points;
114 	TiePoints newpoints, *p_newpoints;
115 	int i;
116 	int dx, dy;
117 
118 	/* Test cor and area.
119 	 */
120 	if( halfcorrelation < 0 || halfarea < 0 ||
121 		halfarea < halfcorrelation ) {
122 		vips_error( "vips__lrmosaic", "%s", _( "bad area parameters" ) );
123 		return( -1 );
124 	}
125 
126 	/* Set positions of left and right.
127 	 */
128 	left.left = 0;
129 	left.top = 0;
130 	left.width = ref_in->Xsize;
131 	left.height = ref_in->Ysize;
132 	right.left = xref - xsec;
133 	right.top = yref - ysec;
134 	right.width = sec_in->Xsize;
135 	right.height = sec_in->Ysize;
136 
137 	/* Find overlap.
138 	 */
139 	vips_rect_intersectrect( &left, &right, &overlap );
140 	if( overlap.width < 2 * halfarea + 1 ||
141 		overlap.height < 2 * halfarea + 1 ) {
142 		vips_error( "vips__lrmosaic",
143 			"%s", _( "overlap too small for search" ) );
144 		return( -1 );
145 	}
146 
147 	/* Extract overlaps as 8-bit, 1 band.
148 	 */
149 	if( vips_extract_area( ref_in, &t[0],
150 			overlap.left, overlap.top,
151 			overlap.width, overlap.height, NULL ) ||
152 		vips_extract_area( sec_in, &t[1],
153 			overlap.left - right.left, overlap.top - right.top,
154 			overlap.width, overlap.height, NULL ) )
155 		return( -1 );
156 	if( ref_in->Coding == VIPS_CODING_LABQ ) {
157 		if( vips_LabQ2sRGB( t[0], &t[2], NULL ) ||
158 			vips_LabQ2sRGB( t[1], &t[3], NULL ) ||
159 			vips_extract_band( t[2], &t[4], 1, NULL ) ||
160 			vips_extract_band( t[3], &t[5], 1, NULL ) )
161 			return( -1 );
162 	}
163 	else if( ref_in->Coding == VIPS_CODING_NONE ) {
164 		if( vips_extract_band( t[0], &t[2], bandno_in, NULL ) ||
165 			vips_extract_band( t[1], &t[3], bandno_in, NULL ) ||
166 			vips_scale( t[2], &t[4], NULL ) ||
167 			vips_scale( t[3], &t[5], NULL ) )
168 			return( -1 );
169 	}
170 	else {
171 		vips_error( "vips__lrmosaic", "%s", _( "unknown Coding type" ) );
172 		return( -1 );
173 	}
174 
175 	/* Initialise and fill TiePoints
176 	 */
177 	p_points = &points;
178 	p_newpoints = &newpoints;
179 	p_points->reference = ref_in->filename;
180 	p_points->secondary = sec_in->filename;
181 	p_points->nopoints = VIPS_MAXPOINTS;
182 	p_points->deltax = 0;
183 	p_points->deltay = 0;
184 	p_points->halfcorsize = halfcorrelation;
185 	p_points->halfareasize = halfarea;
186 
187 	/* Initialise the structure
188 	 */
189 	for( i = 0; i < VIPS_MAXPOINTS; i++ ) {
190 		p_points->x_reference[i] = 0;
191 		p_points->y_reference[i] = 0;
192 		p_points->x_secondary[i] = 0;
193 		p_points->y_secondary[i] = 0;
194 		p_points->contrast[i] = 0;
195 		p_points->correlation[i] = 0.0;
196 		p_points->dx[i] = 0.0;
197 		p_points->dy[i] = 0.0;
198 		p_points->deviation[i] = 0.0;
199 	}
200 
201 	/* Search ref for possible tie-points. Sets: p_points->contrast,
202 	 * p_points->x,y_reference.
203  	 */
204 	if( vips__lrcalcon( t[4], p_points ) )
205 		return( -1 );
206 
207 	/* For each candidate point, correlate against corresponding part of
208 	 * sec. Sets x,y_secondary and fills correlation and dx, dy.
209  	 */
210 	if( vips__chkpair( t[4], t[5], p_points ) )
211 		return( -1 );
212 
213 	/* First call to vips_clinear().
214 	 */
215   	if( vips__initialize( p_points ) )
216 		return( -1 );
217 
218 	/* Improve the selection of tiepoints until all abs(deviations) are
219 	 * < 1.0 by deleting all wrong points.
220  	 */
221 	if( vips__improve( p_points, p_newpoints ) )
222 		return( -1 );
223 
224 	/* Average remaining offsets.
225 	 */
226 	if( vips__avgdxdy( p_newpoints, &dx, &dy ) )
227 		return( -1 );
228 
229 	/* Offset with overlap position.
230 	 */
231 	*dx0 = -right.left + dx;
232 	*dy0 = -right.top + dy;
233 
234 	/* Write 1st order parameters too.
235 	 */
236 	*scale1 = newpoints.l_scale;
237 	*angle1 = newpoints.l_angle;
238 	*dx1 = newpoints.l_deltax;
239 	*dy1 = newpoints.l_deltay;
240 
241 	return( 0 );
242 }
243 
244 int
vips__lrmosaic(VipsImage * ref,VipsImage * sec,VipsImage * out,int bandno,int xref,int yref,int xsec,int ysec,int hwindowsize,int hsearchsize,int balancetype,int mwidth)245 vips__lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out,
246 	int bandno,
247 	int xref, int yref, int xsec, int ysec,
248 	int hwindowsize, int hsearchsize,
249 	int balancetype,
250 	int mwidth )
251 {
252 	int dx0, dy0;
253 	double scale1, angle1, dx1, dy1;
254 	VipsImage *dummy;
255 	VipsImage *x;
256 
257 	/* Correct overlap. dummy is just a placeholder used to ensure that
258 	 * memory used by the analysis phase is freed as soon as possible.
259 	 */
260 	dummy = vips_image_new();
261 	if( vips__find_lroverlap( ref, sec, dummy,
262 		bandno,
263 		xref, yref, xsec, ysec,
264 		hwindowsize, hsearchsize,
265 		&dx0, &dy0,
266 		&scale1, &angle1, &dx1, &dy1 ) ) {
267 		g_object_unref( dummy );
268 		return( -1 );
269 	}
270 	g_object_unref( dummy );
271 
272 	/* Merge left right.
273 	 */
274 	if( vips_merge( ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, dx0, dy0,
275 		"mblend", mwidth,
276 		NULL ) )
277 		return( -1 );
278 	if( vips_image_write( x, out ) ) {
279 		g_object_unref( x );
280 		return( -1 );
281 	}
282 	g_object_unref( x );
283 
284 	return( 0 );
285 }
286