gegl r1910 - in trunk: . operations/workshop
- From: ok svn gnome org
- To: svn-commits-list gnome org
- Subject: gegl r1910 - in trunk: . operations/workshop
- Date: Thu, 24 Jan 2008 21:33:12 +0000 (GMT)
Author: ok
Date: Thu Jan 24 21:33:12 2008
New Revision: 1910
URL: http://svn.gnome.org/viewvc/gegl?rev=1910&view=rev
Log:
* operations/workshop/lens-correct.[ch]: added a lens correction
operation from Bradley Broom <bmbrom gmail com>.
* operations/workshop/demosaic-bimedian.c: updated bimedian filter.
Also modified the files to use "gegl-old-chant.h" for the chanting
for now.
Added:
trunk/operations/workshop/lens-correct.c
trunk/operations/workshop/lens-correct.h
Modified:
trunk/ChangeLog
trunk/operations/workshop/demosaic-bimedian.c
Modified: trunk/operations/workshop/demosaic-bimedian.c
==============================================================================
--- trunk/operations/workshop/demosaic-bimedian.c (original)
+++ trunk/operations/workshop/demosaic-bimedian.c Thu Jan 24 21:33:12 2008
@@ -70,12 +70,12 @@
t = c;
c = b;
if (a > t)
- {
- b = a;
- a = t;
- }
+ {
+ b = a;
+ a = t;
+ }
else
- b = t;
+ b = t;
}
/* Return average of central two elements. */
if (d >= c) /* Sorted order would be abcd */
@@ -109,76 +109,76 @@
dst_buf = g_malloc0 (gegl_buffer_get_pixel_count (dst) * 4 * 3);
gegl_buffer_get (src, 1.0, NULL, babl_format ("Y float"), src_buf,
- GEGL_AUTO_ROWSTRIDE);
+ GEGL_AUTO_ROWSTRIDE);
offset = ROW + COL;
doffset = 0;
for (y=dst_extent->y; y<dst_extent->height + dst_extent->y; y++)
{
for (x=dst_extent->x; x<dst_extent->width + dst_extent->x; x++)
- {
- gfloat red=0.0;
- gfloat green=0.0;
- gfloat blue=0.0;
-
- if ((y + op->pattern%2)%2==0)
- {
- if ((x+op->pattern/2)%2==1)
- {
- /* GRG
- * BGB
- * GRG
- */
- blue =(src_buf[offset-COL]+src_buf[offset+COL])/2.0;
- green=src_buf[offset];
- red =(src_buf[offset-ROW]+src_buf[offset+ROW])/2.0;
- }
- else
- {
- /* RGR
- * GBG
- * RGR
- */
- blue =src_buf[offset];
- green=m4(src_buf[offset-ROW], src_buf[offset-COL],
- src_buf[offset+COL], src_buf[offset+ROW]);
- red =m4(src_buf[offset-ROW-COL], src_buf[offset-ROW+COL],
- src_buf[offset+ROW-COL], src_buf[offset+ROW+COL]);
- }
- }
- else
- {
- if ((x+op->pattern/2)%2==1)
- {
- /* BGB
- * GRG
- * BGB
- */
- blue =m4(src_buf[offset-ROW-COL], src_buf[offset-ROW+COL],
- src_buf[offset+ROW-COL], src_buf[offset+ROW+COL]);
- green=m4(src_buf[offset-ROW], src_buf[offset-COL],
- src_buf[offset+COL], src_buf[offset+ROW]);
- red =src_buf[offset];
- }
- else
- {
- /* GBG
- * RGR
- * GBG
- */
- blue =(src_buf[offset-ROW]+src_buf[offset+ROW])/2.0;
- green=src_buf[offset];
- red =(src_buf[offset-COL]+src_buf[offset+COL])/2.0;
- }
- }
-
- dst_buf [doffset*3+0] = red;
- dst_buf [doffset*3+1] = green;
- dst_buf [doffset*3+2] = blue;
-
- offset++;
- doffset++;
- }
+ {
+ gfloat red=0.0;
+ gfloat green=0.0;
+ gfloat blue=0.0;
+
+ if ((y + op->pattern%2)%2==0)
+ {
+ if ((x+op->pattern/2)%2==1)
+ {
+ /* GRG
+ * BGB
+ * GRG
+ */
+ blue =(src_buf[offset-COL]+src_buf[offset+COL])/2.0;
+ green=src_buf[offset];
+ red =(src_buf[offset-ROW]+src_buf[offset+ROW])/2.0;
+ }
+ else
+ {
+ /* RGR
+ * GBG
+ * RGR
+ */
+ blue =src_buf[offset];
+ green=m4(src_buf[offset-ROW], src_buf[offset-COL],
+ src_buf[offset+COL], src_buf[offset+ROW]);
+ red =m4(src_buf[offset-ROW-COL], src_buf[offset-ROW+COL],
+ src_buf[offset+ROW-COL], src_buf[offset+ROW+COL]);
+ }
+ }
+ else
+ {
+ if ((x+op->pattern/2)%2==1)
+ {
+ /* BGB
+ * GRG
+ * BGB
+ */
+ blue =m4(src_buf[offset-ROW-COL], src_buf[offset-ROW+COL],
+ src_buf[offset+ROW-COL], src_buf[offset+ROW+COL]);
+ green=m4(src_buf[offset-ROW], src_buf[offset-COL],
+ src_buf[offset+COL], src_buf[offset+ROW]);
+ red =src_buf[offset];
+ }
+ else
+ {
+ /* GBG
+ * RGR
+ * GBG
+ */
+ blue =(src_buf[offset-ROW]+src_buf[offset+ROW])/2.0;
+ green=src_buf[offset];
+ red =(src_buf[offset-COL]+src_buf[offset+COL])/2.0;
+ }
+ }
+
+ dst_buf [doffset*3+0] = red;
+ dst_buf [doffset*3+1] = green;
+ dst_buf [doffset*3+2] = blue;
+
+ offset++;
+ doffset++;
+ }
offset+=2;
}
Added: trunk/operations/workshop/lens-correct.c
==============================================================================
--- (empty file)
+++ trunk/operations/workshop/lens-correct.c Thu Jan 24 21:33:12 2008
@@ -0,0 +1,402 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL 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 3 of the License, or (at your option) any later version.
+ *
+ * GEGL 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 GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2006 Ãyvind KolÃs <pippin gimp org>
+ * Copyright 2008 Bradley Broom <bmbroom gmail com>
+ */
+#if GEGL_CHANT_PROPERTIES
+
+gegl_chant_pointer (lens_info_pointer, "Pointer to LensCorrectionModel")
+
+#else
+
+#define GEGL_CHANT_NAME lens_correct
+#define GEGL_CHANT_SELF "lens-correct.c"
+#define GEGL_CHANT_DESCRIPTION "Copies image performing lens distortion correction."
+#define GEGL_CHANT_CATEGORIES "blur"
+#define GEGL_CHANT_CLASS_INIT /* we need to modify the standard class init of the super class */
+
+#define GEGL_CHANT_FILTER
+
+#include "gegl-old-chant.h"
+
+#include <math.h>
+
+#include "lens-correct.h"
+
+#if 0
+#define TRACE /* Define this to see basic tracing info. */
+#endif
+
+/* Find the src pixel that maps to the destination pixel passed as parameters x and y.
+ */
+static void
+find_src_pixel (LensCorrectionModel *lcip, ChannelCorrectionModel *pp,
+ gfloat x, gfloat y, gfloat *srcx, gfloat *srcy)
+{
+ double r, radj;
+ double dx, dy;
+
+ r = hypot (x - lcip->cx, y - lcip->cy) / lcip->rscale;
+ radj = (((pp->a*r+pp->b)*r+pp->c)*r+pp->d);
+ *srcx = (x - lcip->cx) * radj + lcip->cx;
+ *srcy = (y - lcip->cy) * radj + lcip->cy;
+}
+
+/* Find dst pixel that comes from the source pixel passed as parameters x and y.
+ */
+static void
+find_dst_pixel (LensCorrectionModel *lcip, ChannelCorrectionModel *pp,
+ gfloat x, gfloat y, gfloat *dstx, gfloat *dsty)
+{
+ /* Compute scaled distance of pixel from image center. */
+ gfloat srcr = hypot (x - lcip->cx, y - lcip->cy) / lcip->rscale;
+
+ /* Main path doesn't work for srcr == 0, but no need if pixel is close
+ * to image center.
+ */
+ if (srcr < 0.01/lcip->rscale) {
+ *dstx = x;
+ *dsty = y;
+ }
+ else {
+ gfloat dstr = srcr;
+ gfloat r;
+ #ifdef COUNT_IT
+ int it = 0;
+ #endif
+
+ /* Adjust dstr until r is within about one hundred of a pixel of srcr.
+ * Usually, one iteration is enough.
+ */
+ r = (((pp->a*dstr+pp->b)*dstr+pp->c)*dstr+pp->d) * dstr;
+ while (fabs (r - srcr) > 0.01/lcip->rscale) {
+ /* Compute derivative of lens distortion function at dstr. */
+ gfloat dr = ((4.0*pp->a*dstr+3.0*pp->b)*dstr+2.0*pp->c)*dstr+pp->d;
+ if (fabs(dr) < 1.0e-5) {
+ /* In theory, the derivative of a quartic function can have zeros,
+ * but I don't think any valid lens correction model will.
+ * Still, we check to avoid an infinite loop if the ChannelCorrectionModel is broken.
+ */
+ g_warning ("find_dst_pixel: x=%g y=%g found zero slope, bailing out", x, y);
+ break;
+ }
+ /* Adjust dstr based on error distance and current derivative. */
+ dstr += (srcr-r)/dr;
+ #ifdef COUNT_IT
+ it++;
+ #endif
+ r = (((pp->a*dstr+pp->b)*dstr+pp->c)*dstr+pp->d) * dstr;
+ }
+ #ifdef COUNT_IT
+ g_warning ("find_dst_pixel: iterations == %d", it);
+ #endif
+
+ /* Compute dst x,y coords from change in radial distance from image center. */
+ *dstx = (x - lcip->cx) * (dstr/srcr) + lcip->cx;
+ *dsty = (y - lcip->cy) * (dstr/srcr) + lcip->cy;
+ }
+}
+
+/* Define the type of the above two functions.
+ */
+typedef void pixel_map_func (LensCorrectionModel *lcip, ChannelCorrectionModel *pp,
+ gfloat x, gfloat y, gfloat *dstx, gfloat *dsty);
+
+/* Compute the bounding box of the GeglRectangle, *in_rect,
+ * when passed through the pixel mapping function given by *mappix,
+ * using the LensCorrectionModel *lcip.
+ *
+ * The implementation assumes that the LensCorrectionModel is monotonic.
+ */
+static GeglRectangle
+map_region (const GeglRectangle *in_rect, LensCorrectionModel *lcip, pixel_map_func *mappix)
+{
+ GeglRectangle result = *in_rect;
+
+ #ifdef TRACE
+ g_warning ("> map_region in_rect=%dx%d+%d+%d", in_rect->width, in_rect->height, in_rect->x, in_rect->y);
+ #endif
+
+ if (result.width != 0 && result.height != 0)
+ {
+ gint ii;
+ gfloat x, y;
+ gfloat minx, miny, maxx, maxy;
+
+ /* To find the bounding box of the mapped pixels, we go around the
+ * perimeter of in_rect mapping each pixel. By keeping track of
+ * the min/max x/y coordinates thus obtained, we compute the bounding box.
+ */
+ (*mappix) (lcip, &lcip->green, in_rect->x, in_rect->y, &minx, &miny);
+ maxx = minx; maxy = miny;
+ for (ii = 0; ii < 2*(in_rect->width+in_rect->height); ii++) {
+ /* Compute srcx,srcy coordinate for this point on the perimeter. */
+ gint srcx = in_rect->x;
+ gint srcy = in_rect->y;
+ if (ii < in_rect->width)
+ {
+ srcx += ii;
+ }
+ else if (ii < in_rect->width + in_rect->height)
+ {
+ srcx += in_rect->width;
+ srcy += (ii - in_rect->width);
+ }
+ else if (ii < 2*in_rect->width + in_rect->height)
+ {
+ srcy += in_rect->height;
+ srcx += 2*in_rect->width + in_rect->height - ii;
+ }
+ else
+ {
+ srcy += 2*(in_rect->width + in_rect->height) - ii;
+ }
+ /* Find dst pixels for each color channel. */
+ (*mappix) (lcip, &lcip->green, srcx, srcy, &x, &y);
+ if (x < minx) minx = x;
+ else if (x > maxx) maxx = x;
+ if (y < miny) miny = y;
+ else if (y > maxy) maxy = y;
+ (*mappix) (lcip, &lcip->red, srcx, srcy, &x, &y);
+ if (x < minx) minx = x;
+ else if (x > maxx) maxx = x;
+ if (y < miny) miny = y;
+ else if (y > maxy) maxy = y;
+ (*mappix) (lcip, &lcip->blue, srcx, srcy, &x, &y);
+ if (x < minx) minx = x;
+ else if (x > maxx) maxx = x;
+ if (y < miny) miny = y;
+ else if (y > maxy) maxy = y;
+ }
+ result.x = minx;
+ result.y = miny;
+ result.width = maxx - minx + 1;
+ result.height = maxy - miny + 1;
+ }
+ #ifdef TRACE
+ g_warning ("< map_region result=%dx%d+%d+%d", result.width, result.height, result.x, result.y);
+ #endif
+ return result;
+}
+
+/* We expect src_extent to include all pixels required to form the
+ * pixels of dst_extent.
+ */
+#define ROW src_extent->width
+#define COL 1
+static void
+copy_through_lens (GeglChantOperation *op,
+ LensCorrectionModel *oip,
+ GeglBuffer *src,
+ GeglBuffer *dst)
+{
+ const GeglRectangle *src_extent;
+ const GeglRectangle *dst_extent;
+ gfloat *src_buf;
+ gfloat *dst_buf;
+ gint x,y; /* Coordinate of current dst pixel. */
+ gint rgb; /* Color channel of dst pixel being processed. */
+ gint doffset; /* Buffer offset of current dst pixel. */
+ gint tmpx, tmpy, toff;
+ ChannelCorrectionModel *ccm[3]; /* Allow access to red,green,blue models in loop. */
+
+ src_extent = gegl_buffer_get_extent (src);
+ #ifdef TRACE
+ g_warning ("> copy_through_lens src_extent = %dx%d+%d+%d",
+ src_extent->width, src_extent->height, src_extent->x,src_extent->y);
+ #endif
+ if (dst == NULL)
+ {
+ #ifdef TRACE
+ g_warning (" dst is NULL");
+ g_warning ("< copy_through_lens");
+ #endif
+ return;
+ }
+ dst_extent = gegl_buffer_get_extent (dst);
+ if (dst_extent == NULL) {
+ #ifdef TRACE
+ g_warning (" dst_extent is NULL");
+ g_warning ("< copy_through_lens");
+ #endif
+ return;
+ }
+
+ /* Get src pixels. */
+ src_buf = g_malloc0 (gegl_buffer_get_pixel_count (src) * 4 * 3);
+ gegl_buffer_get (src, 1.0, NULL, babl_format ("RGB float"), src_buf, GEGL_AUTO_ROWSTRIDE);
+
+ /* Get buffer in which to place dst pixels. */
+ dst_buf = g_malloc0 (gegl_buffer_get_pixel_count (dst) * 4 * 3);
+
+ /* Compute each dst pixel in turn and store into dst buffer. */
+ ccm[0] = &oip->red;
+ ccm[1] = &oip->green;
+ ccm[2] = &oip->blue;
+ doffset = 0;
+ for (y=dst_extent->y; y<dst_extent->height + dst_extent->y; y++)
+ {
+ for (x=dst_extent->x; x<dst_extent->width + dst_extent->x; x++)
+ {
+ for (rgb = 0; rgb < 3; rgb++)
+ {
+ gfloat gx, gy;
+ gfloat val = 0.0;
+ gint xx, yy;
+ gfloat wx[2], wy[2], wt = 0.0;
+
+ find_src_pixel (oip, ccm[rgb], (gfloat)x, (gfloat)y, &gx, &gy);
+ tmpx = gx;
+ tmpy = gy;
+ wx[1] = gx - tmpx;
+ wx[0] = 1.0 - wx[1];
+ wy[1] = gy - tmpy;
+ wy[0] = 1.0 - wy[1];
+ tmpx -= src_extent->x;
+ tmpy -= src_extent->y;
+ toff = (tmpy * ROW + tmpx) * 3;
+ for (xx = 0; xx < 2; xx++)
+ {
+ for (yy = 0; yy < 2; yy++)
+ {
+ if (tmpx+xx >= 0 && tmpx+xx < src_extent->width &&
+ tmpy+yy >= 0 && tmpy+yy < src_extent->height)
+ {
+ val += src_buf[toff+(yy*ROW+xx)*3+rgb] * wx[xx] * wy[yy];
+ wt += wx[xx] * wy[yy];
+ }
+ }
+ }
+ if (wt <= 0)
+ {
+ g_warning ("gegl_lens_correct: mapped pixel %g,%g not in %dx%d+%d+%d", gx, gy,
+ src_extent->width, src_extent->height, src_extent->x, src_extent->y);
+ g_warning (" dst = %dx%d+%d+%d", dst_extent->width, dst_extent->height, dst_extent->x,dst_extent->y);
+ dst_buf [doffset+rgb] = 0.0;
+ }
+ else
+ {
+ dst_buf [doffset+rgb] = val / wt;
+ }
+ }
+ doffset+=3;
+ }
+ }
+
+ /* Store dst pixels. */
+ gegl_buffer_set (dst, NULL, babl_format ("RGB float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
+
+ /* Free acquired storage. */
+ g_free (src_buf);
+ g_free (dst_buf);
+
+ #ifdef TRACE
+ g_warning ("< copy_through_lens");
+ #endif
+}
+
+/*****************************************************************************/
+
+/* Compute the region for which this operation is defined.
+ */
+static GeglRectangle
+get_defined_region (GeglOperation *operation)
+{
+ GeglRectangle result = {0,0,0,0};
+ GeglRectangle *in_rect = gegl_operation_source_get_defined_region (operation, "input");
+ GeglChantOperation *area = GEGL_CHANT_OPERATION (operation);
+
+ #ifdef TRACE
+ g_warning ("> get_defined_region pointer == 0x%x in_rect == 0x%x", area->lens_info_pointer, in_rect);
+ #endif
+ if (in_rect && area->lens_info_pointer)
+ result = map_region (in_rect, area->lens_info_pointer, find_dst_pixel);
+
+ #ifdef TRACE
+ g_warning ("< get_defined_region result = %dx%d+%d+%d", result.width, result.height, result.x, result.y);
+ #endif
+ return result;
+}
+
+/* Compute the input rectangle required to compute the specified region of interest (roi).
+ */
+static GeglRectangle
+compute_input_request (GeglOperation *operation,
+ const gchar *input_pad,
+ const GeglRectangle *roi)
+{
+ GeglChantOperation *area = GEGL_CHANT_OPERATION (operation);
+ GeglRectangle result = *gegl_operation_source_get_defined_region (operation, "input");
+ #ifdef TRACE
+ g_warning ("> compute_input_request src=%dx%d+%d+%d", result.width, result.height, result.x, result.y);
+ if (roi)
+ g_warning (" ROI == %dx%d+%d+%d", roi->width, roi->height, roi->x, roi->y);
+ #endif
+ if (roi && area->lens_info_pointer) {
+ result = map_region (roi, area->lens_info_pointer, find_src_pixel);
+ result.width++;
+ result.height++;
+ }
+ #ifdef TRACE
+ g_warning ("< compute_input_request res=%dx%d+%d+%d", result.width, result.height, result.x, result.y);
+ #endif
+ return result;
+}
+
+/* Specify the input and output buffer formats.
+ */
+static void
+prepare (GeglOperation *operation)
+{
+ #ifdef TRACE
+ g_warning ("> prepare");
+ #endif
+ gegl_operation_set_format (operation, "input", babl_format ("RGB float"));
+ gegl_operation_set_format (operation, "output", babl_format ("RGB float"));
+ #ifdef TRACE
+ g_warning ("< prepare");
+ #endif
+}
+
+/* Perform the specified operation.
+ */
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *result)
+{
+ GeglChantOperation *self = GEGL_CHANT_OPERATION (operation);
+
+ copy_through_lens (self, self->lens_info_pointer, input, output);
+
+ return TRUE;
+}
+
+/* This is called at the end of the gobject class_init function, the
+ * definition of GEGL_CHANT_CLASS_INIT above is needed to make this happen.
+ *
+ * Here we override the standard passthrough options for the rect
+ * computations.
+ */
+static void class_init (GeglOperationClass *operation_class)
+{
+ operation_class->get_defined_region = get_defined_region;
+ operation_class->compute_input_request = compute_input_request;
+ operation_class->prepare = prepare;
+}
+
+#endif
Added: trunk/operations/workshop/lens-correct.h
==============================================================================
--- (empty file)
+++ trunk/operations/workshop/lens-correct.h Thu Jan 24 21:33:12 2008
@@ -0,0 +1,26 @@
+#ifndef _LENS_CORRECT_H_
+#define _LENS_CORRECT_H_
+
+/* Struct containing the correction parameters a,b,c,d for a lens color channel.
+ * These parameters as the same as used in the Panotools system.
+ * For a detailed explanation, please consult http://wiki.panotools.org/Lens_correction_model
+ *
+ * Normally a, b, and c are close to zero, and d is close to one.
+ * Note that d is the parameter that's approximately equal to 1 - a - b - c, NOT one of the image
+ * shift parameters as used in some GUIs.
+ */
+typedef struct {
+ gfloat a, b, c, d;
+} ChannelCorrectionModel;
+
+/* Struct containing all the information required for lens correction. It includes the total size
+ * of the image plus the correction parameters for each color channel.
+ */
+typedef struct {
+ GeglRectangle BB; /* Bounding box of the imaged area. */
+ gfloat cx, cy; /* Coordinates of lens center within the imaged area. */
+ gfloat rscale; /* Scale of the image (1/2 of the shortest side). */
+ ChannelCorrectionModel red, green, blue; /* Correction parameters for each color channel. */
+} LensCorrectionModel;
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]