convolution docs
This commit is contained in:
parent
97cc8327ca
commit
2932f383bc
@ -37,11 +37,11 @@
|
|||||||
<xi:include href="xml/relational.xml"/>
|
<xi:include href="xml/relational.xml"/>
|
||||||
<xi:include href="xml/colour.xml"/>
|
<xi:include href="xml/colour.xml"/>
|
||||||
<xi:include href="xml/conversion.xml"/>
|
<xi:include href="xml/conversion.xml"/>
|
||||||
|
<xi:include href="xml/convolution.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter>
|
<chapter>
|
||||||
<title>VIPS operation API by section (no gtkdoc comments yet)</title>
|
<title>VIPS operation API by section (no gtkdoc comments yet)</title>
|
||||||
<xi:include href="xml/convolution.xml"/>
|
|
||||||
<xi:include href="xml/format.xml"/>
|
<xi:include href="xml/format.xml"/>
|
||||||
<xi:include href="xml/morphology.xml"/>
|
<xi:include href="xml/morphology.xml"/>
|
||||||
<xi:include href="xml/resample.xml"/>
|
<xi:include href="xml/resample.xml"/>
|
||||||
|
@ -105,7 +105,7 @@ gnoise_gen( REGION *or, void *seq, void *a, void *b )
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* im_gaussnoise:
|
* im_gaussnoise:
|
||||||
* @out: output #IMAGE
|
* @out: output image
|
||||||
* @x: output width
|
* @x: output width
|
||||||
* @y: output height
|
* @y: output height
|
||||||
* @mean: average value in output
|
* @mean: average value in output
|
||||||
@ -115,7 +115,7 @@ gnoise_gen( REGION *or, void *seq, void *a, void *b )
|
|||||||
* distribution. The noise distribution is created by averaging 12 random
|
* distribution. The noise distribution is created by averaging 12 random
|
||||||
* numbers with the appropriate weights.
|
* numbers with the appropriate weights.
|
||||||
*
|
*
|
||||||
* See also: im_make_xy(), im_text(), im_black().
|
* See also: im_addgnoise(), im_make_xy(), im_text(), im_black().
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -1 on error
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
|
@ -113,6 +113,15 @@ system_image( IMAGE *im,
|
|||||||
*
|
*
|
||||||
* In all cases, @log must be freed with im_free().
|
* In all cases, @log must be freed with im_free().
|
||||||
*
|
*
|
||||||
|
* For example, this call will run the ImageMagick convert program on an
|
||||||
|
* image, using JPEG files to pass images into and out of the convert command.
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* im_system_image( in, out,
|
||||||
|
* "%s.jpg", "%s.jpg", "convert %s -swirl 45 %s",
|
||||||
|
* &log )
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
* See also: im_system().
|
* See also: im_system().
|
||||||
*
|
*
|
||||||
* Returns: an image on success, NULL on error
|
* Returns: an image on success, NULL on error
|
||||||
|
@ -1,15 +1,4 @@
|
|||||||
/* @(#) Add gaussian noise with mean 0 and variance sigma to image
|
/* im_addgnoise
|
||||||
* @(#) The noise is generated by averaging 12 random numbers
|
|
||||||
* @(#) page 78 PIETGEN 1989 n = 12
|
|
||||||
* @(#) Input image is any, output is float
|
|
||||||
* @(#) If running on SYSTEM V CONSTANT should be replaced by 2**15 - 1
|
|
||||||
* @(#) Usage
|
|
||||||
* @(#)
|
|
||||||
* @(#) int im_addgnoise(imin, imout, sigma)
|
|
||||||
* @(#) IMAGE *imin, *imout;
|
|
||||||
* @(#) double sigma;
|
|
||||||
* @(#) Returns 0 on success and -1 on error
|
|
||||||
* @(#)
|
|
||||||
*
|
*
|
||||||
* Copyright 1990, N. Dessipris.
|
* Copyright 1990, N. Dessipris.
|
||||||
*
|
*
|
||||||
@ -26,6 +15,9 @@
|
|||||||
* 2008-01-28 tcv:
|
* 2008-01-28 tcv:
|
||||||
* - now works (was broken)
|
* - now works (was broken)
|
||||||
* - no limit on bands
|
* - no limit on bands
|
||||||
|
* 4/2/10
|
||||||
|
* - no need to bandup here now, im_add() does that
|
||||||
|
* - gtkdoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -66,25 +58,29 @@
|
|||||||
#include <dmalloc.h>
|
#include <dmalloc.h>
|
||||||
#endif /*WITH_DMALLOC*/
|
#endif /*WITH_DMALLOC*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_addgnoise:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @sigma: standard deviation of noise
|
||||||
|
*
|
||||||
|
* Add gaussian noise with mean 0 and variance sigma to @in.
|
||||||
|
* The noise is generated by averaging 12 random numbers,
|
||||||
|
* see page 78, PIETGEN, 1989.
|
||||||
|
*
|
||||||
|
* See also: im_gaussnoise().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
im_addgnoise( IMAGE *in, IMAGE *out, double sigma ){
|
im_addgnoise( IMAGE *in, IMAGE *out, double sigma )
|
||||||
#define FUNCTION_NAME "im_addgnoise"
|
{
|
||||||
|
IMAGE *t;
|
||||||
|
|
||||||
if( im_piocheck( in, out ))
|
if( !(t = im_open_local( out, "im_addgnoise", "p" )) ||
|
||||||
return -1;
|
im_gaussnoise( t, in->Xsize, in->Ysize, 0, sigma ) ||
|
||||||
{
|
im_add( in, t, out ) )
|
||||||
int i;
|
return( -1 );
|
||||||
IMAGE **temps= IM_ARRAY( out, in-> Bands, IMAGE* );
|
|
||||||
IMAGE *joined_temps= im_open_local( out, FUNCTION_NAME ": joined_temps", "p" );
|
|
||||||
|
|
||||||
if( ! temps || ! joined_temps || im_open_local_array( out, temps, in-> Bands, FUNCTION_NAME ": temps", "p" ))
|
return( 0 );
|
||||||
return -1;
|
|
||||||
|
|
||||||
for( i= 0; i < in-> Bands; ++i )
|
|
||||||
if( im_gaussnoise( temps[i], in-> Xsize, in-> Ysize, 0.0, sigma ))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return im_gbandjoin( temps, joined_temps, in-> Bands ) || im_add( in, joined_temps, out );
|
|
||||||
}
|
|
||||||
#undef FUNCTION_NAME
|
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,12 @@
|
|||||||
/* @(#) im_complass: Optimised convolution for line detection
|
/* im_compass
|
||||||
* @(#) Uses the entered mask and 7 rotated versions of it (each by 45 degrees)
|
|
||||||
* @(#)
|
|
||||||
* @(#) Usage
|
|
||||||
* @(#) int im_compass( in, out, m )
|
|
||||||
* @(#) IMAGE *in, *out;
|
|
||||||
* @(#) INTMASK *m;
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns 0 on sucess and -1 on error
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns an int pointer to valid offsets for rotating a square mask
|
|
||||||
* @(#) of odd size by 45 degrees.
|
|
||||||
* @(#)
|
|
||||||
* @(#) Usage
|
|
||||||
* @(#) int *im_offsets45( size )
|
|
||||||
* @(#) int size;
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns an int pointer to valid offsets on sucess and -1 on error
|
|
||||||
* @(#)
|
|
||||||
*
|
*
|
||||||
* Author: N. Dessipris (Copyright, N. Dessipris 1991)
|
* Author: N. Dessipris (Copyright, N. Dessipris 1991)
|
||||||
* Written on: 08/05/1991
|
* Written on: 08/05/1991
|
||||||
* Modified on:
|
* Modified on:
|
||||||
* 11/3/01 JC
|
* 11/3/01 JC
|
||||||
* - rewritten, calling im_conv() and im_maxvalue()
|
* - rewritten, calling im_conv() and im_maxvalue()
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -67,6 +51,20 @@
|
|||||||
#include <dmalloc.h>
|
#include <dmalloc.h>
|
||||||
#endif /*WITH_DMALLOC*/
|
#endif /*WITH_DMALLOC*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_compass:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask: convolution mask
|
||||||
|
*
|
||||||
|
* @in is convolved 8 times with @mask, each time @mask is rotated by 45
|
||||||
|
* degrees. Each output pixel is the largest absolute value of the 8
|
||||||
|
* convolutions.
|
||||||
|
*
|
||||||
|
* See also: im_lindetect(), im_gradient(), im_conv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
im_compass( IMAGE *in, IMAGE *out, INTMASK *mask )
|
im_compass( IMAGE *in, IMAGE *out, INTMASK *mask )
|
||||||
{
|
{
|
||||||
@ -94,6 +92,20 @@ im_compass( IMAGE *in, IMAGE *out, INTMASK *mask )
|
|||||||
return( im_maxvalue( absed, out, 8 ) );
|
return( im_maxvalue( absed, out, 8 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_lindetect:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask: convolution mask
|
||||||
|
*
|
||||||
|
* @in is convolved four times with @mask, each time @mask is rotated by 45
|
||||||
|
* degrees. Each output pixel is the largest absolute value of the four
|
||||||
|
* convolutions.
|
||||||
|
*
|
||||||
|
* See also: im_compass(), im_gradient(), im_conv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
im_lindetect( IMAGE *in, IMAGE *out, INTMASK *mask )
|
im_lindetect( IMAGE *in, IMAGE *out, INTMASK *mask )
|
||||||
{
|
{
|
||||||
@ -121,15 +133,26 @@ im_lindetect( IMAGE *in, IMAGE *out, INTMASK *mask )
|
|||||||
return( im_maxvalue( absed, out, 4 ) );
|
return( im_maxvalue( absed, out, 4 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GTEMPS (4)
|
/**
|
||||||
|
* im_gradient:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask: convolution mask
|
||||||
|
*
|
||||||
|
* @in is convolved with @mask and with @mask after a 90 degree rotation. The
|
||||||
|
* result is the sum of the absolute value of the two convolutions.
|
||||||
|
*
|
||||||
|
* See also: im_lindetect(), im_gradient(), im_conv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
im_gradient( IMAGE *in, IMAGE *out, INTMASK *mask )
|
im_gradient( IMAGE *in, IMAGE *out, INTMASK *mask )
|
||||||
{
|
{
|
||||||
IMAGE *t[GTEMPS];
|
IMAGE *t[4];
|
||||||
INTMASK *rmask;
|
INTMASK *rmask;
|
||||||
|
|
||||||
if( im_open_local_array( out, t, GTEMPS, "im_gradient", "p" ) )
|
if( im_open_local_array( out, t, 4, "im_gradient", "p" ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( !(rmask = (INTMASK *) im_local( out,
|
if( !(rmask = (INTMASK *) im_local( out,
|
||||||
|
@ -1,27 +1,4 @@
|
|||||||
/* @(#) Generate an image where the value of each pixel represents the
|
/* im_contrast_surface
|
||||||
* @(#) contrast within a window of half_win_size from the corresponsing
|
|
||||||
* @(#) point in the input image. Sub-sample by a factor of spacing.
|
|
||||||
* @(#)
|
|
||||||
* @(#) Pixels beyond the edges of the image are considered to be have the
|
|
||||||
* @(#) value zero (black).
|
|
||||||
* @(#)
|
|
||||||
* @(#) Input must be single-band uncoded uchar, WIO or PIO.
|
|
||||||
* @(#)
|
|
||||||
* @(#) Output is single-band uncoded uint, WIO or PIO.
|
|
||||||
* @(#)
|
|
||||||
* @(#) int
|
|
||||||
* @(#) im_contrast_surface(
|
|
||||||
* @(#) IMAGE *in,
|
|
||||||
* @(#) IMAGE *out,
|
|
||||||
* @(#) int half_win_size,
|
|
||||||
* @(#) int spacing
|
|
||||||
* @(#) );
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns either 0 (success) or -1 (fail)
|
|
||||||
* @(#)
|
|
||||||
* @(#) Also: im_contrast_surface_raw(). As above, but pixels within
|
|
||||||
* @(#) half_win_size of the edge are not calculated, and output is smaller
|
|
||||||
* @(#) accordingly.
|
|
||||||
*
|
*
|
||||||
* Copyright: 2006, The Nottingham Trent University
|
* Copyright: 2006, The Nottingham Trent University
|
||||||
*
|
*
|
||||||
@ -29,6 +6,9 @@
|
|||||||
* (based on algorithm by Nicos Dessipris & John Cupitt)
|
* (based on algorithm by Nicos Dessipris & John Cupitt)
|
||||||
*
|
*
|
||||||
* Written on: 2006-03-13
|
* Written on: 2006-03-13
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - small cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -111,6 +91,21 @@ static unsigned int calc_cont (REGION * reg, int win_size_less_one,
|
|||||||
|
|
||||||
/** EXPORTED FUNCTIONS **/
|
/** EXPORTED FUNCTIONS **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_contrast_surface:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @half_win_size: window radius
|
||||||
|
* @spacing: subsample output by this
|
||||||
|
*
|
||||||
|
* Generate an image where the value of each pixel represents the
|
||||||
|
* contrast within a window of half_win_size from the corresponsing
|
||||||
|
* point in the input image. Sub-sample by a factor of spacing.
|
||||||
|
*
|
||||||
|
* See also: im_spcor(), im_gradcor().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
im_contrast_surface (IMAGE * in, IMAGE * out, int half_win_size, int spacing)
|
im_contrast_surface (IMAGE * in, IMAGE * out, int half_win_size, int spacing)
|
||||||
{
|
{
|
||||||
@ -138,16 +133,12 @@ im_contrast_surface_raw (IMAGE * in, IMAGE * out, int half_win_size,
|
|||||||
|
|
||||||
cont_surf_params_t *params;
|
cont_surf_params_t *params;
|
||||||
|
|
||||||
if (im_piocheck (in, out))
|
if (im_piocheck (in, out) ||
|
||||||
|
im_check_uncoded (FUNCTION_NAME, in) ||
|
||||||
|
im_check_mono (FUNCTION_NAME, in) ||
|
||||||
|
im_check_format (FUNCTION_NAME, in, IM_BANDFMT_UCHAR))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (IM_CODING_NONE != in->Coding || IM_BANDFMT_UCHAR != in->BandFmt
|
|
||||||
|| 1 != in->Bands)
|
|
||||||
{
|
|
||||||
im_error (FUNCTION_NAME, "%s", _("one band uncoded uchar only"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (half_win_size < 1 || spacing < 1)
|
if (half_win_size < 1 || spacing < 1)
|
||||||
{
|
{
|
||||||
im_error (FUNCTION_NAME, "%s", _("bad parameters"));
|
im_error (FUNCTION_NAME, "%s", _("bad parameters"));
|
||||||
|
@ -1,27 +1,4 @@
|
|||||||
/* @(#) Convolve an image with an INTMASK. Image can have any number of bands,
|
/* im_conv
|
||||||
* @(#) any non-complex type. Size and type of output image matches type of
|
|
||||||
* @(#) input image.
|
|
||||||
* @(#)
|
|
||||||
* @(#) int
|
|
||||||
* @(#) im_conv( in, out, mask )
|
|
||||||
* @(#) IMAGE *in, *out;
|
|
||||||
* @(#) INTMASK *mask;
|
|
||||||
* @(#)
|
|
||||||
* @(#) Also: im_conv_raw(). As above, but does not add a black border.
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns either 0 (success) or -1 (fail)
|
|
||||||
* @(#)
|
|
||||||
* @(#) Old code, kept for use of other old code in this package:
|
|
||||||
* @(#)
|
|
||||||
* @(#) Creates int luts for all non zero elm of the original mask;
|
|
||||||
* @(#) which is kept in buffer of length buffersize
|
|
||||||
* @(#) cnt is needed for freeing luts. Called by the above.
|
|
||||||
* @(#)
|
|
||||||
* @(#) int im__create_int_luts( buffer, buffersize, orig_luts, luts, cnt )
|
|
||||||
* @(#) int *buffer, buffersize;
|
|
||||||
* @(#) int **orig_luts, **luts, *cnt;
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns either 0 (sucess) or -1 (fail)
|
|
||||||
*
|
*
|
||||||
* Copyright: 1990, N. Dessipris.
|
* Copyright: 1990, N. Dessipris.
|
||||||
*
|
*
|
||||||
@ -71,6 +48,9 @@
|
|||||||
* - only check for non-zero elements once
|
* - only check for non-zero elements once
|
||||||
* - add mask-all-zero check
|
* - add mask-all-zero check
|
||||||
* - cleanups
|
* - cleanups
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - more cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -285,7 +265,7 @@ conv_start( IMAGE *out, void *a, void *b )
|
|||||||
i += 1; \
|
i += 1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* INT and FLOAT inner loops.
|
/* INT inner loops.
|
||||||
*/
|
*/
|
||||||
#define CONV_INT( TYPE, IM_CLIP ) { \
|
#define CONV_INT( TYPE, IM_CLIP ) { \
|
||||||
TYPE ** restrict p = (TYPE **) seq->pts; \
|
TYPE ** restrict p = (TYPE **) seq->pts; \
|
||||||
@ -307,6 +287,8 @@ conv_start( IMAGE *out, void *a, void *b )
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FLOAT inner loops.
|
||||||
|
*/
|
||||||
#define CONV_FLOAT( TYPE ) { \
|
#define CONV_FLOAT( TYPE ) { \
|
||||||
TYPE ** restrict p = (TYPE **) seq->pts; \
|
TYPE ** restrict p = (TYPE **) seq->pts; \
|
||||||
TYPE * restrict q = (TYPE *) IM_REGION_ADDR( or, le, y ); \
|
TYPE * restrict q = (TYPE *) IM_REGION_ADDR( or, le, y ); \
|
||||||
@ -434,14 +416,9 @@ im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
|
|||||||
*/
|
*/
|
||||||
if( im_piocheck( in, out ) ||
|
if( im_piocheck( in, out ) ||
|
||||||
im_check_uncoded( "im_conv", in ) ||
|
im_check_uncoded( "im_conv", in ) ||
|
||||||
im_check_noncomplex( "im_conv", in ) )
|
im_check_noncomplex( "im_conv", in ) ||
|
||||||
|
im_check_imask( "im_conv", mask ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
if( !mask || mask->xsize > 1000 || mask->ysize > 1000 ||
|
|
||||||
mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff ||
|
|
||||||
mask->scale == 0 ) {
|
|
||||||
im_error( "im_conv", "%s", _( "nonsense mask parameters" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
if( !(conv = conv_new( in, out, mask )) )
|
if( !(conv = conv_new( in, out, mask )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -460,10 +437,8 @@ im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
|
|||||||
/* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
|
/* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
|
||||||
* too many recalculations on overlaps.
|
* too many recalculations on overlaps.
|
||||||
*/
|
*/
|
||||||
if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) )
|
if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) ||
|
||||||
return( -1 );
|
im_generate( out, conv_start, conv_gen, conv_stop, in, conv ) )
|
||||||
|
|
||||||
if( im_generate( out, conv_start, conv_gen, conv_stop, in, conv ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
out->Xoffset = -mask->xsize / 2;
|
out->Xoffset = -mask->xsize / 2;
|
||||||
@ -472,7 +447,24 @@ im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The above, with a border to make out the same size as in.
|
/**
|
||||||
|
* im_conv:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask: convolution mask
|
||||||
|
*
|
||||||
|
* Convolve @in with @mask using integer arithmetic. The output image
|
||||||
|
* always has the same #VipsBandFmt as the input image. Non-complex images
|
||||||
|
* only.
|
||||||
|
*
|
||||||
|
* Each output pixel is
|
||||||
|
* calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale
|
||||||
|
* and offset are part of @mask. For integer @in, the division by scale
|
||||||
|
* includes round-to-nearest.
|
||||||
|
*
|
||||||
|
* See also: im_conv_f(), im_convsep(), im_create_imaskv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
im_conv( IMAGE *in, IMAGE *out, INTMASK *mask )
|
im_conv( IMAGE *in, IMAGE *out, INTMASK *mask )
|
||||||
|
@ -1,14 +1,4 @@
|
|||||||
/* @(#) Convolve an image with a DOUBLEMASK. Image can have any number of bands,
|
/* im_conv_f
|
||||||
* @(#) any non-complex type. Output is IM_BANDFMT_FLOAT for all non-complex inputs
|
|
||||||
* @(#) except IM_BANDFMT_DOUBLE, which gives IM_BANDFMT_DOUBLE.
|
|
||||||
* @(#)
|
|
||||||
* @(#) int
|
|
||||||
* @(#) im_conv_f( in, out, mask )
|
|
||||||
* @(#) IMAGE *in, *out;
|
|
||||||
* @(#) DOUBLEMASK *mask;
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns either 0 (success) or -1 (fail)
|
|
||||||
* @(#)
|
|
||||||
*
|
*
|
||||||
* Copyright: 1990, N. Dessipris.
|
* Copyright: 1990, N. Dessipris.
|
||||||
*
|
*
|
||||||
@ -43,6 +33,9 @@
|
|||||||
* 13/11/09
|
* 13/11/09
|
||||||
* - rename as im_conv_f() to make it easier to vips.c to make the
|
* - rename as im_conv_f() to make it easier to vips.c to make the
|
||||||
* overloaded version
|
* overloaded version
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - more cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -320,14 +313,9 @@ im_conv_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|||||||
*/
|
*/
|
||||||
if( im_piocheck( in, out ) ||
|
if( im_piocheck( in, out ) ||
|
||||||
im_check_uncoded( "im_conv", in ) ||
|
im_check_uncoded( "im_conv", in ) ||
|
||||||
im_check_noncomplex( "im_conv", in ) )
|
im_check_noncomplex( "im_conv", in ) ||
|
||||||
|
im_check_dmask( "im_conv", mask ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
if( !mask || mask->xsize > 1000 || mask->ysize > 1000 ||
|
|
||||||
mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff ||
|
|
||||||
mask->scale == 0 ) {
|
|
||||||
im_error( "im_conv", "%s", _( "nonsense mask parameters" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
if( !(conv = conv_new( in, out, mask )) )
|
if( !(conv = conv_new( in, out, mask )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -360,7 +348,24 @@ im_conv_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The above, with a border to make out the same size as in.
|
/**
|
||||||
|
* im_conv_f:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask: convolution mask
|
||||||
|
*
|
||||||
|
* Convolve @in with @mask using floating-point arithmetic. The output image
|
||||||
|
* is always %IM_BANDFMT_FLOAT unless @in is %IM_BANDFMT_DOUBLE, in which case
|
||||||
|
* @out is also %IM_BANDFMT_DOUBLE. Non-complex images
|
||||||
|
* only.
|
||||||
|
*
|
||||||
|
* Each output pixel is
|
||||||
|
* calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale
|
||||||
|
* and offset are part of @mask.
|
||||||
|
*
|
||||||
|
* See also: im_conv(), im_convsep_f(), im_create_dmaskv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
im_conv_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
im_conv_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
||||||
|
@ -1,15 +1,4 @@
|
|||||||
/* @(#) Convolve an image with a seperable (1xN, or Nx1) INTMASK. Image can
|
/* im_convsep
|
||||||
* @(#) have any number of bands, any non-complex type. Size and type of
|
|
||||||
* @(#) output image matches type of input image.
|
|
||||||
* @(#)
|
|
||||||
* @(#) int
|
|
||||||
* @(#) im_convsep( in, out, mask )
|
|
||||||
* @(#) IMAGE *in, *out;
|
|
||||||
* @(#) INTMASK *mask;
|
|
||||||
* @(#)
|
|
||||||
* @(#) Also: im_convsep_raw(). As above, but does not add a black border.
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns either 0 (success) or -1 (fail)
|
|
||||||
*
|
*
|
||||||
* Copyright: 1990, N. Dessipris.
|
* Copyright: 1990, N. Dessipris.
|
||||||
*
|
*
|
||||||
@ -29,6 +18,9 @@
|
|||||||
* overflow on intermediates
|
* overflow on intermediates
|
||||||
* 12/5/08
|
* 12/5/08
|
||||||
* - int rounding was +1 too much, argh
|
* - int rounding was +1 too much, argh
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - more cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -379,24 +371,16 @@ im_convsep_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
|
|||||||
|
|
||||||
/* Check parameters.
|
/* Check parameters.
|
||||||
*/
|
*/
|
||||||
if( !in || in->Coding != IM_CODING_NONE ||
|
if( im_piocheck( in, out ) ||
|
||||||
vips_bandfmt_iscomplex( in->BandFmt ) ) {
|
im_check_uncoded( "im_convsep", in ) ||
|
||||||
im_error( "im_convsep", "%s", _( "non-complex uncoded only" ) );
|
im_check_noncomplex( "im_convsep", in ) ||
|
||||||
|
im_check_imask( "im_convsep", mask ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
if( !mask || mask->xsize > 1000 || mask->ysize > 1000 ||
|
|
||||||
mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff ||
|
|
||||||
mask->scale == 0 ) {
|
|
||||||
im_error( "im_convsep", "%s", _( "nonsense mask parameters" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
if( mask->xsize != 1 && mask->ysize != 1 ) {
|
if( mask->xsize != 1 && mask->ysize != 1 ) {
|
||||||
im_error( "im_convsep",
|
im_error( "im_convsep",
|
||||||
"%s", _( "expect 1xN or Nx1 input mask" ) );
|
"%s", _( "expect 1xN or Nx1 input mask" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
if( im_piocheck( in, out ) )
|
|
||||||
return( -1 );
|
|
||||||
if( !(conv = conv_new( in, out, mask )) )
|
if( !(conv = conv_new( in, out, mask )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -424,7 +408,32 @@ im_convsep_raw( IMAGE *in, IMAGE *out, INTMASK *mask )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The above, with a border to make out the same size as in.
|
|
||||||
|
/**
|
||||||
|
* im_convsep:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask: convolution mask
|
||||||
|
*
|
||||||
|
* Perform a separable convolution of @in with @mask using integer arithmetic.
|
||||||
|
*
|
||||||
|
* The mask must be 1xn or nx1 elements.
|
||||||
|
* The output image
|
||||||
|
* always has the same #VipsBandFmt as the input image. Non-complex images
|
||||||
|
* only.
|
||||||
|
*
|
||||||
|
* The image is convolved twice: once with @mask and then again with @mask
|
||||||
|
* rotated by 90 degrees. This is much faster for certain types of mask
|
||||||
|
* (gaussian blur, for example) than doing a full 2D convolution.
|
||||||
|
*
|
||||||
|
* Each output pixel is
|
||||||
|
* calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale
|
||||||
|
* and offset are part of @mask. For integer @in, the division by scale
|
||||||
|
* includes round-to-nearest.
|
||||||
|
*
|
||||||
|
* See also: im_convsep_f(), im_conv(), im_create_imaskv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
im_convsep( IMAGE *in, IMAGE *out, INTMASK *mask )
|
im_convsep( IMAGE *in, IMAGE *out, INTMASK *mask )
|
||||||
|
@ -1,14 +1,4 @@
|
|||||||
/* @(#) Convolve an image with a DOUBLEMASK. Image can have any number of bands,
|
/* im_convsep_f
|
||||||
* @(#) any non-complex type. Output is IM_BANDFMT_FLOAT for all non-complex inputs
|
|
||||||
* @(#) except IM_BANDFMT_DOUBLE, which gives IM_BANDFMT_DOUBLE.
|
|
||||||
* @(#) Separable mask of sizes 1xN or Nx1
|
|
||||||
* @(#)
|
|
||||||
* @(#) int im_convsep_f( in, out, mask )
|
|
||||||
* @(#) IMAGE *in, *out;
|
|
||||||
* @(#) DOUBLEMASK *mask; details in mask.h
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns either 0 (sucess) or -1 (fail)
|
|
||||||
* @(#) Picture can have any number of channels (max 64).
|
|
||||||
*
|
*
|
||||||
* Copyright: 1990, N. Dessipris.
|
* Copyright: 1990, N. Dessipris.
|
||||||
*
|
*
|
||||||
@ -21,6 +11,9 @@
|
|||||||
* - now uses im_embed() with edge stretching on the input, not
|
* - now uses im_embed() with edge stretching on the input, not
|
||||||
* the output
|
* the output
|
||||||
* - sets Xoffset / Yoffset
|
* - sets Xoffset / Yoffset
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - more cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -81,10 +74,7 @@ typedef struct {
|
|||||||
static int
|
static int
|
||||||
conv_destroy( Conv *conv )
|
conv_destroy( Conv *conv )
|
||||||
{
|
{
|
||||||
if( conv->mask ) {
|
IM_FREEF( im_free_dmask, conv->mask );
|
||||||
(void) im_free_dmask( conv->mask );
|
|
||||||
conv->mask = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -285,26 +275,16 @@ im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|||||||
|
|
||||||
/* Check parameters.
|
/* Check parameters.
|
||||||
*/
|
*/
|
||||||
if( !in ||
|
if( im_piocheck( in, out ) ||
|
||||||
in->Coding != IM_CODING_NONE ||
|
im_check_uncoded( "im_convsep_f", in ) ||
|
||||||
vips_bandfmt_iscomplex( in->BandFmt ) ) {
|
im_check_noncomplex( "im_convsep_f", in ) ||
|
||||||
im_error( "im_convsep_f",
|
im_check_dmask( "im_convsep_f", mask ) )
|
||||||
"%s", _( "non-complex uncoded only" ) );
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
if( !mask || mask->xsize > 1000 || mask->ysize > 1000 ||
|
|
||||||
mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff ||
|
|
||||||
mask->scale == 0 ) {
|
|
||||||
im_error( "im_convsep_f", "%s", _( "bad mask parameters" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
if( mask->xsize != 1 && mask->ysize != 1 ) {
|
if( mask->xsize != 1 && mask->ysize != 1 ) {
|
||||||
im_error( "im_convsep_f",
|
im_error( "im_convsep_f",
|
||||||
"%s", _( "expect 1xN or Nx1 input mask" ) );
|
"%s", _( "expect 1xN or Nx1 input mask" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
if( im_piocheck( in, out ) )
|
|
||||||
return( -1 );
|
|
||||||
if( !(conv = conv_new( in, out, mask )) )
|
if( !(conv = conv_new( in, out, mask )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -335,7 +315,32 @@ im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The above, with a border to make out the same size as in.
|
/**
|
||||||
|
* im_convsep_f:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask: convolution mask
|
||||||
|
*
|
||||||
|
* Perform a separable convolution of @in with @mask using floating-point
|
||||||
|
* arithmetic.
|
||||||
|
*
|
||||||
|
* The mask must be 1xn or nx1 elements.
|
||||||
|
* The output image
|
||||||
|
* is always %IM_BANDFMT_FLOAT unless @in is %IM_BANDFMT_DOUBLE, in which case
|
||||||
|
* @out is also %IM_BANDFMT_DOUBLE. Non-complex images
|
||||||
|
* only.
|
||||||
|
*
|
||||||
|
* The image is convolved twice: once with @mask and then again with @mask
|
||||||
|
* rotated by 90 degrees. This is much faster for certain types of mask
|
||||||
|
* (gaussian blur, for example) than doing a full 2D convolution.
|
||||||
|
*
|
||||||
|
* Each output pixel is
|
||||||
|
* calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale
|
||||||
|
* and offset are part of @mask.
|
||||||
|
*
|
||||||
|
* See also: im_convsep(), im_conv(), im_create_dmaskv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
im_convsep_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
im_convsep_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
||||||
|
@ -1,19 +1,4 @@
|
|||||||
/* @(#) Functions which calculates spatial correlation between two images.
|
/* im_fastcor
|
||||||
* @(#) by taking absolute differences pixel by pixel without calculating
|
|
||||||
* @(#) the correlation coefficient.
|
|
||||||
* @(#)
|
|
||||||
* @(#) The function works as follows:
|
|
||||||
* @(#)
|
|
||||||
* @(#) int im_fastcor( im, ref, out )
|
|
||||||
* @(#) IMAGE *im, *ref, *out;
|
|
||||||
* @(#)
|
|
||||||
* @(#) ref must be smaller than in. The correlation is
|
|
||||||
* @(#) calculated by overlaping im on the top left corner of ref
|
|
||||||
* @(#) and moving it all over ref calculating the correlation coefficient
|
|
||||||
* @(#) at each point. The resultant coefficients are written as unsigned int
|
|
||||||
* @(#) numbers in out which has the size of im.
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns 0 on sucess and -1 on error.
|
|
||||||
*
|
*
|
||||||
* Copyright: 1990, N. Dessipris.
|
* Copyright: 1990, N. Dessipris.
|
||||||
*
|
*
|
||||||
@ -34,6 +19,9 @@
|
|||||||
* - use im_embed() with edge stretching on the input, not the output
|
* - use im_embed() with edge stretching on the input, not the output
|
||||||
* - calculate sum of squares of differences, rather than abs of
|
* - calculate sum of squares of differences, rather than abs of
|
||||||
* difference
|
* difference
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -142,7 +130,8 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|||||||
{
|
{
|
||||||
/* PIO between in and out; WIO from ref.
|
/* PIO between in and out; WIO from ref.
|
||||||
*/
|
*/
|
||||||
if( im_piocheck( in, out ) || im_incheck( ref ) )
|
if( im_piocheck( in, out ) ||
|
||||||
|
im_incheck( ref ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Check sizes.
|
/* Check sizes.
|
||||||
@ -154,14 +143,13 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|||||||
|
|
||||||
/* Check types.
|
/* Check types.
|
||||||
*/
|
*/
|
||||||
if( in->Coding != IM_CODING_NONE || in->Bands != 1 ||
|
if( im_check_uncoded( "im_fastcor", in ) ||
|
||||||
in->BandFmt != IM_BANDFMT_UCHAR ||
|
im_check_format( "im_fastcor", in, IM_BANDFMT_UCHAR ) ||
|
||||||
ref->Coding != IM_CODING_NONE || ref->Bands != 1 ||
|
im_check_mono( "im_fastcor", in ) ||
|
||||||
ref->BandFmt != IM_BANDFMT_UCHAR ) {
|
im_check_uncoded( "im_fastcor", ref ) ||
|
||||||
im_error( "im_fastcor_raw", "%s",
|
im_check_format( "im_fastcor", ref, IM_BANDFMT_UCHAR ) ||
|
||||||
_( "input not uncoded 1 band uchar" ) );
|
im_check_mono( "im_fastcor", ref ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare the output image.
|
/* Prepare the output image.
|
||||||
*/
|
*/
|
||||||
@ -171,16 +159,12 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|||||||
out->Xsize = in->Xsize - ref->Xsize + 1;
|
out->Xsize = in->Xsize - ref->Xsize + 1;
|
||||||
out->Ysize = in->Ysize - ref->Ysize + 1;
|
out->Ysize = in->Ysize - ref->Ysize + 1;
|
||||||
|
|
||||||
/* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
|
/* FATSTRIP is good for us, as THINSTRIP will cause
|
||||||
* too many recalculations on overlaps.
|
* too many recalculations on overlaps.
|
||||||
*/
|
*/
|
||||||
if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) )
|
if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) ||
|
||||||
return( -1 );
|
im_generate( out,
|
||||||
|
im_start_one, fastcor_gen, im_stop_one, in, ref ) )
|
||||||
/* Write the correlation.
|
|
||||||
*/
|
|
||||||
if( im_generate( out,
|
|
||||||
im_start_one, fastcor_gen, im_stop_one, in, ref ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
out->Xoffset = -ref->Xsize / 2;
|
out->Xoffset = -ref->Xsize / 2;
|
||||||
@ -189,7 +173,22 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The above, with a border to make out the same size as in.
|
/**
|
||||||
|
* im_fastcor:
|
||||||
|
* @in: input image
|
||||||
|
* @ref: reference image
|
||||||
|
* @out: output image
|
||||||
|
*
|
||||||
|
* Calculate a fast correlation surface.
|
||||||
|
*
|
||||||
|
* @ref is placed at every position in @in and the sum of squares of
|
||||||
|
* differences calculated. One-band, 8-bit unsigned images only. The output
|
||||||
|
* image is always %IM_BANDFMT_UINT. @ref must be smaller than @in. The output
|
||||||
|
* image is the same size as the input.
|
||||||
|
*
|
||||||
|
* See also: im_spcor().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
im_fastcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
im_fastcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
||||||
|
@ -1,23 +1,12 @@
|
|||||||
/* @(#) Like im_spcor(), but with a new metric.
|
/* im_gradcor
|
||||||
* @(#)
|
|
||||||
* @(#) takes the gradient images of the two images, and takes the dot-product
|
|
||||||
* @(#) correlation of the two vector images.
|
|
||||||
* @(#)
|
|
||||||
* @(#) (vector images are never really used, the two components are
|
|
||||||
* @(#) calculated separately)
|
|
||||||
* @(#)
|
|
||||||
* @(#) The vector expression of this method is my (tcv) own creation. It is
|
|
||||||
* @(#) equivalent to the complex-number method of:
|
|
||||||
* @(#)
|
|
||||||
* @(#) ARGYRIOU, V. et al. 2003. Estimation of sub-pixel motion using
|
|
||||||
* @(#) gradient cross correlation. Electronics Letters, 39 (13).
|
|
||||||
* @(#)
|
|
||||||
* @(#) It's suitability for sub-pixel alignment is not (yet) tested.
|
|
||||||
*
|
*
|
||||||
* Copyright: 2007 Nottingham Trent University
|
* Copyright: 2007 Nottingham Trent University
|
||||||
*
|
*
|
||||||
* Author: Tom Vajzovic
|
* Author: Tom Vajzovic
|
||||||
* Written on: 2007-06-07
|
* Written on: 2007-06-07
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -112,19 +101,14 @@ int im_gradcor_raw( IMAGE *large, IMAGE *small, IMAGE *out ){
|
|||||||
if( im_piocheck( large, out ) || im_pincheck( small ) )
|
if( im_piocheck( large, out ) || im_pincheck( small ) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if( ! vips_bandfmt_isint( large->BandFmt ) ||
|
if( im_check_uncoded( "im_gradcor", large ) ||
|
||||||
! vips_bandfmt_isint( small->BandFmt ) ){
|
im_check_mono( "im_gradcor", large ) ||
|
||||||
im_error( FUNCTION_NAME, "image does not have integer band format" );
|
im_check_uncoded( "im_gradcor", small ) ||
|
||||||
return -1;
|
im_check_mono( "im_gradcor", small ) ||
|
||||||
}
|
im_check_format_same( "im_gradcor", large, small ) ||
|
||||||
if( large-> Coding || small-> Coding ){
|
im_check_int( "im_gradcor", large ) )
|
||||||
im_error( FUNCTION_NAME, "image is not uncoded" );
|
return( -1 );
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if( 1 != large-> Bands || 1 != small-> Bands ){
|
|
||||||
im_error( FUNCTION_NAME, "image is multi-band" );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if( large-> Xsize < small-> Xsize || large-> Ysize < small-> Ysize ){
|
if( large-> Xsize < small-> Xsize || large-> Ysize < small-> Ysize ){
|
||||||
im_error( FUNCTION_NAME, "second image must be smaller than first" );
|
im_error( FUNCTION_NAME, "second image must be smaller than first" );
|
||||||
return -1;
|
return -1;
|
||||||
@ -152,6 +136,32 @@ int im_gradcor_raw( IMAGE *large, IMAGE *small, IMAGE *out ){
|
|||||||
#undef FUNCTION_NAME
|
#undef FUNCTION_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_gradcor:
|
||||||
|
* @in: input image
|
||||||
|
* @ref: reference image
|
||||||
|
* @out: output image
|
||||||
|
*
|
||||||
|
* Calculate a correlation surface.
|
||||||
|
*
|
||||||
|
* @ref is placed at every position in @in and a correlation coefficient
|
||||||
|
* calculated. One-band, integer images only. @in and @ref must have the
|
||||||
|
* same #VipsBandFmt. The output
|
||||||
|
* image is always %IM_BANDFMT_FLOAT. @ref must be smaller than @in. The output
|
||||||
|
* image is the same size as the input.
|
||||||
|
*
|
||||||
|
* The method takes the gradient images of the two images then takes the
|
||||||
|
* dot-product correlation of the two vector images.
|
||||||
|
* The vector expression of this method is my (tcv) own creation. It is
|
||||||
|
* equivalent to the complex-number method of:
|
||||||
|
*
|
||||||
|
* ARGYRIOU, V. et al. 2003. Estimation of sub-pixel motion using
|
||||||
|
* gradient cross correlation. Electronics Letters, 39 (13).
|
||||||
|
*
|
||||||
|
* See also: im_spcor().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
im_gradcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
im_gradcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
||||||
{
|
{
|
||||||
@ -173,24 +183,35 @@ im_gradcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|||||||
#undef FUNCTION_NAME
|
#undef FUNCTION_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_grad_x:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
*
|
||||||
|
* Find horizontal differences between adjacent pixels.
|
||||||
|
*
|
||||||
|
* Generates an image where the value of each pixel is the difference between
|
||||||
|
* it and the pixel to its right. The output has the same height as the input
|
||||||
|
* and one pixel less width. One-band integer formats only. The result is
|
||||||
|
* always %IM_BANDFMT_INT.
|
||||||
|
*
|
||||||
|
* This operation is much faster than (though equivalent to) im_conv() with the
|
||||||
|
* mask [[-1, 1]].
|
||||||
|
*
|
||||||
|
* See also: im_grad_y(), im_conv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
int im_grad_x( IMAGE *in, IMAGE *out ){
|
int im_grad_x( IMAGE *in, IMAGE *out ){
|
||||||
#define FUNCTION_NAME "im_grad_x"
|
#define FUNCTION_NAME "im_grad_x"
|
||||||
|
|
||||||
if( im_piocheck( in, out ) )
|
if( im_piocheck( in, out ) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if( ! vips_bandfmt_isint( in->BandFmt ) ){
|
if( im_check_uncoded( "im_grad_x", in ) ||
|
||||||
im_error( FUNCTION_NAME, "image does not have integer band format" );
|
im_check_mono( "im_grad_x", in ) ||
|
||||||
return -1;
|
im_check_int( "im_grad_x", in ) )
|
||||||
}
|
return( -1 );
|
||||||
if( in-> Coding ){
|
|
||||||
im_error( FUNCTION_NAME, "image is not uncoded" );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if( 1 != in-> Bands ){
|
|
||||||
im_error( FUNCTION_NAME, "image is multi-band" );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if( im_cp_desc( out, in ) )
|
if( im_cp_desc( out, in ) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -238,24 +259,37 @@ int im_grad_x( IMAGE *in, IMAGE *out ){
|
|||||||
#undef FUNCTION_NAME
|
#undef FUNCTION_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_grad_y:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
*
|
||||||
|
* Find vertical differences between adjacent pixels.
|
||||||
|
*
|
||||||
|
* Generates an image where the value of each pixel is the difference between
|
||||||
|
* it and the pixel below it. The output has the same width as the input
|
||||||
|
* and one pixel less height. One-band integer formats only. The result is
|
||||||
|
* always %IM_BANDFMT_INT.
|
||||||
|
*
|
||||||
|
* This operation is much faster than (though equivalent to) im_conv() with the
|
||||||
|
* mask [[-1], [1]].
|
||||||
|
*
|
||||||
|
* See also: im_grad_x(), im_conv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
int im_grad_y( IMAGE *in, IMAGE *out ){
|
int im_grad_y( IMAGE *in, IMAGE *out ){
|
||||||
#define FUNCTION_NAME "im_grad_y"
|
#define FUNCTION_NAME "im_grad_y"
|
||||||
|
|
||||||
if( im_piocheck( in, out ) )
|
if( im_piocheck( in, out ) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if( ! vips_bandfmt_isint( in->BandFmt ) ){
|
if( im_check_uncoded( "im_grad_y", in ) ||
|
||||||
im_error( FUNCTION_NAME, "image does not have integer band format" );
|
im_check_mono( "im_grad_y", in ) ||
|
||||||
return -1;
|
im_check_int( "im_grad_y", in ) )
|
||||||
}
|
return( -1 );
|
||||||
if( in-> Coding ){
|
|
||||||
im_error( FUNCTION_NAME, "image is not uncoded" );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if( 1 != in-> Bands ){
|
|
||||||
im_error( FUNCTION_NAME, "image is multi-band" );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if( im_cp_desc( out, in ) )
|
if( im_cp_desc( out, in ) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -36,6 +36,9 @@
|
|||||||
* - ~15% speed up in total
|
* - ~15% speed up in total
|
||||||
* 29/11/06
|
* 29/11/06
|
||||||
* - convolve first to help region sharing
|
* - convolve first to help region sharing
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -212,6 +215,73 @@ sharpen_mask_new( int radius )
|
|||||||
return( line );
|
return( line );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_sharpen:
|
||||||
|
* @in: input image
|
||||||
|
* @out: output image
|
||||||
|
* @mask_size: how large a mask to use
|
||||||
|
* @x1: flat/jaggy threshold
|
||||||
|
* @y2: maximum amount of brightening
|
||||||
|
* @y3: maximum amount of darkening
|
||||||
|
* @m1: slope for flat areas
|
||||||
|
* @m2: slope for jaggy areas
|
||||||
|
*
|
||||||
|
* Selectively sharpen the L channel of a LAB image. Works for %IM_CODING_LABQ
|
||||||
|
* and LABS images.
|
||||||
|
*
|
||||||
|
* The operation performs a gaussian blur of size @mask_size and subtracts
|
||||||
|
* from @in to
|
||||||
|
* generate a high-frequency signal. This signal is passed through a lookup
|
||||||
|
* table formed from the five parameters and added back to @in.
|
||||||
|
*
|
||||||
|
* The lookup table is formed like this:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
^
|
||||||
|
y2 |- - - - - -----------
|
||||||
|
| /
|
||||||
|
| / slope m2
|
||||||
|
| .../
|
||||||
|
-x1 | ... |
|
||||||
|
-------------------...---------------------->
|
||||||
|
| ... | x1
|
||||||
|
|... slope m1
|
||||||
|
/ |
|
||||||
|
/ m2 |
|
||||||
|
/ |
|
||||||
|
/ |
|
||||||
|
/ |
|
||||||
|
/ |
|
||||||
|
______/ _ _ _ _ _ _ | -y3
|
||||||
|
|
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* For printing, we recommend the following settings:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
mask_size == 7
|
||||||
|
x1 == 1.5
|
||||||
|
y2 == 20 (don't brighten by more than 20 L*)
|
||||||
|
y3 == 50 (can darken by up to 50 L*)
|
||||||
|
|
||||||
|
m1 == 1 (some sharpening in flat areas)
|
||||||
|
m2 == 2 (more sharpening in jaggy areas)
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* If you want more or less sharpening, we suggest you just change the m1
|
||||||
|
* and m2 parameters.
|
||||||
|
*
|
||||||
|
* The @mask_size parameter changes the width of the fringe and can be
|
||||||
|
* adjusted according to the output printing resolution. As an approximate
|
||||||
|
* guideline, use 3 for 4 pixels/mm (CRT display resolution), 5 for 8
|
||||||
|
* pixels/mm, 7 for 12 pixels/mm and 9 for 16 pixels/mm (300 dpi == 12
|
||||||
|
* pixels/mm). These figures refer to the image raster, not the half-tone
|
||||||
|
* resolution.
|
||||||
|
*
|
||||||
|
* See also: im_conv().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
im_sharpen( IMAGE *in, IMAGE *out,
|
im_sharpen( IMAGE *in, IMAGE *out,
|
||||||
int mask_size,
|
int mask_size,
|
||||||
@ -243,20 +313,19 @@ im_sharpen( IMAGE *in, IMAGE *out,
|
|||||||
|
|
||||||
/* Check IMAGE parameters
|
/* Check IMAGE parameters
|
||||||
*/
|
*/
|
||||||
if( in->Coding != IM_CODING_NONE ||
|
if( im_piocheck( in, out ) ||
|
||||||
in->Bands != 3 ||
|
im_check_uncoded( "im_sharpen", in ) ||
|
||||||
in->BandFmt != IM_BANDFMT_SHORT ) {
|
im_check_bands( "im_gradcor", in, 3 ) ||
|
||||||
im_error( "im_sharpen", "%s", _( "input not 3-band short" ) );
|
im_check_format( "im_gradcor", in, IM_BANDFMT_SHORT ) )
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( im_piocheck( in, out ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Check number range.
|
/* Check number range.
|
||||||
*/
|
*/
|
||||||
if( x1 < 0 || x2 < 0 || x1 > 99 || x2 > 99 || x1 > x2 ||
|
if( x1 < 0 || x1 > 99 ||
|
||||||
x3 < 0 || x3 > 99 || x1 > x3 ) {
|
x2 < 0 || x2 > 99 ||
|
||||||
|
x1 > x2 ||
|
||||||
|
x3 < 0 || x3 > 99 ||
|
||||||
|
x1 > x3 ) {
|
||||||
im_error( "im_sharpen", "%s", _( "parameters out of range" ) );
|
im_error( "im_sharpen", "%s", _( "parameters out of range" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,4 @@
|
|||||||
/* @(#) Functions which calculates the correlation coefficient between two
|
/* im_spcor
|
||||||
* @(#) images.
|
|
||||||
* @(#)
|
|
||||||
* @(#) int im_spcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|
||||||
* @(#)
|
|
||||||
* @(#) We calculate:
|
|
||||||
* @(#)
|
|
||||||
* @(#) sumij (ref(i,j)-mean(ref))(inkl(i,j)-mean(inkl))
|
|
||||||
* @(#) c(k,l) = ------------------------------------------------
|
|
||||||
* @(#) sqrt(sumij (ref(i,j)-mean(ref))^2) *
|
|
||||||
* @(#) sqrt(sumij (inkl(i,j)-mean(inkl))^2)
|
|
||||||
* @(#)
|
|
||||||
* @(#) where inkl is the area of in centred at position (k,l).
|
|
||||||
* @(#)
|
|
||||||
* @(#) Writes float to out. in and ref must be 1 band uchar, or 1 band
|
|
||||||
* @(#) ushort.
|
|
||||||
* @(#)
|
|
||||||
* @(#) Returns 0 on sucess and -1 on error.
|
|
||||||
*
|
*
|
||||||
* Copyright: 1990, N. Dessipris; 2006, 2007 Nottingham Trent University.
|
* Copyright: 1990, N. Dessipris; 2006, 2007 Nottingham Trent University.
|
||||||
*
|
*
|
||||||
@ -48,6 +31,9 @@
|
|||||||
* - make im_spcor a wrapper selecting either im__spcor or im__spcor2
|
* - make im_spcor a wrapper selecting either im__spcor or im__spcor2
|
||||||
* 2008-09-09 JC
|
* 2008-09-09 JC
|
||||||
* - roll back the windowed version for now, it has some tile edge effects
|
* - roll back the windowed version for now, it has some tile edge effects
|
||||||
|
* 3/2/10
|
||||||
|
* - gtkdoc
|
||||||
|
* - cleanups
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -185,14 +171,11 @@ spcor_gen( REGION *or, void *vseq, void *a, void *b )
|
|||||||
*/
|
*/
|
||||||
switch( ref->BandFmt ) {
|
switch( ref->BandFmt ) {
|
||||||
case IM_BANDFMT_UCHAR: LOOP(unsigned char); break;
|
case IM_BANDFMT_UCHAR: LOOP(unsigned char); break;
|
||||||
|
case IM_BANDFMT_CHAR: LOOP(signed char); break;
|
||||||
case IM_BANDFMT_USHORT: LOOP(unsigned short); break;
|
case IM_BANDFMT_USHORT: LOOP(unsigned short); break;
|
||||||
case IM_BANDFMT_SHORT: LOOP(signed short); break;
|
case IM_BANDFMT_SHORT: LOOP(signed short); break;
|
||||||
default:
|
default:
|
||||||
error_exit( "im_spcor: internal error #7934" );
|
g_assert( 0 );
|
||||||
|
|
||||||
/* Keep gcc -Wall happy.
|
|
||||||
*/
|
|
||||||
return( -1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now: calculate correlation coefficient!
|
/* Now: calculate correlation coefficient!
|
||||||
@ -260,20 +243,17 @@ im_spcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|||||||
|
|
||||||
/* Check types.
|
/* Check types.
|
||||||
*/
|
*/
|
||||||
if( in->Coding != IM_CODING_NONE ||
|
if( im_check_uncoded( "im_spcor", in ) ||
|
||||||
in->Bands != 1 ||
|
im_check_mono( "im_spcor", in ) ||
|
||||||
ref->Coding != IM_CODING_NONE ||
|
im_check_uncoded( "im_spcor", ref ) ||
|
||||||
ref->Bands != 1 ||
|
im_check_mono( "im_spcor", ref ) ||
|
||||||
in->BandFmt != ref->BandFmt ) {
|
im_check_format_same( "im_spcor", in, ref ) )
|
||||||
im_error( "im_spcor_raw",
|
|
||||||
"%s", _( "input not uncoded 1 band" ) );
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
if( in->BandFmt != IM_BANDFMT_UCHAR &&
|
if( in->BandFmt != IM_BANDFMT_UCHAR &&
|
||||||
in->BandFmt != IM_BANDFMT_CHAR &&
|
in->BandFmt != IM_BANDFMT_CHAR &&
|
||||||
in->BandFmt != IM_BANDFMT_SHORT &&
|
in->BandFmt != IM_BANDFMT_SHORT &&
|
||||||
in->BandFmt != IM_BANDFMT_USHORT ) {
|
in->BandFmt != IM_BANDFMT_USHORT ) {
|
||||||
im_error( "im_spcor_raw",
|
im_error( "im_spcor",
|
||||||
"%s", _( "input not char/uchar/short/ushort" ) );
|
"%s", _( "input not char/uchar/short/ushort" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
@ -309,7 +289,37 @@ im_spcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The above, with the input expanded to make out the same size as in.
|
/**
|
||||||
|
* im_spcor:
|
||||||
|
* @in: input image
|
||||||
|
* @ref: reference image
|
||||||
|
* @out: output image
|
||||||
|
*
|
||||||
|
* Calculate a correlation surface.
|
||||||
|
*
|
||||||
|
* @ref is placed at every position in @in and the correlation coefficient
|
||||||
|
* calculated. One-band, 8 or 16-bit images only. @in and @ref must have the
|
||||||
|
* same #VipsBandFmt. The output
|
||||||
|
* image is always %IM_BANDFMT_FLOAT. @ref must be smaller than @in. The output
|
||||||
|
* image is the same size as the input.
|
||||||
|
*
|
||||||
|
* The correlation coefficient is calculated as:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* sumij (ref(i,j)-mean(ref))(inkl(i,j)-mean(inkl))
|
||||||
|
* c(k,l) = ------------------------------------------------
|
||||||
|
* sqrt(sumij (ref(i,j)-mean(ref))^2) *
|
||||||
|
* sqrt(sumij (inkl(i,j)-mean(inkl))^2)
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* where inkl is the area of @in centred at position (k,l).
|
||||||
|
*
|
||||||
|
* from Niblack "An Introduction to Digital Image Processing",
|
||||||
|
* Prentice/Hall, pp 138.
|
||||||
|
*
|
||||||
|
* See also: im_gradcor(), im_fastcor().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
im_spcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
im_spcor( IMAGE *in, IMAGE *ref, IMAGE *out )
|
||||||
|
@ -59,6 +59,8 @@ int im_check_u8or16( const char *domain, IMAGE *im );
|
|||||||
int im_check_format_same( const char *domain, IMAGE *im1, IMAGE *im2 );
|
int im_check_format_same( const char *domain, IMAGE *im1, IMAGE *im2 );
|
||||||
int im_check_size_same( const char *domain, IMAGE *im1, IMAGE *im2 );
|
int im_check_size_same( const char *domain, IMAGE *im1, IMAGE *im2 );
|
||||||
int im_check_vector( const char *domain, int n, IMAGE *im );
|
int im_check_vector( const char *domain, int n, IMAGE *im );
|
||||||
|
int im_check_imask( const char *domain, INTMASK *mask );
|
||||||
|
int im_check_dmask( const char *domain, DOUBLEMASK *mask );
|
||||||
|
|
||||||
gboolean vips_bandfmt_isint( VipsBandFmt fmt );
|
gboolean vips_bandfmt_isint( VipsBandFmt fmt );
|
||||||
gboolean vips_bandfmt_isuint( VipsBandFmt fmt );
|
gboolean vips_bandfmt_isuint( VipsBandFmt fmt );
|
||||||
|
@ -919,6 +919,60 @@ im_check_vector( const char *domain, int n, IMAGE *im )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_check_imask:
|
||||||
|
* @domain: the originating domain for the error message
|
||||||
|
* @mask: mask to check
|
||||||
|
*
|
||||||
|
* Sanity-check a mask parameter.
|
||||||
|
*
|
||||||
|
* See also: im_error().
|
||||||
|
*
|
||||||
|
* Returns: 0 if OK, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
im_check_imask( const char *domain, INTMASK *mask )
|
||||||
|
{
|
||||||
|
if( !mask ||
|
||||||
|
mask->xsize > 1000 ||
|
||||||
|
mask->ysize > 1000 ||
|
||||||
|
mask->xsize <= 0 ||
|
||||||
|
mask->ysize <= 0 ||
|
||||||
|
!mask->coeff ) {
|
||||||
|
im_error( "im_conv", "%s", _( "nonsense mask parameters" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im_check_dmask:
|
||||||
|
* @domain: the originating domain for the error message
|
||||||
|
* @mask: mask to check
|
||||||
|
*
|
||||||
|
* Sanity-check a mask parameter.
|
||||||
|
*
|
||||||
|
* See also: im_error().
|
||||||
|
*
|
||||||
|
* Returns: 0 if OK, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
im_check_dmask( const char *domain, DOUBLEMASK *mask )
|
||||||
|
{
|
||||||
|
if( !mask ||
|
||||||
|
mask->xsize > 1000 ||
|
||||||
|
mask->ysize > 1000 ||
|
||||||
|
mask->xsize <= 0 ||
|
||||||
|
mask->ysize <= 0 ||
|
||||||
|
!mask->coeff ) {
|
||||||
|
im_error( "im_conv", "%s", _( "nonsense mask parameters" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vips_bandfmt_isint:
|
* vips_bandfmt_isint:
|
||||||
* @fmt: format to test
|
* @fmt: format to test
|
||||||
|
Loading…
Reference in New Issue
Block a user