[Gimp-developer] patch for scale-region.c
Alastair M. Robinson
blackfive at fakenhamweb.co.uk
Fri Aug 29 06:04:48 PDT 2008
Hi
Sven Neumann wrote:
> As already explained in my previous mail, the decimation routines are
> only used for the pre-scaling steps. As soon as the image is close
> enough to the final size, the chosen interpolation routine is used. This
> gives continuous results for all scale factors as there is no longer any
> special casing for scaling down by 50%.
What I don't understand is why there's a need to interpolate at all in
the case of scaling an image down. When scaling up, interpolation is
used to estimate missing information, but when scaling down there is no
missing information to be estimated - the problem is instead finding the
best strategy for *discarding* information.
What I do in PhotoPrint is just use a simple sub-pixel-capable box
filter - which is what your current approach
(scale-by-nearest-power-of-two, then interpolate) is approximating.
The routine looks like this:
// We accumulate pixel values from a potentially
// large number of pixels and process all the samples
// in a pixel at one time.
double tmp[IS_MAX_SAMPLESPERPIXEL];
for(int i=0;i<samplesperpixel;++i)
tmp[i]=0;
ISDataType *srcdata=source->GetRow(row);
// We use a Bresenham-esque method of calculating the
// pixel boundaries for scaling - add the smaller value
// to an accumulator until it exceeds the larger value,
// then subtract the larger value, leaving the remainder
// in place for the next round.
int a=0;
int src=0;
int dst=0;
while(dst<width)
{
// Add the smaller value (destination width)
a+=width;
// As long as the counter is less than the larger value
// (source width), we take full pixels.
while(a<source->width)
{
if(src>=source->width)
src=source->width-1;
for(int i=0;i<samplesperpixel;++i)
tmp[i]+=srcdata[samplesperpixel*src+i];
++src;
a+=width;
}
double p=source->width-(a-width);
p/=width;
// p now contains the proportion of the next pixel
// to be counted towards the output pixel.
a-=source->width;
// And a now contains the remainder,
// ready for the next round.
// So we add p * the new source pixel
// to the current output pixel...
if(src>=source->width)
src=source->width-1;
for(int i=0;i<samplesperpixel;++i)
tmp[i]+=p*srcdata[samplesperpixel*src+i];
// Store it...
for(int i=0;i<samplesperpixel;++i)
{
rowbuffer[samplesperpixel*dst+i] =
0.5+(tmp[i]*width)/source->width;
}
++dst;
// And start off the next output pixel with
// (1-p) * the source pixel.
for(int i=0;i<samplesperpixel;++i)
tmp[i]=(1.0-p)*srcdata[samplesperpixel*src+i];
++src;
}
> The main problem with the code in trunk is though that I think that the
> results of the new code are too blurry. Please have a look at the tests
> that I published at http://svenfoo.org/scalepatch/. And please try the
> patch and do your own tests.
The slight blurriness comes, I think, from performing the scaling in two
distinct stages. Just for kicks, since I had a rare spare hour to play
with such things, here are versions of the 3% and 23% test from your
page, for comparison, scaled using the downsample filter whose core is
posted above:
http://www.blackfiveservices.co.uk/3Percent.png
http://www.blackfiveservices.co.uk/23Percent.png
Hope this is some help
All the best,
--
Alastair M. Robinson
More information about the Gimp-developer
mailing list