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_conv.c \
|
||||
im_conv_f.c \
|
||||
im_convsep_f.c \
|
||||
im_contrast_surface.c \
|
||||
im_fastcor.c \
|
||||
im_gradcor.c \
|
||||
|
@ -38,6 +38,9 @@
|
||||
* - more cleanups
|
||||
* 1/10/10
|
||||
* - 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 );
|
||||
}
|
||||
|
||||
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…
Reference in New Issue
Block a user