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