[Rawstudio-commit] r2201 - trunk/plugins/resample
Anders Brander
anders at brander.dk
Sat Feb 14 11:37:13 CET 2009
Author: abrander
Date: 2009-02-14 11:37:12 +0100 (Sat, 14 Feb 2009)
New Revision: 2201
Modified:
trunk/plugins/resample/resample.c
Log:
Added (optional) more tolerant resampler (Patch by Klaus Post).
Modified: trunk/plugins/resample/resample.c
===================================================================
--- trunk/plugins/resample/resample.c 2009-02-10 00:34:34 UTC (rev 2200)
+++ trunk/plugins/resample/resample.c 2009-02-14 10:37:12 UTC (rev 2201)
@@ -56,6 +56,8 @@
static gint get_height(RSFilter *filter);
static RS_IMAGE16 *ResizeH(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y);
static RS_IMAGE16 *ResizeV(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x);
+static RS_IMAGE16 *ResizeH_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y);
+static RS_IMAGE16 *ResizeV_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x);
static RSFilterClass *rs_resample_parent_class = NULL;
inline guint clampbits(gint x, guint n) { guint32 _y_temp; if( (_y_temp=x>>n) ) x = ~_y_temp >> (32-n); return x;}
@@ -155,8 +157,19 @@
if ((input_width == resample->new_width) && (input_height == resample->new_height))
return input;
- temp = ResizeH(input, input_width, resample->new_width, input_height);
- output = ResizeV(temp, input_height, resample->new_height, temp->w);
+ /* Use compatible (and slow) version if input isn't 3 channels and pixelsize 4 */
+ gboolean use_compatible = ( ! ( input->pixelsize == 4 && input->channels == 3));
+
+ if (use_compatible)
+ {
+ temp = ResizeH_compatible(input, input_width, resample->new_width, input_height);
+ output = ResizeV_compatible(temp, input_height, resample->new_height, temp->w);
+ }
+ else
+ {
+ temp = ResizeH(input, input_width, resample->new_width, input_height);
+ output = ResizeV(temp, input_height, resample->new_height, temp->w);
+ }
g_object_unref(temp);
g_object_unref(input);
@@ -395,3 +408,181 @@
return output;
}
+static RS_IMAGE16 *
+ResizeH_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y)
+{
+ gint pixelsize = input->pixelsize;
+ gint ch = input->channels;
+
+ gdouble pos_step = ((gdouble) old_size) / ((gdouble)new_size);
+ gdouble filter_step = MIN(1.0 / pos_step, 1.0);
+ gdouble filter_support = (gdouble) lanczos_taps() / filter_step;
+ gint fir_filter_size = (gint) (ceil(filter_support*2));
+ gint *weights = g_new(gint, new_size * fir_filter_size);
+ gint *offsets = g_new(gint, new_size);
+
+ RS_IMAGE16 *output = rs_image16_new(new_size, insize_y, ch, pixelsize);
+
+ g_assert(new_size > fir_filter_size);
+
+ gdouble pos = 0.0;
+ gint i,j,k;
+
+ for (i=0; i<new_size; ++i)
+ {
+ gint end_pos = (gint) (pos + filter_support);
+
+ if (end_pos > old_size-1)
+ end_pos = old_size-1;
+
+ gint start_pos = end_pos - fir_filter_size + 1;
+
+ if (start_pos < 0)
+ start_pos = 0;
+
+ offsets[i] = start_pos * pixelsize;
+
+ /* the following code ensures that the coefficients add to exactly FPScale */
+ gdouble total = 0.0;
+
+ /* Ensure that we have a valid position */
+ gdouble ok_pos = MAX(0.0,MIN(old_size-1,pos));
+
+ for (j=0; j<fir_filter_size; ++j)
+ {
+ /* Accumulate all coefficients */
+ total += lanczos_weight((start_pos+j - ok_pos) * filter_step);
+ }
+
+ g_assert(total > 0.0f);
+
+ gdouble total2 = 0.0;
+
+ for (k=0; k<fir_filter_size; ++k)
+ {
+ gdouble total3 = total2 + lanczos_weight((start_pos+k - ok_pos) * filter_step) / total;
+ weights[i*fir_filter_size+k] = (gint) (total3*FPScale+0.5) - (gint) (total2*FPScale+0.5);
+ total2 = total3;
+ }
+ pos += pos_step;
+ }
+
+
+ guint y,x,c;
+ for (y = 0; y < insize_y ; y++)
+ {
+ gint *wg = weights;
+ gushort *in_line = GET_PIXEL(input, 0, y);
+ gushort *out = GET_PIXEL(output, 0, y);
+
+ for (x = 0; x < new_size; x++)
+ {
+ guint i;
+ gushort *in = &in_line[offsets[x]];
+ for (c = 0 ; c < ch; c++)
+ {
+ gint acc = 0;
+
+ for (i = 0; i <fir_filter_size; i++)
+ {
+ acc += in[i*pixelsize+c]*wg[i];
+ }
+ out[x*pixelsize+c] = clampbits((acc + (FPScale/2))>>FPScaleShift, 16);
+ }
+ wg += fir_filter_size;
+ }
+ }
+
+ g_free(weights);
+ g_free(offsets);
+
+ return output;
+}
+
+static RS_IMAGE16 *
+ResizeV_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x)
+{
+ gint pixelsize = input->pixelsize;
+ gint ch = input->channels;
+
+ gdouble pos_step = ((gdouble) old_size) / ((gdouble)new_size);
+ gdouble filter_step = MIN(1.0 / pos_step, 1.0);
+ gdouble filter_support = (gdouble) lanczos_taps() / filter_step;
+ gint fir_filter_size = (gint) (ceil(filter_support*2));
+ gint *weights = g_new(gint, new_size * fir_filter_size);
+ gint *offsets = g_new(gint, new_size);
+
+ RS_IMAGE16 *output = rs_image16_new(insize_x, new_size, ch, pixelsize);
+
+ g_assert(new_size > fir_filter_size);
+
+ gdouble pos = 0.0;
+
+ gint i,j,k;
+
+ for (i=0; i<new_size; ++i)
+ {
+ gint end_pos = (gint) (pos + filter_support);
+ if (end_pos > old_size-1)
+ end_pos = old_size-1;
+
+ gint start_pos = end_pos - fir_filter_size + 1;
+
+ if (start_pos < 0)
+ start_pos = 0;
+
+ offsets[i] = start_pos;
+
+ /* The following code ensures that the coefficients add to exactly FPScale */
+ gdouble total = 0.0;
+
+ /* Ensure that we have a valid position */
+ gdouble ok_pos = MAX(0.0,MIN(old_size-1,pos));
+
+ for (j=0; j<fir_filter_size; ++j)
+ {
+ /* Accumulate all coefficients */
+ total += lanczos_weight((start_pos+j - ok_pos) * filter_step);
+ }
+
+ g_assert(total > 0.0f);
+
+ gdouble total2 = 0.0;
+
+ for (k=0; k<fir_filter_size; ++k)
+ {
+ gdouble total3 = total2 + lanczos_weight((start_pos+k - ok_pos) * filter_step) / total;
+ weights[i*fir_filter_size+k] = (gint) (total3*FPScale+0.5) - (gint) (total2*FPScale+0.5);
+ total2 = total3;
+ }
+ pos += pos_step;
+ }
+
+ guint y,x,c;
+ gint *wg = weights;
+
+ for (y = 0; y < new_size ; y++)
+ {
+ gushort *out = GET_PIXEL(output, 0, y);
+ for (x = 0; x < insize_x; x++)
+ {
+ gushort *in = GET_PIXEL(input, x, offsets[y]);
+ for (c = 0; c < ch; c++)
+ {
+ gint acc = 0;
+ for (i = 0; i < fir_filter_size; i++)
+ {
+ acc += in[i*input->rowstride]* wg[i];
+ }
+ out[x*pixelsize+c] = clampbits((acc + (FPScale/2))>>FPScaleShift, 16);
+ in++;
+ }
+ }
+ wg+=fir_filter_size;
+ }
+
+ g_free(weights);
+ g_free(offsets);
+
+ return output;
+}
More information about the Rawstudio-commit
mailing list