hist hacking

This commit is contained in:
John Cupitt 2010-03-25 14:41:27 +00:00
parent 81c6456b78
commit 05c5ae9734
8 changed files with 152 additions and 150 deletions

View File

@ -4,6 +4,7 @@
- im_wbuffer2() renamed as vips_discsink(), some cleanups - im_wbuffer2() renamed as vips_discsink(), some cleanups
- im_gammacorrect() can do 16-bit images too - im_gammacorrect() can do 16-bit images too
- im_histplot() could fail for signed int histograms - im_histplot() could fail for signed int histograms
- im_fwfft() and im_invfft() could free their output image too early
16/1/10 started 7.21.2 16/1/10 started 7.21.2
- "invalidate" is careful to keep images alive, so invalidate callbacks can do - "invalidate" is careful to keep images alive, so invalidate callbacks can do

3
TODO
View File

@ -2,6 +2,9 @@
- lots of stupid little files in hist, eg. im_hsp.c ... paste them into larger - lots of stupid little files in hist, eg. im_hsp.c ... paste them into larger
modules modules
- quite a few hist operations have no GUI ... lhisteq, for example? or
histspec?
- check the order of decls in hist.h, is it sensible? - check the order of decls in hist.h, is it sensible?
check the order in freq_flt as well check the order in freq_flt as well

View File

