remove special im_convsep_f() code
This commit is contained in:
parent
59a73c079b
commit
2bcf18a2b7
@ -6,7 +6,6 @@ libconvolution_la_SOURCES = \
|
|||||||
im_compass.c \
|
im_compass.c \
|
||||||
im_conv.c \
|
im_conv.c \
|
||||||
im_conv_f.c \
|
im_conv_f.c \
|
||||||
im_convsep_f.c \
|
|
||||||
im_contrast_surface.c \
|
im_contrast_surface.c \
|
||||||
im_fastcor.c \
|
im_fastcor.c \
|
||||||
im_gradcor.c \
|
im_gradcor.c \
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
* - more cleanups
|
* - more cleanups
|
||||||
* 1/10/10
|
* 1/10/10
|
||||||
* - support complex (just double the bands)
|
* - support complex (just double the bands)
|
||||||
|
* 29/10/10
|
||||||
|
* - get rid of im_convsep_f(), just call this twice, no longer worth
|
||||||
|
* keeping two versions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -390,3 +393,76 @@ im_conv_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
||||||
|
{
|
||||||
|
IMAGE *t;
|
||||||
|
DOUBLEMASK *rmask;
|
||||||
|
|
||||||
|
if( mask->xsize != 1 && mask->ysize != 1 ) {
|
||||||
|
im_error( "im_convsep_f",
|
||||||
|
"%s", _( "expect 1xN or Nx1 input mask" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !(t = im_open_local( out, "im_convsep_f", "p" )) ||
|
||||||
|
!(rmask = (INTMASK *) im_local( out,
|
||||||
|
(im_construct_fn) im_dup_dmask,
|
||||||
|
(im_callback_fn) im_free_dmask, mask, mask->filename, NULL )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
rmask->xsize = mask->ysize;
|
||||||
|
rmask->ysize = mask->xsize;
|
||||||
|
|
||||||
|
if( im_conv_f_raw( in, t, mask ) ||
|
||||||
|
im_conv_f_raw( t, out, rmask ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
im_convsep_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
||||||
|
{
|
||||||
|
IMAGE *t1 = im_open_local( out, "im_convsep intermediate", "p" );
|
||||||
|
int size = mask->xsize * mask->ysize;
|
||||||
|
|
||||||
|
if( !t1 ||
|
||||||
|
im_embed( in, t1, 1, size / 2, size / 2,
|
||||||
|
in->Xsize + size - 1,
|
||||||
|
in->Ysize + size - 1 ) ||
|
||||||
|
im_convsep_f_raw( t1, out, mask ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
out->Xoffset = 0;
|
||||||
|
out->Yoffset = 0;
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
@ -1,368 +0,0 @@
|
|||||||
/* im_convsep_f
|
|
||||||
*
|
|
||||||
* Copyright: 1990, N. Dessipris.
|
|
||||||
*
|
|
||||||
* Author: Nicos Dessipris
|
|
||||||
* Written on: 29/04/1991
|
|
||||||
* Modified on: 29/4/93 K.Martinez for sys5
|
|
||||||
* 9/3/01 JC
|
|
||||||
* - rewritten using im_conv()
|
|
||||||
* 7/4/04
|
|
||||||
* - now uses im_embed() with edge stretching on the input, not
|
|
||||||
* the output
|
|
||||||
* - sets Xoffset / Yoffset
|
|
||||||
* 3/2/10
|
|
||||||
* - gtkdoc
|
|
||||||
* - more cleanups
|
|
||||||
* 1/10/10
|
|
||||||
* - support complex (just double the bands)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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 <stdlib.h>
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include <vips/vips.h>
|
|
||||||
|
|
||||||
#ifdef WITH_DMALLOC
|
|
||||||
#include <dmalloc.h>
|
|
||||||
#endif /*WITH_DMALLOC*/
|
|
||||||
|
|
||||||
/* Our parameters ... we take a copy of the mask argument.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
IMAGE *in;
|
|
||||||
IMAGE *out;
|
|
||||||
DOUBLEMASK *mask; /* Copy of mask arg */
|
|
||||||
|
|
||||||
int size; /* N for our 1xN or Nx1 mask */
|
|
||||||
int scale; /* Our scale ... we have to ^2 mask->scale */
|
|
||||||
} Conv;
|
|
||||||
|
|
||||||
/* End of evaluation.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
conv_destroy( Conv *conv )
|
|
||||||
{
|
|
||||||
IM_FREEF( im_free_dmask, conv->mask );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static Conv *
|
|
||||||
conv_new( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|
||||||
{
|
|
||||||
Conv *conv = IM_NEW( out, Conv );
|
|
||||||
|
|
||||||
if( !conv )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
conv->in = in;
|
|
||||||
conv->out = out;
|
|
||||||
conv->mask = NULL;
|
|
||||||
conv->size = mask->xsize * mask->ysize;
|
|
||||||
conv->scale = mask->scale * mask->scale;
|
|
||||||
|
|
||||||
if( im_add_close_callback( out,
|
|
||||||
(im_callback_fn) conv_destroy, conv, NULL ) ||
|
|
||||||
!(conv->mask = im_dup_dmask( mask, "conv_mask" )) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
return( conv );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Our sequence value.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
Conv *conv;
|
|
||||||
REGION *ir; /* Input region */
|
|
||||||
|
|
||||||
PEL *sum; /* Line buffer */
|
|
||||||
} ConvSequence;
|
|
||||||
|
|
||||||
/* Free a sequence value.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
conv_stop( void *vseq, void *a, void *b )
|
|
||||||
{
|
|
||||||
ConvSequence *seq = (ConvSequence *) vseq;
|
|
||||||
|
|
||||||
IM_FREEF( im_region_free, seq->ir );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convolution start function.
|
|
||||||
*/
|
|
||||||
static void *
|
|
||||||
conv_start( IMAGE *out, void *a, void *b )
|
|
||||||
{
|
|
||||||
IMAGE *in = (IMAGE *) a;
|
|
||||||
Conv *conv = (Conv *) b;
|
|
||||||
ConvSequence *seq;
|
|
||||||
|
|
||||||
if( !(seq = IM_NEW( out, ConvSequence )) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
/* Init!
|
|
||||||
*/
|
|
||||||
seq->conv = conv;
|
|
||||||
seq->ir = NULL;
|
|
||||||
seq->sum = NULL;
|
|
||||||
|
|
||||||
/* Attach region and arrays.
|
|
||||||
*/
|
|
||||||
seq->ir = im_region_create( in );
|
|
||||||
if( vips_bandfmt_isint( conv->out->BandFmt ) )
|
|
||||||
seq->sum = (PEL *)
|
|
||||||
IM_ARRAY( out, IM_IMAGE_N_ELEMENTS( in ), int );
|
|
||||||
else
|
|
||||||
seq->sum = (PEL *)
|
|
||||||
IM_ARRAY( out, IM_IMAGE_N_ELEMENTS( in ), double );
|
|
||||||
if( !seq->ir || !seq->sum ) {
|
|
||||||
conv_stop( seq, in, conv );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( (void *) seq );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* What we do for every point in the mask, for each pixel.
|
|
||||||
*/
|
|
||||||
#define VERTICAL_CONV { z -= 1; li -= lskip; sum += coeff[z] * vfrom[li]; }
|
|
||||||
#define HORIZONTAL_CONV { z -= 1; li -= bands; sum += coeff[z] * hfrom[li]; }
|
|
||||||
|
|
||||||
#define CONV_FLOAT( ITYPE, OTYPE ) { \
|
|
||||||
ITYPE *vfrom; \
|
|
||||||
double *vto; \
|
|
||||||
double *hfrom; \
|
|
||||||
OTYPE *hto; \
|
|
||||||
\
|
|
||||||
/* Convolve to sum array. We convolve the full width of \
|
|
||||||
* this input line. \
|
|
||||||
*/ \
|
|
||||||
vfrom = (ITYPE *) IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
vto = (double *) seq->sum; \
|
|
||||||
for( x = 0; x < isz; x++ ) { \
|
|
||||||
double sum; \
|
|
||||||
\
|
|
||||||
z = conv->size; \
|
|
||||||
li = lskip * z; \
|
|
||||||
sum = 0; \
|
|
||||||
\
|
|
||||||
IM_UNROLL( z, VERTICAL_CONV ); \
|
|
||||||
\
|
|
||||||
vto[x] = sum; \
|
|
||||||
vfrom += 1; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* Convolve sums to output. \
|
|
||||||
*/ \
|
|
||||||
hfrom = (double *) seq->sum; \
|
|
||||||
hto = (OTYPE *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
for( x = 0; x < osz; x++ ) { \
|
|
||||||
double sum; \
|
|
||||||
\
|
|
||||||
z = conv->size; \
|
|
||||||
li = bands * z; \
|
|
||||||
sum = 0; \
|
|
||||||
\
|
|
||||||
IM_UNROLL( z, HORIZONTAL_CONV ); \
|
|
||||||
\
|
|
||||||
sum = (sum / conv->scale) + mask->offset; \
|
|
||||||
\
|
|
||||||
hto[x] = sum; \
|
|
||||||
hfrom += 1; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convolve!
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
conv_gen( REGION *or, void *vseq, void *a, void *b )
|
|
||||||
{
|
|
||||||
ConvSequence *seq = (ConvSequence *) vseq;
|
|
||||||
IMAGE *in = (IMAGE *) a;
|
|
||||||
Conv *conv = (Conv *) b;
|
|
||||||
REGION *ir = seq->ir;
|
|
||||||
DOUBLEMASK *mask = conv->mask;
|
|
||||||
double *coeff = conv->mask->coeff;
|
|
||||||
int bands = in->Bands;
|
|
||||||
|
|
||||||
Rect *r = &or->valid;
|
|
||||||
int le = r->left;
|
|
||||||
int to = r->top;
|
|
||||||
int bo = IM_RECT_BOTTOM(r);
|
|
||||||
int osz = IM_REGION_N_ELEMENTS( or ) *
|
|
||||||
(vips_bandfmt_iscomplex( in->BandFmt ) ? 2 : 1);
|
|
||||||
|
|
||||||
Rect s;
|
|
||||||
int lskip;
|
|
||||||
int isz;
|
|
||||||
int x, y, z, li;
|
|
||||||
|
|
||||||
/* Prepare the section of the input image we need. A little larger
|
|
||||||
* than the section of the output image we are producing.
|
|
||||||
*/
|
|
||||||
s = *r;
|
|
||||||
s.width += conv->size - 1;
|
|
||||||
s.height += conv->size - 1;
|
|
||||||
if( im_prepare( ir, &s ) )
|
|
||||||
return( -1 );
|
|
||||||
lskip = IM_REGION_LSKIP( ir ) / IM_IMAGE_SIZEOF_ELEMENT( in );
|
|
||||||
isz = IM_REGION_N_ELEMENTS( ir );
|
|
||||||
|
|
||||||
for( y = to; y < bo; y++ ) {
|
|
||||||
switch( in->BandFmt ) {
|
|
||||||
case IM_BANDFMT_UCHAR:
|
|
||||||
CONV_FLOAT( unsigned char, float ); break;
|
|
||||||
case IM_BANDFMT_CHAR:
|
|
||||||
CONV_FLOAT( signed char, float ); break;
|
|
||||||
case IM_BANDFMT_USHORT:
|
|
||||||
CONV_FLOAT( unsigned short, float ); break;
|
|
||||||
case IM_BANDFMT_SHORT:
|
|
||||||
CONV_FLOAT( signed short, float ); break;
|
|
||||||
case IM_BANDFMT_UINT:
|
|
||||||
CONV_FLOAT( unsigned int, float ); break;
|
|
||||||
case IM_BANDFMT_INT:
|
|
||||||
CONV_FLOAT( signed int, float ); break;
|
|
||||||
case IM_BANDFMT_FLOAT:
|
|
||||||
case IM_BANDFMT_COMPLEX:
|
|
||||||
CONV_FLOAT( float, float ); break;
|
|
||||||
case IM_BANDFMT_DOUBLE:
|
|
||||||
case IM_BANDFMT_DPCOMPLEX:
|
|
||||||
CONV_FLOAT( double, double ); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert( 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|
||||||
{
|
|
||||||
Conv *conv;
|
|
||||||
|
|
||||||
/* Check parameters.
|
|
||||||
*/
|
|
||||||
if( im_piocheck( in, out ) ||
|
|
||||||
im_check_uncoded( "im_convsep_f", in ) ||
|
|
||||||
im_check_dmask( "im_convsep_f", mask ) )
|
|
||||||
return( -1 );
|
|
||||||
if( mask->xsize != 1 && mask->ysize != 1 ) {
|
|
||||||
im_error( "im_convsep_f",
|
|
||||||
"%s", _( "expect 1xN or Nx1 input mask" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
if( mask->scale == 0 ) {
|
|
||||||
im_error( "im_convsep_f", "%s", "mask scale must be non-zero" );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
if( !(conv = conv_new( in, out, mask )) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Prepare output. Consider a 7x7 mask and a 7x7 image --- the output
|
|
||||||
* would be 1x1.
|
|
||||||
*/
|
|
||||||
if( im_cp_desc( out, in ) )
|
|
||||||
return( -1 );
|
|
||||||
if( vips_bandfmt_isint( in->BandFmt ) )
|
|
||||||
out->BandFmt = IM_BANDFMT_FLOAT;
|
|
||||||
out->Xsize -= conv->size - 1;
|
|
||||||
out->Ysize -= conv->size - 1;
|
|
||||||
if( out->Xsize <= 0 || out->Ysize <= 0 ) {
|
|
||||||
im_error( "im_convsep_f",
|
|
||||||
"%s", _( "image too small for mask" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SMALLTILE seems fastest.
|
|
||||||
*/
|
|
||||||
if( im_demand_hint( out, IM_SMALLTILE, in, NULL ) ||
|
|
||||||
im_generate( out, conv_start, conv_gen, conv_stop, in, conv ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
out->Xoffset = -conv->size / 2;
|
|
||||||
out->Yoffset = -conv->size / 2;
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
im_convsep_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask )
|
|
||||||
{
|
|
||||||
IMAGE *t1 = im_open_local( out, "im_convsep_f intermediate", "p" );
|
|
||||||
int size = mask->xsize * mask->ysize;
|
|
||||||
|
|
||||||
if( !t1 ||
|
|
||||||
im_embed( in, t1, 1, size / 2, size / 2,
|
|
||||||
in->Xsize + size - 1,
|
|
||||||
in->Ysize + size - 1 ) ||
|
|
||||||
im_convsep_f_raw( t1, out, mask ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
out->Xoffset = 0;
|
|
||||||
out->Yoffset = 0;
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user