blob: b3e12d6af0e7715c7901862611e60334f0586705 [file] [log] [blame]
/* im_measure.c
*
* Modified:
* 19/8/94 JC
* - now uses doubles for addressing
* - could miss by up to h pixels previously!
* - ANSIfied
* - now issues warning if any deviations are greater than 20% of the
* mean
* 31/10/95 JC
* - more careful about warning for averages <0, or averages near zero
* - can get these cases with im_measure() of IM_TYPE_LAB images
* 28/10/02 JC
* - number bands from zero in error messages
* 7/7/04
* - works on labq
* 18/8/08
* - add gtkdoc comments
* - remove deprecated im_extract()
* 30/11/09
* - changes for im_extract() broke averaging
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <math.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* Measure into array.
*/
static int
measure_patches( IMAGE *im, double *coeff,
int left, int top, int width, int height,
int u, int v, int *sel, int nsel )
{
IMAGE *tmp;
int patch;
int i, j;
int m, n;
double avg, dev;
int x, y, w, h;
/* How large are the patches we are to measure?
*/
double pw = (double) width / (double) u;
double ph = (double) height / (double) v;
/* Set up sub to be the size we need for a patch.
*/
w = (pw + 1) / 2;
h = (ph + 1) / 2;
/* Loop through sel, picking out areas to measure.
*/
for( j = 0, patch = 0; patch < nsel; patch++ ) {
/* Sanity check. Is the patch number sensible?
*/
if( sel[patch] <= 0 || sel[patch] > u * v ) {
im_error( "im_measure",
_( "patch %d is out of range" ),
sel[patch] );
return( 1 );
}
/* Patch coordinates.
*/
m = (sel[patch] - 1) % u;
n = (sel[patch] - 1) / u;
/* Move sub to correct position.
*/
x = left + m * pw + (pw + 2) / 4;
y = top + n * ph + (ph + 2) / 4;
/* Loop through bands.
*/
for( i = 0; i < im->Bands; i++, j++ ) {
/* Make temp buffer to extract to.
*/
if( !(tmp = im_open( "patch", "t" )) )
return( -1 );
/* Extract and measure.
*/
if( im_extract_areabands( im, tmp, x, y, w, h, i, 1 ) ||
im_avg( tmp, &avg ) ||
im_deviate( tmp, &dev ) ) {
im_close( tmp );
return( -1 );
}
im_close( tmp );
/* Is the deviation large compared with the average?
* This could be a clue that our parameters have
* caused us to miss the patch. Look out for averages
* <0, or averages near zero (can get these if use
* im_measure() on IM_TYPE_LAB images).
*/
if( dev * 5 > fabs( avg ) && fabs( avg ) > 3 )
im_warn( "im_measure",
_( "patch %d, band %d: "
"avg = %g, sdev = %g" ),
patch, i, avg, dev );
/* Save results.
*/
coeff[j] = avg;
}
}
return( 0 );
}
/**
* im_measure_area:
* @im: image to measure
* @left: area of image containing chart
* @top: area of image containing chart
* @width: area of image containing chart
* @height: area of image containing chart
* @h: patches across chart
* @v: patches down chart
* @sel: array of patch numbers to measure (numbered from 1 in row-major order)
* @nsel: length of patch number array
* @name: name to give to returned @DOUBLEMASK
*
* Analyse a grid of colour patches, producing a #DOUBLEMASK of patch averages.
* The mask has a row for each measured patch, and a column for each image
* band. The operations issues a warning if any patch has a deviation more
* than 20% of
* the mean. Only the central 50% of each patch is averaged. If @sel is %NULL
* then all patches are measured.
*
* Example: 6 band image of 4x2 block of colour patches.
*
* <tgroup cols='4' align='left' colsep='1' rowsep='1'>
* <tbody>
* <row>
* <entry>1</entry>
* <entry>2</entry>
* <entry>3</entry>
* <entry>4</entry>
* </row>
* <row>
* <entry>5</entry>
* <entry>6</entry>
* <entry>7</entry>
* <entry>8</entry>
* </row>
* </tbody>
* </tgroup>
*
* Then call im_measure( im, box, 4, 2, { 2, 4 }, 2, "fred" ) makes a mask
* "fred" which has 6 columns, two rows. The first row contains the averages
* for patch 2, the second for patch 4.
*
* See also: im_avg(), im_deviate(), im_stats().
*
* Returns: #DOUBLEMASK of measurements.
*/
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 )
{
DOUBLEMASK *mask;
/* Check input image.
*/
if( im->Coding == IM_CODING_LABQ ) {
IMAGE *t1;
if( !(t1 = im_open( "measure-temp", "p" )) )
return( NULL );
if( im_LabQ2Lab( im, t1 ) ||
!(mask = im_measure_area( t1,
left, top, width, height,
u, v,
sel, nsel, name )) ) {
im_close( t1 );
return( NULL );
}
im_close( t1 );
return( mask );
}
if( im_check_uncoded( "im_measure", im ) ||
im_check_noncomplex( "im_measure", im ) )
return( NULL );
/* Default to all patches if sel == NULL.
*/
if( sel == NULL ) {
int i;
nsel = u * v;
if( !(sel = IM_ARRAY( im, nsel, int )) )
return( NULL );
for( i = 0; i < nsel; i++ )
sel[i] = i + 1;
}
/* What size mask do we need?
*/
if( !(mask = im_create_dmask( name, im->Bands, nsel )) )
return( NULL );
/* Perform measure and return.
*/
if( measure_patches( im, mask->coeff, left, top, width, height,
u, v, sel, nsel ) ) {
im_free_dmask( mask );
return( NULL );
}
return( mask );
}