@ -30,6 +30,8 @@
* 7/2/10 * 7/2/10
* - cleanups * - cleanups
* - gtkdoc * - gtkdoc
* 25/3/10
* - have a "t" image linked to out to keep the image alive for longer
*/ */
/* /*
@ -573,6 +575,7 @@ im__fftproc( IMAGE *dummy, IMAGE *in, IMAGE *out, im__fftproc_fn fn )
{ {
IMAGE **bands; IMAGE **bands;
IMAGE **fft; IMAGE **fft;
IMAGE *t;
int b; int b;
if( in->Bands == 1 ) if( in->Bands == 1 )
@ -589,7 +592,12 @@ im__fftproc( IMAGE *dummy, IMAGE *in, IMAGE *out, im__fftproc_fn fn )
fn( dummy, bands[b], fft[b] ) ) fn( dummy, bands[b], fft[b] ) )
return( -1 ); return( -1 );
if( im_gbandjoin( fft, out, in->Bands ) ) /* We need a "t" for the combined image that won't get freed too
* quickly.
*/
if( !(t = im_open_local( out, "im__fftproc", "t" )) ||
im_gbandjoin( fft, t, in->Bands ) ||
im_copy( t, out ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );

View File

@ -258,7 +258,6 @@ invfft1( IMAGE *dummy, IMAGE *in, IMAGE *out )
#endif /*HAVE_FFTW3*/ #endif /*HAVE_FFTW3*/
#endif /*HAVE_FFTW*/ #endif /*HAVE_FFTW*/
/** /**
* im_invfft: * im_invfft:
* @in: input image * @in: input image

View File

@ -63,7 +63,7 @@
* Histogram-equalise @in. Equalise using band @bandno, or if @bandno is -1, * Histogram-equalise @in. Equalise using band @bandno, or if @bandno is -1,
* equalise all bands. * equalise all bands.
* *
* See also: im_histgr(), im_histeq(). * See also: im_lhisteq(), im_histgr(), im_histeq().
* *
* Returns: 0 on success, -1 on error * Returns: 0 on success, -1 on error
*/ */

View File

@ -1,12 +1,4 @@
/* @(#) Performs local histogram equalisation on an image using a /* local histogram equalisation
* @(#) window of size xw by yw
* @(#) Works only on monochrome images
* @(#)
* @(#) int im_lhisteq(in, out, xwin, ywin)
* @(#) IMAGE *in, *out;
* @(#) int xwin, ywin;
* @(#)
* @(#) Returns 0 on sucess and -1 on error
* *
* Copyright: 1991, N. Dessipris * Copyright: 1991, N. Dessipris
* *
@ -22,6 +14,9 @@
* - sets Xoffset/Yoffset * - sets Xoffset/Yoffset
* 23/6/08 * 23/6/08
* - check for window too small as well * - check for window too small as well
* 25/3/10
* - gtkdoc
* - small cleanups
*/ */
/* /*
@ -80,18 +75,12 @@ lhist_gen( REGION *or, void *seq, void *a, void *b )
{ {
REGION *ir = (REGION *) seq; REGION *ir = (REGION *) seq;
LhistInfo *inf = (LhistInfo *) b; LhistInfo *inf = (LhistInfo *) b;
Rect irect;
Rect *r = &or->valid; Rect *r = &or->valid;
int le = r->left;
int to = r->top;
int bo = IM_RECT_BOTTOM( r );
int ri = IM_RECT_RIGHT( r );
Rect irect;
int x, y, i, j; int x, y, i, j;
int lsk; int lsk;
int centre; /* Offset to move to centre of window */
int coff; /* Offset to move to centre of window */
/* What part of ir do we need? /* What part of ir do we need?
*/ */
@ -99,49 +88,60 @@ lhist_gen( REGION *or, void *seq, void *a, void *b )
irect.top = or->valid.top; irect.top = or->valid.top;
irect.width = or->valid.width + inf->xwin; irect.width = or->valid.width + inf->xwin;
irect.height = or->valid.height + inf->ywin; irect.height = or->valid.height + inf->ywin;
if( im_prepare( ir, &irect ) ) if( im_prepare( ir, &irect ) )
return( -1 ); return( -1 );
lsk = IM_REGION_LSKIP( ir );
coff = lsk * (inf->ywin / 2) + inf->xwin / 2;
for( y = to; y < bo; y++ ) { lsk = IM_REGION_LSKIP( ir );
centre = lsk * (inf->ywin / 2) + inf->xwin / 2;
for( y = 0; y < r->height; y++ ) {
/* Get input and output pointers for this line. /* Get input and output pointers for this line.
*/ */
PEL *p = (PEL *) IM_REGION_ADDR( ir, le, y ); PEL *p = (PEL *) IM_REGION_ADDR( ir, r->left, r->top + y );
PEL *q = (PEL *) IM_REGION_ADDR( or, le, y ); PEL *q = (PEL *) IM_REGION_ADDR( or, r->left, r->top + y );
PEL *p1, *p2;
PEL *p1;
int hist[256]; int hist[256];
/* Find histogram for start of this line. /* Find histogram for start of this line.
*/ */
memset( hist, 0, 256 * sizeof( int ) ); memset( hist, 0, 256 * sizeof( int ) );
for( p1 = p, j = 0; j < inf->ywin; j++, p1 += lsk ) p1 = p;
for( p2 = p1, i = 0; i < inf->xwin; i++, p2++ ) for( j = 0; j < inf->ywin; j++ ) {
hist[*p2]++; for( i = 0; i < inf->xwin; i++ )
hist[p1[i]] += 1;
p1 += lsk;
}
/* Loop for output pels. /* Loop for output pels.
*/ */
for( x = le; x < ri; x++, p++ ) { for( x = 0; x < r->width; x++ ) {
/* Sum histogram up to current pel. /* Sum histogram up to current pel.
*/ */
int target = p[coff]; int target = p[centre];
int sum = 0; int sum;
for( sum = 0, i = 0; i < target; i++ ) sum = 0;
for( i = 0; i < target; i++ )
sum += hist[i]; sum += hist[i];
/* Transform. /* Transform.
*/ */
*q++ = sum * 256 / inf->npels; q[x] = sum * 256 / inf->npels;
/* Adapt histogram - remove the pels from the left hand /* Adapt histogram - remove the pels from the left hand
* column, add in pels for a new right-hand column. * column, add in pels for a new right-hand column.
*/ */
for( p1 = p, j = 0; j < inf->ywin; j++, p1 += lsk ) { p1 = p;
hist[p1[0]]--; for( j = 0; j < inf->ywin; j++ ) {
hist[p1[inf->xwin]]++; hist[p1[0]] -= 1;
hist[p1[inf->xwin]] += 1;
p1 += lsk;
} }
p += 1;
} }
} }
@ -153,22 +153,22 @@ im_lhisteq_raw( IMAGE *in, IMAGE *out, int xwin, int ywin )
{ {
LhistInfo *inf; LhistInfo *inf;
if( im_piocheck( in, out ) ) if( im_check_mono( "im_lhisteq", in ) ||
im_check_uncoded( "im_lhisteq", in ) ||
im_check_format( "im_lhisteq", in, IM_BANDFMT_UCHAR ) ||
im_piocheck( in, out ) )
return( -1 ); return( -1 );
if( in->BandFmt != IM_BANDFMT_UCHAR || if( xwin > in->Xsize ||
in->Bands != 1 || in->Coding != IM_CODING_NONE ) { ywin > in->Ysize ) {
im_error( "im_lhisteq",
"%s", _( "one band uchar uncoded only" ) );
return( -1 );
}
if( xwin > in->Xsize || ywin > in->Ysize ) {
im_error( "im_lhisteq", "%s", _( "window too large" ) ); im_error( "im_lhisteq", "%s", _( "window too large" ) );
return( -1 ); return( -1 );
} }
if( xwin <= 0 || ywin <= 0 ) { if( xwin <= 0 ||
ywin <= 0 ) {
im_error( "im_lhisteq", "%s", _( "window too small" ) ); im_error( "im_lhisteq", "%s", _( "window too small" ) );
return( -1 ); return( -1 );
} }
if( im_cp_desc( out, in ) ) if( im_cp_desc( out, in ) )
return( -1 ); return( -1 );
out->Xsize -= xwin - 1; out->Xsize -= xwin - 1;
@ -188,8 +188,6 @@ im_lhisteq_raw( IMAGE *in, IMAGE *out, int xwin, int ywin )
if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) ) if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) )
return( -1 ); return( -1 );
/* Write the hist.
*/
if( im_generate( out, if( im_generate( out,
im_start_one, lhist_gen, im_stop_one, in, inf ) ) im_start_one, lhist_gen, im_stop_one, in, inf ) )
return( -1 ); return( -1 );
@ -200,14 +198,30 @@ im_lhisteq_raw( IMAGE *in, IMAGE *out, int xwin, int ywin )
return( 0 ); return( 0 );
} }
/* The above, with a border to make out the same size as in. /**
* im_lhisteq:
* @in: input image
* @out: output image
* @xwin: width of region
* @hwin: height of region
*
* Performs local histogram equalisation on @in using a
* window of size @xwin by @ywin centered on the input pixel. Works only on
* monochrome images.
*
* The output image is the same size as the input image. The edge pixels are
* created by copy edge pixels of the input image outwards.
*
* See also: im_heq().
*
* Returns: 0 on success, -1 on error
*/ */
int int
im_lhisteq( IMAGE *in, IMAGE *out, int xwin, int ywin ) im_lhisteq( IMAGE *in, IMAGE *out, int xwin, int ywin )
{ {
IMAGE *t1 = im_open_local( out, "im_lhisteq:1", "p" ); IMAGE *t1;
if( !t1 || if( !(t1 = im_open_local( out, "im_lhisteq:1", "p" )) ||
im_embed( in, t1, 1, im_embed( in, t1, 1,
xwin / 2, ywin / 2, xwin / 2, ywin / 2,
in->Xsize + xwin - 1, in->Ysize + ywin - 1 ) || in->Xsize + xwin - 1, in->Ysize + ywin - 1 ) ||

View File

@ -1,28 +1,4 @@
/* @(#) Map an image through another image, acting as a LUT (Look Up Table). /* map though a LUT
* @(#) The lut may have any type, and the output image will be that type.
* @(#)
* @(#) The input image must be an unsigned integer types, that is, it must
* @(#) be one of IM_BANDFMT_UCHAR, IM_BANDFMT_USHORT or IM_BANDFMT_UINT.
* @(#)
* @(#) If the input is IM_BANDFMT_UCHAR, then the LUT must have 256 elements,
* @(#) in other words, lut->Xsize * lut->Ysize == 256.
* @(#)
* @(#) If the input is IM_BANDFMT_USHORT or IM_BANDFMT_UINT, then the lut
* @(#) may have any number of elements, and input pels whose value is
* @(#) greater than lut->Xsize * lut->Ysize are mapped with the last LUT
* @(#) element.
* @(#)
* @(#) If LUT has one band, then all bands of input pass through it. If LUT
* @(#) has same number of bands as input, then each band is LUTed
* @(#) separately. If input has one band, then LUT may have many bands and
* @(#) the output will have the same number of bands as the LUT.
* @(#)
* @(#) int
* @(#) im_maplut( in, out, lut )
* @(#) IMAGE *in, *out, *lut;
* @(#)
* @(#) Returns 0 on success and -1 on error
* @(#)
* *
* Modified: * Modified:
* 18/6/93 JC * 18/6/93 JC
@ -50,6 +26,9 @@
* years :-) * years :-)
* 7/11/07 * 7/11/07
* - new eval start/end system * - new eval start/end system
* 25/3/10
* - gtkdoc
* - small cleanups
*/ */
/* /*
@ -130,11 +109,11 @@ lut_end( LutInfo *st )
static LutInfo * static LutInfo *
build_luts( IMAGE *out, IMAGE *lut ) build_luts( IMAGE *out, IMAGE *lut )
{ {
LutInfo *st = IM_NEW( out, LutInfo ); LutInfo *st;
int i, x; int i, x;
PEL *q; PEL *q;
if( !st ) if( !(st = IM_NEW( out, LutInfo )) )
return( NULL ); return( NULL );
/* Make luts. We unpack the LUT image into a C 2D array to speed /* Make luts. We unpack the LUT image into a C 2D array to speed
@ -244,15 +223,15 @@ maplut_start( IMAGE *out, void *a, void *b )
for( y = to; y < bo; y++ ) { \ for( y = to; y < bo; y++ ) { \
for( z = 0; z < b; z++ ) { \ for( z = 0; z < b; z++ ) { \
PEL *p = (PEL *) IM_REGION_ADDR( ir, le, y ) + z; \ PEL *p = (PEL *) IM_REGION_ADDR( ir, le, y ) + z; \
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ) + z*2; \ OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ) + z * 2; \
OUT *tlut = (OUT *) st->table[z]; \ OUT *tlut = (OUT *) st->table[z]; \
\ \
for( x = 0; x < ne; x += b ) { \ for( x = 0; x < ne; x += b ) { \
int n = p[x]*2; \ int n = p[x] * 2; \
\ \
q[0] = tlut[n]; \ q[0] = tlut[n]; \
q[1] = tlut[n + 1]; \ q[1] = tlut[n + 1]; \
q += b*2; \ q += b * 2; \
} \ } \
} \ } \
} \ } \
@ -287,7 +266,7 @@ maplut_start( IMAGE *out, void *a, void *b )
for( y = to; y < bo; y++ ) { \ for( y = to; y < bo; y++ ) { \
for( z = 0; z < b; z++ ) { \ for( z = 0; z < b; z++ ) { \
IN *p = (IN *) IM_REGION_ADDR( ir, le, y ) + z; \ IN *p = (IN *) IM_REGION_ADDR( ir, le, y ) + z; \
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ) + z*2; \ OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ) + z * 2; \
OUT *tlut = (OUT *) st->table[z]; \ OUT *tlut = (OUT *) st->table[z]; \
\ \
for( x = 0; x < ne; x += b ) { \ for( x = 0; x < ne; x += b ) { \
@ -298,10 +277,10 @@ maplut_start( IMAGE *out, void *a, void *b )
seq->overflow++; \ seq->overflow++; \
} \ } \
\ \
q[0] = tlut[ index*2 ]; \ q[0] = tlut[index * 2]; \
q[1] = tlut[ index*2+1 ]; \ q[1] = tlut[index * 2 + 1]; \
\ \
q += b*2; \ q += b * 2; \
} \ } \
} \ } \
} \ } \
@ -378,8 +357,8 @@ maplut_start( IMAGE *out, void *a, void *b )
seq->overflow++; \ seq->overflow++; \
} \ } \
\ \
q[0] = tlut[index*2]; \ q[0] = tlut[index * 2]; \
q[1] = tlut[index*2 + 1]; \ q[1] = tlut[index * 2 + 1]; \
q += 2; \ q += 2; \
} \ } \
} \ } \
@ -465,8 +444,8 @@ maplut_start( IMAGE *out, void *a, void *b )
} \ } \
\ \
for( z = 0; z < st->nb; z++ ) { \ for( z = 0; z < st->nb; z++ ) { \
q[0] = tlut[z][n*2]; \ q[0] = tlut[z][n * 2]; \
q[1] = tlut[z][n*2 + 1]; \ q[1] = tlut[z][n * 2 + 1]; \
q += 2; \ q += 2; \
} \ } \
} \ } \
@ -481,8 +460,7 @@ maplut_start( IMAGE *out, void *a, void *b )
case IM_BANDFMT_USHORT: GEN( unsigned short, OUT ); break; \ case IM_BANDFMT_USHORT: GEN( unsigned short, OUT ); break; \
case IM_BANDFMT_UINT: GEN( unsigned int, OUT ); break; \ case IM_BANDFMT_UINT: GEN( unsigned int, OUT ); break; \
default: \ default: \
im_error( "im_maplut", "%s", _( "bad input file" ) ); \ g_assert( 0 ); \
return( -1 ); \
} }
/* Switch for LUT types. One function for non-complex images, a /* Switch for LUT types. One function for non-complex images, a
@ -512,8 +490,7 @@ maplut_start( IMAGE *out, void *a, void *b )
case IM_BANDFMT_DPCOMPLEX: inner_switch( UCHAR_FC, GEN_FC, \ case IM_BANDFMT_DPCOMPLEX: inner_switch( UCHAR_FC, GEN_FC, \
double ); break; \ double ); break; \
default: \ default: \
im_error( "im_maplut", "%s", _( "bad lut file" ) ); \ g_assert( 0 ); \
return( -1 ); \
} }
/* Do a map. /* Do a map.
@ -529,8 +506,8 @@ maplut_gen( REGION *or, void *vseq, void *a, void *b )
int le = r->left; int le = r->left;
int to = r->top; int to = r->top;
int bo = IM_RECT_BOTTOM(r); int bo = IM_RECT_BOTTOM(r);
int np = r->width; /* Pels across region */ int np = r->width; /* Pels across region */
int ne = IM_REGION_N_ELEMENTS( or ); /* Number of elements */ int ne = IM_REGION_N_ELEMENTS( or ); /* Number of elements */
int x, y, z, i; int x, y, z, i;
/* Get input ready. /* Get input ready.
@ -557,51 +534,49 @@ maplut_gen( REGION *or, void *vseq, void *a, void *b )
return( 0 ); return( 0 );
} }
/**
* im_maplut:
* @in: input image
* @out: output image
* @lut: look-up table
*
* Map an image through another image acting as a LUT (Look Up Table).
* The lut may have any type, and the output image will be that type.
*
* The input image must be an unsigned integer types, that is, it must
* be one of IM_BANDFMT_UCHAR, IM_BANDFMT_USHORT or IM_BANDFMT_UINT.
*
* If @lut is too small for the input type (for example, if @in is
* IM_BANDFMT_UCHAR but @lut only has 100 elements), the lut is padded out
* by copying the last element. Overflows are reported at the end of
* computation.
* If @lut is too large, extra values are ignored.
*
* If @lut has one band, then all bands of @in pass through it. If @lut
* has same number of bands as @in, then each band is mapped
* separately. If @in has one band, then @lut may have many bands and
* the output will have the same number of bands as @lut.
*
* See also: im_histgr(), im_identity().
*
* Returns: 0 on success, -1 on error
*/
int int
im_maplut( IMAGE *in, IMAGE *out, IMAGE *lut ) im_maplut( IMAGE *in, IMAGE *out, IMAGE *lut )
{ {
LutInfo *st; LutInfo *st;
/* Check lut.
*/
if( lut->Coding != IM_CODING_NONE ) {
im_error( "im_maplut", "%s", _( "lut is not uncoded" ) );
return( -1 );
}
if( lut->Xsize * lut->Ysize > 100000 ) {
im_error( "im_maplut", "%s", _( "lut seems very large!" ) );
return( -1 );
}
/* Check input output. Old-style IO from lut, for simplicity. /* Check input output. Old-style IO from lut, for simplicity.
*/ */
if( im_piocheck( in, out ) || im_incheck( lut ) ) if( im_check_hist( "im_maplut", lut ) ||
im_check_uncoded( "im_maplut", lut ) ||
im_check_uncoded( "im_maplut", in ) ||
im_check_bands_1orn( "im_maplut", in, lut ) ||
im_check_uint( "im_maplut", in ) ||
im_piocheck( in, out ) ||
im_incheck( lut ) )
return( -1 ); return( -1 );
/* Check args.
*/
if( in->Coding != IM_CODING_NONE ) {
im_error( "im_maplut", "%s", _( "input is not uncoded" ) );
return( -1 );
}
if( !vips_bandfmt_isuint( in->BandFmt ) ) {
im_error( "im_maplut", "%s",
_( "input is not some unsigned integer type" ) );
return( -1 );
}
if( in->Bands != 1 && lut->Bands != 1 && lut->Bands != in->Bands ) {
im_error( "im_maplut", "%s", _( "lut should have 1 band, "
"or same number of bands as input, "
"or any number of bands if input has 1 band" ) );
return( -1 );
}
if( in->BandFmt == IM_BANDFMT_UCHAR &&
lut->Xsize * lut->Ysize != 256 ) {
im_error( "im_maplut", "%s", _( "input is uchar and lut "
"does not have 256 elements" ) );
return( -1 );
}
/* Prepare the output header. /* Prepare the output header.
*/ */
if( im_cp_descv( out, in, lut, NULL ) ) if( im_cp_descv( out, in, lut, NULL ) )

View File

@ -1,19 +1,4 @@
/* @(#) Function which returns an int. This integer is the threshold /* find percent of pixels
* @(#) above which there are percent values of the input images
* @(#) If for instance precent=.1, the number of pels of the input image
* @(#) with values greater than the returned int will correspond to
* @(#) 10% of all pels of the image.
* @(#) One band IM_BANDFMT_UCHAR images only.
* @(#)
* @(#) Function im_mpercent() assumes that input
* @(#) is either memory mapped or in a buffer.
* @(#)
* @(#) int im_percent(in, percent)
* @(#) IMAGE *in;
* @(#) double percent;
* @(#)
* @(#) Returns 0 on success and -1 on error
*
* Copyright: 1990, N. Dessipris * Copyright: 1990, N. Dessipris
* *
* Author: N. Dessipris * Author: N. Dessipris
@ -24,6 +9,8 @@
* - ANSIfied a little * - ANSIfied a little
* 19/1/07 * 19/1/07
* - redone with the vips hist operators * - redone with the vips hist operators
* 25/3/10
* - gtkdoc
*/ */
/* /*
@ -66,8 +53,23 @@
#include <dmalloc.h> #include <dmalloc.h>
#endif /*WITH_DMALLOC*/ #endif /*WITH_DMALLOC*/
/* What threshold will select a specified percentage of the pixels in the /**
* image. * im_mpercent:
* @in: input image
* @percent: threshold percentage
* @out: output threshold value
*
* im_mpercent() returns (through the @out parameter) the threshold above
* which there are @percent values of @in. If for example percent=.1, the
* number of pels of the input image with values greater than the returned
* int will correspond to 10% of all pels of the image.
*
* The function works for uchar and ushort images only. It can be used
* to threshold the scaled result of a filtering operation.
*
* See also: im_histgr(), im_profile().
*
* Returns: 0 on success, -1 on error
*/ */
int int
im_mpercent( IMAGE *in, double percent, int *out ) im_mpercent( IMAGE *in, double percent, int *out )