applied patch from Jörg Gittinger that improves the quality of the Motion

2007-05-16  Sven Neumann  <sven@gimp.org>

	* plug-ins/common/mblur.c: applied patch from Jörg Gittinger 
that
	improves the quality of the Motion Blur filter (bug #380435).


svn path=/trunk/; revision=22513
This commit is contained in:
Sven Neumann 2007-05-16 17:40:13 +00:00 committed by Sven Neumann
parent 8684b3267c
commit 3c9f28cc1e
2 changed files with 179 additions and 84 deletions

View File

@ -1,3 +1,8 @@
2007-05-16 Sven Neumann <sven@gimp.org>
* plug-ins/common/mblur.c: applied patch from Jörg Gittinger that
improves the quality of the Motion Blur filter (bug #380435).
2007-05-16 Sven Neumann <sven@gimp.org>
* plug-ins/script-fu/script-fu-interface.c (script_fu_interface):

View File

@ -15,6 +15,8 @@
* I also used some code from Whirl and Pinch plug-in by Federico Mena Quintero
* (federico@nuclecu.unam.mx)
*
* Copyright (C) 2007 Joerg Gittinger (sw@gittingerbox.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@ -30,22 +32,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Version 1.2
*
* Everything is new - no changes
*
* TODO:
* Bilinear interpolation from original mblur for 0.54
* Speed all things up
* ? better caching scheme
* - while blurring along long trajectory do not average all
* pixels but average only few samples
* Function for weight of samples along trajectory
* Preview
* Support paths in GiMP 1.1 :-)
* Smash all bugs :-)
*/
#include "config.h"
#include <libgimp/gimp.h>
@ -56,7 +42,10 @@
#define PLUG_IN_PROC "plug-in-mblur"
#define PLUG_IN_BINARY "mblur"
#define PLUG_IN_VERSION "Sep 1997, 1.2"
#define PLUG_IN_VERSION "May 2007, 1.3"
#define MBLUR_LENGTH_MAX 256.0
typedef enum
@ -126,11 +115,11 @@ static mblur_vals_t mbvals =
{
MBLUR_LINEAR, /* mblur_type */
5, /* length */
45, /* radius */
10, /* radius */
100000.0, /* center_x */
100000.0, /* center_y */
TRUE, /* blur_outward */
FALSE /* preview */
TRUE /* preview */
};
@ -168,8 +157,8 @@ query (void)
"This plug-in simulates the effect seen when "
"photographing a moving object at a slow shutter "
"speed. Done by adding multiple displaced copies.",
"Torsten Martinsen, Federico Mena Quintero and Daniel Skarda",
"Torsten Martinsen, Federico Mena Quintero and Daniel Skarda",
"Torsten Martinsen, Federico Mena Quintero, Daniel Skarda, Joerg Gittinger",
"Torsten Martinsen, Federico Mena Quintero, Daniel Skarda, Joerg Gittinger",
PLUG_IN_VERSION,
N_("_Motion Blur..."),
"RGB*, GRAY*",
@ -235,7 +224,7 @@ run (const gchar *name,
/* Make sure all the arguments are present */
if (nparams == 9)
{
mbvals.blur_outward = param[6].data.d_int32;
mbvals.blur_outward = param[8].data.d_int32;
--nparams;
}
@ -312,7 +301,7 @@ mblur_linear (GimpDrawable *drawable,
guchar pixel[4];
gint32 sum[4];
gint progress, max_progress;
gint c;
gint c, p;
gint x, y, i, xx, yy, n;
gint dx, dy, px, py, swapdir, err, e, s1, s2;
@ -376,9 +365,9 @@ mblur_linear (GimpDrawable *drawable,
err = dy - dx; /* Initial error term */
dx *= 2;
for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
for (pr = gimp_pixel_rgns_register (1, &dest_rgn), p = 0;
pr != NULL;
pr = gimp_pixel_rgns_process (pr))
pr = gimp_pixel_rgns_process (pr), p++)
{
dest = dest_rgn.data;
@ -395,6 +384,7 @@ mblur_linear (GimpDrawable *drawable,
for (i = 0; i < n; )
{
gimp_pixel_fetcher_get_pixel (pft, xx, yy, pixel);
if (has_alpha)
{
gint32 alpha = pixel[img_bpp-1];
@ -468,13 +458,16 @@ mblur_linear (GimpDrawable *drawable,
else
{
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((gdouble) progress / max_progress);
if ((p % 8) == 0)
gimp_progress_update ((gdouble) progress / max_progress);
}
}
gimp_pixel_fetcher_destroy (pft);
}
static void
mblur_radial (GimpDrawable *drawable,
GimpPreview *preview,
@ -493,13 +486,15 @@ mblur_radial (GimpDrawable *drawable,
guchar *dest;
guchar *d;
guchar pixel[4];
guchar p1[4], p2[4], p3[4], p4[4];
gint32 sum[4];
gint progress, max_progress, c;
gint x, y, i, n, xr, yr;
gint count, R, r, w, h, step;
gfloat angle, theta, * ct, * st, offset, xx, yy;
gint x, y, i, p, n, count;
gdouble angle, theta, r, xx, yy, xr, yr;
gdouble phi, phi_start, s_val, c_val;
gdouble dx, dy;
/* initialize */
@ -522,25 +517,9 @@ mblur_radial (GimpDrawable *drawable,
angle = gimp_deg_to_rad (mbvals.angle);
w = MAX (img_width - center_x, center_x);
h = MAX (img_height - center_y, center_y);
R = sqrt (w * w + h * h);
n = 4 * angle * sqrt (R) + 2;
theta = angle / ((float) (n - 1));
ct = g_new (float, n);
st = g_new (float, n);
offset = theta * (n - 1) / 2;
for (i = 0; i < n; ++i)
{
ct[i] = cos (theta * i - offset);
st[i] = sin (theta * i - offset);
}
for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
for (pr = gimp_pixel_rgns_register (1, &dest_rgn), p = 0;
pr != NULL;
pr = gimp_pixel_rgns_process (pr))
pr = gimp_pixel_rgns_process (pr), p++)
{
dest = dest_rgn.data;
@ -550,31 +529,88 @@ mblur_radial (GimpDrawable *drawable,
for (x = dest_rgn.x; x < dest_rgn.x + dest_rgn.w; x++)
{
xr = x - center_x;
yr = y - center_y;
r = sqrt (xr * xr + yr * yr);
xr = (gdouble) x - center_x;
yr = (gdouble) y - center_y;
if (r == 0)
step = 1;
else if ((step = R / r) == 0)
step = 1;
else if (step > n-1)
step = n-1;
r = sqrt (SQR (xr) + SQR (yr));
n = r * angle;
if (angle == 0.0)
{
gimp_pixel_fetcher_get_pixel (pft, x, y, d);
d += dest_rgn.bpp;
continue;
}
/* ensure quality with small angles */
if (n < 3)
n = 3; /* always use at least 3 (interpolation) steps */
/* limit loop count due to performanc reasons */
if (n > 100)
n = 100 + sqrt (n-100);
if (xr != 0.0)
{
phi = atan(yr/xr);
if (xr < 0.0)
phi = G_PI + phi;
}
else
{
if (yr >= 0.0)
phi = G_PI_2;
else
phi = -G_PI_2;
}
for (c = 0; c < img_bpp; c++)
sum[c] = 0;
for (i = 0, count = 0; i < n; i += step)
if (n == 1)
phi_start = phi;
else
phi_start = phi + angle/2.0;
theta = angle / (gdouble)n;
count = 0;
for (i = 0; i < n; i++)
{
xx = center_x + xr * ct[i] - yr * st[i];
yy = center_y + xr * st[i] + yr * ct[i];
s_val = sin (phi_start - (gdouble) i * theta);
c_val = cos (phi_start - (gdouble) i * theta);
xx = center_x + r * c_val;
yy = center_y + r * s_val;
if ((yy < y1) || (yy >= y1 + height) ||
(xx < x1) || (xx >= x1 + width))
continue;
++count;
gimp_pixel_fetcher_get_pixel (pft, xx, yy, pixel);
if ((xx + 1 < x1 + width) && (yy + 1 < y1 + height))
{
dx = xx - floor (xx);
dy = yy - floor (yy);
gimp_pixel_fetcher_get_pixel (pft, xx, yy, p1);
gimp_pixel_fetcher_get_pixel (pft, xx+1, yy, p2);
gimp_pixel_fetcher_get_pixel (pft, xx, yy+1, p3);
gimp_pixel_fetcher_get_pixel (pft, xx+1, yy+1, p4);
for (c = 0; c < img_bpp; c++)
{
pixel[c] = (((gdouble) p1[c] * (1.0-dx) +
(gdouble) p2[c] * dx) * (1.0-dy) +
((gdouble) p3[c] * (1.0-dx) +
(gdouble) p4[c] * dx) * dy);
}
}
else
{
gimp_pixel_fetcher_get_pixel (pft, xx+.5, yy+.5, pixel);
}
if (has_alpha)
{
@ -629,16 +665,17 @@ mblur_radial (GimpDrawable *drawable,
else
{
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / max_progress);
if ((p % 8) == 0)
gimp_progress_update ((gdouble) progress / max_progress);
}
}
gimp_pixel_fetcher_destroy (pft);
g_free (ct);
g_free (st);
}
static void
mblur_zoom (GimpDrawable *drawable,
GimpPreview *preview,
@ -656,11 +693,17 @@ mblur_zoom (GimpDrawable *drawable,
gdouble center_y;
guchar *dest, *d;
guchar pixel[4];
guchar p1[4], p2[4], p3[4], p4[4];
gint32 sum[4];
gint progress, max_progress;
gint x, y, i, xx, yy, n, c;
gfloat f;
gint x, y, i, n, p, c;
gdouble xx_start, xx_end, yy_start, yy_end;
gdouble xx, yy;
gdouble dxx, dyy;
gdouble dx, dy;
gint xy_len;
gdouble f, r;
gint drawable_x1, drawable_y1;
gint drawable_x2, drawable_y2;
@ -686,11 +729,17 @@ mblur_zoom (GimpDrawable *drawable,
max_progress = width * height;
n = mbvals.length;
f = 0.02;
for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
if (n == 0)
n = 1;
r = sqrt (SQR (drawable->width / 2) + SQR (drawable->height / 2));
n = ((gdouble) n * r / MBLUR_LENGTH_MAX);
f = (r-n)/r;
for (pr = gimp_pixel_rgns_register (1, &dest_rgn), p = 0;
pr != NULL;
pr = gimp_pixel_rgns_process (pr))
pr = gimp_pixel_rgns_process (pr), p++)
{
dest = dest_rgn.data;
@ -703,24 +752,60 @@ mblur_zoom (GimpDrawable *drawable,
for (c = 0; c < img_bpp; c++)
sum[c] = 0;
for (i = 0; i < n; ++i)
{
if (mbvals.blur_outward)
{
xx = center_x + (x - center_x) * (1.0 - f * i);
yy = center_y + (y - center_y) * (1.0 - f * i);
}
else
{
xx = center_x + (x - center_x) * (1.0 + f * i);
yy = center_y + (y - center_y) * (1.0 + f * i);
}
xx_start = x;
yy_start = y;
if (mbvals.blur_outward)
{
xx_end = center_x + ((gdouble) x - center_x) * f;
yy_end = center_y + ((gdouble) y - center_y) * f;
}
else
{
xx_end = center_x + ((gdouble) x - center_x) * (1.0/f);
yy_end = center_y + ((gdouble) y - center_y) * (1.0/f);
}
xy_len = sqrt (SQR (xx_end-xx_start) + SQR (yy_end-yy_start)) + 1;
if (xy_len < 3)
xy_len = 3;
dxx = (xx_end - xx_start) / (gdouble) xy_len;
dyy = (yy_end - yy_start) / (gdouble) xy_len;
xx = xx_start;
yy = yy_start;
for (i = 0; i < xy_len; i++)
{
if ((yy < drawable_y1) || (yy >= drawable_y2) ||
(xx < drawable_x1) || (xx >= drawable_x2))
break;
gimp_pixel_fetcher_get_pixel (pft, xx, yy, pixel);
if ((xx+1 < drawable_x2) && (yy+1 < drawable_y2))
{
dx = xx - floor (xx);
dy = yy - floor (yy);
gimp_pixel_fetcher_get_pixel (pft, xx, yy, p1);
gimp_pixel_fetcher_get_pixel (pft, xx+1, yy, p2);
gimp_pixel_fetcher_get_pixel (pft, xx, yy+1, p3);
gimp_pixel_fetcher_get_pixel (pft, xx+1, yy+1, p4);
for (c = 0; c < img_bpp; c++)
{
pixel[c] = (((gdouble)p1[c] * (1.0-dx) +
(gdouble)p2[c] * dx) * (1.0-dy) +
((gdouble)p3[c] * (1.0-dx) +
(gdouble)p4[c] * dx) * dy);
}
}
else
{
gimp_pixel_fetcher_get_pixel (pft, xx+.5, yy+.5, pixel);
}
if (has_alpha)
{
gint32 alpha = pixel[img_bpp-1];
@ -735,6 +820,9 @@ mblur_zoom (GimpDrawable *drawable,
for (c = 0; c < img_bpp; c++)
sum[c] += pixel[c];
}
xx += dxx;
yy += dyy;
}
if (i == 0)
@ -774,7 +862,9 @@ mblur_zoom (GimpDrawable *drawable,
else
{
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / max_progress);
if ((p % 8) == 0)
gimp_progress_update ((gdouble) progress / max_progress);
}
}
@ -840,7 +930,7 @@ mblur (GimpDrawable *drawable,
static void
mblur_set_sensitivity (void)
{
if (!length || !angle)
if (!length || !angle || !center || !dir_button)
return; /* Not initialized yet */
switch (mbvals.mblur_type)
@ -1021,7 +1111,7 @@ mblur_dialog (gint32 image_ID,
length = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
_("L_ength:"), 150, 3,
mbvals.length, 1.0, 256.0, 1.0, 8.0, 0,
mbvals.length, 1.0, MBLUR_LENGTH_MAX, 1.0, 8.0, 0,
TRUE, 0, 0,
NULL, NULL);