265 lines
7.1 KiB
C
265 lines
7.1 KiB
C
/* @(#) Function which convolves and subsamples VASARI format picture
|
|
* @(#) with a mask stored in a file argument.
|
|
* @(#)
|
|
* @(#) int im_convsub( in, out, mask, xskip, yskip )
|
|
* @(#) IMAGE *in, *out;
|
|
* @(#) INTMASK *mask; details in vips.h
|
|
* @(#) int xskip, yskip; is the subsamping factor along both directions
|
|
* @(#)
|
|
* @(#) Returns either 0 (sucess) or -1 (fail)
|
|
* @(#)
|
|
* @(#) Picture can have any number of channels (max 64).
|
|
* @(#) It is assummed that the output picture is subsampled on
|
|
* @(#) both directions by a factor of xskip horizontally and yskip vertically.
|
|
*
|
|
* Copyright: 1990, N. Dessipris.
|
|
*
|
|
* Author: Nicos Dessipris
|
|
* Written on: 29/04/1991
|
|
* Modified on:
|
|
*/
|
|
|
|
/*
|
|
|
|
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 <vips/vips.h>
|
|
#include <vips/internal.h>
|
|
|
|
#ifdef WITH_DMALLOC
|
|
#include <dmalloc.h>
|
|
#endif /*WITH_DMALLOC*/
|
|
|
|
|
|
int im_convsub( in, out, m, xskip, yskip )
|
|
IMAGE *in, *out;
|
|
INTMASK *m;
|
|
int xskip, yskip;
|
|
{
|
|
|
|
|
|
int x; /* horizontal direction */
|
|
int y; /* vertical direction */
|
|
int n_clipped = 0;
|
|
int p_clipped = 0;
|
|
int i, b;
|
|
PEL **pnts, **cpnt1s, **cpnt2s; /* to keep pointers to data */
|
|
PEL **pnt, **cpnt1, **cpnt2; /* to keep pointers to data */
|
|
PEL *input, *line, *cpline;
|
|
int *pm; /* pointer to mask coefficients */
|
|
int count; /* no of non zero elms of the original mask */
|
|
int *newm, *pnewm; /* pointer to non zero mask coefficients */
|
|
int os; /* size of an input line of data */
|
|
int ms; /* is m->xsize * m->ysize */
|
|
int **lut_orig, **lut;
|
|
int lutcnt = 0;
|
|
int rounding, sum;
|
|
int tempsize;
|
|
|
|
/* Check input, output and vars */
|
|
if ((xskip < 1)||(yskip < 1))
|
|
{
|
|
im_errormsg("im_convsub: xskip and yskip must be >= 1");
|
|
return(-1);
|
|
}
|
|
if (im_iocheck(in, out) == -1)
|
|
{ im_errormsg("im_convsub: Unable to im_iocheck"); return(-1); }
|
|
|
|
if ( (in->Coding != IM_CODING_NONE)||(in->Bbits != IM_BBITS_BYTE)
|
|
||(in->BandFmt != IM_BANDFMT_UCHAR) )
|
|
{
|
|
im_errormsg("im_convsub:input should be unsigned char uncoded");
|
|
return(-1);
|
|
}
|
|
|
|
/* Prepare output */
|
|
if (im_cp_desc(out, in) == -1)
|
|
{ im_errormsg("im_convsub: im_cp_desc failed"); return(-1); }
|
|
tempsize = in->Xsize/xskip;
|
|
while ( 1 )
|
|
{
|
|
if ( tempsize * xskip + m->xsize < in->Xsize )
|
|
break;
|
|
else
|
|
tempsize--;
|
|
if ( tempsize < 0 )
|
|
break;
|
|
}
|
|
out->Xsize = tempsize;
|
|
tempsize = in->Ysize/yskip;
|
|
while ( 1 )
|
|
{
|
|
if ( tempsize * yskip + m->ysize < in->Ysize )
|
|
break;
|
|
else
|
|
tempsize--;
|
|
if ( tempsize < 0 )
|
|
break;
|
|
}
|
|
out->Ysize = tempsize;
|
|
if ( ( out->Xsize < 2 )||( out->Ysize < 2 ) )
|
|
{im_errormsg("im_convsub: too small output sizes");return(-1); }
|
|
|
|
if( im_setupout(out) == -1)
|
|
{im_errormsg("im_convsub: im_setupout failed"); return(-1); }
|
|
|
|
/* Malloc one line of output data */
|
|
os = out->Xsize * out->Bands;
|
|
if ( (line=(PEL*)calloc( (unsigned)os, sizeof(char))) == NULL)
|
|
{ im_errormsg("im_convsub: unable to calloc(1)"); return(-1); }
|
|
|
|
/* Malloc pointers and put them at correct location */
|
|
ms = m->xsize * m->ysize;
|
|
count = 0; /* exclude the non-zero elms */
|
|
pm = m->coeff;
|
|
for ( i=0; i<ms; i++)
|
|
{
|
|
if ( *pm++ != 0 )
|
|
count++;
|
|
}
|
|
|
|
if (((newm = (int*)calloc((unsigned)count, sizeof(int))) == NULL )||
|
|
((pnts = (PEL**)calloc((unsigned)count, sizeof(char *))) == NULL)||
|
|
((cpnt1s=(PEL**)calloc((unsigned)count, sizeof(char *))) == NULL)||
|
|
((cpnt2s=(PEL**)calloc((unsigned)count, sizeof(char *))) ==NULL ) )
|
|
{ im_errormsg("im_convsub: unable to calloc(2)"); return(-1); }
|
|
|
|
pnt = pnts;
|
|
cpnt1 = cpnt1s;
|
|
cpnt2 = cpnt2s;
|
|
|
|
/* copy the non-zero elms of the original mask and set pointers */
|
|
i=0;
|
|
input = (PEL*)in->data;
|
|
pm = m->coeff;
|
|
pnewm = newm;
|
|
for (y=0; y<m->ysize; y++)
|
|
{
|
|
for (x=0; x<m->xsize; x++)
|
|
{
|
|
if ( *pm != 0 )
|
|
{
|
|
*pnewm++ = *pm;
|
|
pnt[i] = (input +(x + y*in->Xsize) * in->Bands);
|
|
i++;
|
|
}
|
|
pm++;
|
|
}
|
|
}
|
|
|
|
if ( i != count )
|
|
{ im_errormsg("im_convsub: impossible state"); return(-1); }
|
|
|
|
/* Malloc pointers; not all lut_orig are used necessarily */
|
|
lut_orig = (int**)calloc((unsigned)count, sizeof(int**) );
|
|
lut = (int**)calloc((unsigned)count, sizeof(int**) );
|
|
if ( (lut == NULL) || (lut_orig == NULL) )
|
|
{ im_errormsg("im_conv: unable to calloc(1)"); return(-1); }
|
|
|
|
/* Create luts; count is needed for freeing pointers. Not all lut_orig are used
|
|
* if zero elms are detected.
|
|
*/
|
|
if ( im__create_int_luts(newm, count, lut_orig, lut, &lutcnt ) == -1 )
|
|
{
|
|
im_errormsg("im_convsub: im_create_int_luts failed");
|
|
return(-1);
|
|
}
|
|
|
|
rounding = m->scale/2;
|
|
|
|
/* Output out->Ysize processed lines */
|
|
for(y=0; y < out->Ysize; y++)
|
|
{
|
|
cpline = line;
|
|
for (i=0; i<count; i++)
|
|
{
|
|
cpnt1[i] = pnt[i];
|
|
/* skip yskip input lines */
|
|
pnt[i] += ( in->Xsize * in->Bands * yskip );
|
|
}
|
|
|
|
/* process out->Xsize points */
|
|
for( x = 0; x < out->Xsize; x++ )
|
|
{
|
|
for (i=0; i<count; i++)
|
|
{ /* skip xskip elms */
|
|
cpnt2[i] = cpnt1[i];
|
|
cpnt1[i] += xskip * in->Bands;
|
|
}
|
|
for ( b=0; b<out->Bands; b++ )
|
|
{
|
|
sum = 0;
|
|
for (i=0; i<count; i++)
|
|
{ /* core of convolution */
|
|
sum += *( lut[i] + (*cpnt2[i]) );
|
|
cpnt2[i]++;
|
|
}
|
|
sum = ( (sum+rounding)/m->scale ) + m->offset;
|
|
|
|
if ( sum < (int)0 )
|
|
{ n_clipped++; sum = (int)0; }
|
|
else if ( sum > (int)255)
|
|
{ p_clipped++; sum = (int)255; }
|
|
*cpline++ = (unsigned char)sum;
|
|
}
|
|
}
|
|
|
|
/* Output the calculated line */
|
|
if ( im_writeline(y, out, (PEL*)line) == -1 )
|
|
{
|
|
im_errormsg("im_convsub: im_writeline failed(2)");
|
|
free((char*)line); free((char*)newm);
|
|
free((char*)pnts);
|
|
free((char*)cpnt1s); free((char*)cpnt2s);
|
|
for ( i=0; i<lutcnt; i++)
|
|
free( (char*)lut_orig[i] );
|
|
free( (char*)lut_orig ); free( (char*)lut );
|
|
return(-1);
|
|
}
|
|
} /* end of the for (..y..) loop */
|
|
|
|
if (n_clipped || p_clipped)
|
|
fprintf(stderr,
|
|
"im_convsub: %d pels over 255 and %d under 0 clipped\n",
|
|
p_clipped, n_clipped);
|
|
|
|
free((char*)line); free((char*)newm);
|
|
free((char*)pnts);
|
|
free((char*)cpnt1s); free((char*)cpnt2s);
|
|
for ( i=0; i<lutcnt; i++)
|
|
free( (char*)lut_orig[i] );
|
|
free( (char*)lut_orig ); free( (char*)lut );
|
|
|
|
return(0);
|
|
}
|