1 /* im_measure.c
2 *
3 * Modified:
4 * 19/8/94 JC
5 * - now uses doubles for addressing
6 * - could miss by up to h pixels previously!
7 * - ANSIfied
8 * - now issues warning if any deviations are greater than 20% of the
9 * mean
10 * 31/10/95 JC
11 * - more careful about warning for averages <0, or averages near zero
12 * - can get these cases with im_measure() of IM_TYPE_LAB images
13 * 28/10/02 JC
14 * - number bands from zero in error messages
15 * 7/7/04
16 * - works on labq
17 * 18/8/08
18 * - add gtkdoc comments
19 * - remove deprecated im_extract()
20 * 30/11/09
21 * - changes for im_extract() broke averaging
22 * 9/11/11
23 * - moved to deprecated, the new VipsMeasure does not have the
24 * select-patches thing, so we have to keep this around
25 */
26
27 /*
28
29 This file is part of VIPS.
30
31 VIPS is free software; you can redistribute it and/or modify
32 it under the terms of the GNU Lesser General Public License as published by
33 the Free Software Foundation; either version 2 of the License, or
34 (at your option) any later version.
35
36 This program is distributed in the hope that it will be useful,
37 but WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 GNU Lesser General Public License for more details.
40
41 You should have received a copy of the GNU Lesser General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
44 02110-1301 USA
45
46 */
47
48 /*
49
50 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
51
52 */
53
54 #ifdef HAVE_CONFIG_H
55 #include <config.h>
56 #endif /*HAVE_CONFIG_H*/
57 #include <vips/intl.h>
58
59 #include <stdio.h>
60 #include <math.h>
61
62 #include <vips/vips.h>
63 #include <vips/vips7compat.h>
64
65 /* Measure into array.
66 */
67 static int
measure_patches(IMAGE * im,double * coeff,int left,int top,int width,int height,int u,int v,int * sel,int nsel)68 measure_patches( IMAGE *im, double *coeff,
69 int left, int top, int width, int height,
70 int u, int v, int *sel, int nsel )
71 {
72 IMAGE *tmp;
73 int patch;
74 int i, j;
75 int m, n;
76 double avg, dev;
77 int x, y, w, h;
78
79 /* How large are the patches we are to measure?
80 */
81 double pw = (double) width / (double) u;
82 double ph = (double) height / (double) v;
83
84 /* Set up sub to be the size we need for a patch.
85 */
86 w = (pw + 1) / 2;
87 h = (ph + 1) / 2;
88
89 /* Loop through sel, picking out areas to measure.
90 */
91 for( j = 0, patch = 0; patch < nsel; patch++ ) {
92 /* Sanity check. Is the patch number sensible?
93 */
94 if( sel[patch] <= 0 || sel[patch] > u * v ) {
95 im_error( "im_measure",
96 _( "patch %d is out of range" ),
97 sel[patch] );
98 return( 1 );
99 }
100
101 /* Patch coordinates.
102 */
103 m = (sel[patch] - 1) % u;
104 n = (sel[patch] - 1) / u;
105
106 /* Move sub to correct position.
107 */
108 x = left + m * pw + (pw + 2) / 4;
109 y = top + n * ph + (ph + 2) / 4;
110
111 /* Loop through bands.
112 */
113 for( i = 0; i < im->Bands; i++, j++ ) {
114 /* Make temp buffer to extract to.
115 */
116 if( !(tmp = im_open( "patch", "t" )) )
117 return( -1 );
118
119 /* Extract and measure.
120 */
121 if( im_extract_areabands( im, tmp, x, y, w, h, i, 1 ) ||
122 im_avg( tmp, &avg ) ||
123 im_deviate( tmp, &dev ) ) {
124 im_close( tmp );
125 return( -1 );
126 }
127 im_close( tmp );
128
129 /* Is the deviation large compared with the average?
130 * This could be a clue that our parameters have
131 * caused us to miss the patch. Look out for averages
132 * <0, or averages near zero (can get these if use
133 * im_measure() on IM_TYPE_LAB images).
134 */
135 if( dev * 5 > fabs( avg ) && fabs( avg ) > 3 )
136 im_warn( "im_measure",
137 _( "patch %d, band %d: "
138 "avg = %g, sdev = %g" ),
139 patch, i, avg, dev );
140
141 /* Save results.
142 */
143 coeff[j] = avg;
144 }
145 }
146
147 return( 0 );
148 }
149
150 static DOUBLEMASK *
internal_im_measure_area(IMAGE * im,int left,int top,int width,int height,int u,int v,int * sel,int nsel,const char * name)151 internal_im_measure_area( IMAGE *im,
152 int left, int top, int width, int height,
153 int u, int v,
154 int *sel, int nsel, const char *name )
155 {
156 DOUBLEMASK *mask;
157
158 if( im_check_uncoded( "im_measure", im ) ||
159 im_check_noncomplex( "im_measure", im ) )
160 return( NULL );
161
162 /* Default to all patches if sel == NULL.
163 */
164 if( sel == NULL ) {
165 int i;
166
167 nsel = u * v;
168 if( !(sel = IM_ARRAY( im, nsel, int )) )
169 return( NULL );
170 for( i = 0; i < nsel; i++ )
171 sel[i] = i + 1;
172 }
173
174 /* What size mask do we need?
175 */
176 if( !(mask = im_create_dmask( name, im->Bands, nsel )) )
177 return( NULL );
178
179 /* Perform measure and return.
180 */
181 if( measure_patches( im, mask->coeff, left, top, width, height,
182 u, v, sel, nsel ) ) {
183 im_free_dmask( mask );
184 return( NULL );
185 }
186
187 return( mask );
188 }
189
190 DOUBLEMASK *
im_measure_area(IMAGE * im,int left,int top,int width,int height,int u,int v,int * sel,int nsel,const char * name)191 im_measure_area( IMAGE *im,
192 int left, int top, int width, int height,
193 int u, int v,
194 int *sel, int nsel, const char *name )
195 {
196 DOUBLEMASK *mask;
197 VipsImage *t;
198
199 /* The old im_measure() worked on labq.
200 */
201 if( im->Coding == IM_CODING_LABQ ) {
202 if( !(t = im_open( "measure-temp", "p" )) )
203 return( NULL );
204 if( im_LabQ2Lab( im, t ) ||
205 !(mask = im_measure_area( t,
206 left, top, width, height,
207 u, v,
208 sel, nsel, name )) ) {
209 g_object_unref( t );
210 return( NULL );
211 }
212 g_object_unref( t );
213
214 return( mask );
215 }
216
217 if( sel )
218 return( internal_im_measure_area( im,
219 left, top, width, height, u, v, sel, nsel, name ) );
220 else {
221 if( vips_measure( im, &t, u, v,
222 "left", left,
223 "top", top,
224 "width", width,
225 "height", height,
226 NULL ) )
227 return( NULL );
228 if( !(mask = im_vips2mask( t, name )) ) {
229 g_object_unref( t );
230 return( NULL );
231 }
232 g_object_unref( t );
233
234 return( mask );
235 }
236 }
237