[gegl/soc-2011-ops] Added lens-correct op, will the option to use lensfun library later
- From: Robert Sasu <sasurobert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/soc-2011-ops] Added lens-correct op, will the option to use lensfun library later
- Date: Tue, 16 Aug 2011 12:55:28 +0000 (UTC)
commit 7a3cfcfbf4cf69caae34d72100a48420cb2937a6
Author: Robert Sasu <sasu robert gmail com>
Date: Tue Aug 16 15:55:01 2011 +0300
Added lens-correct op, will the option to use lensfun library later
operations/workshop/lens-correct.c | 556 ++++++++++++++++--------------------
1 files changed, 241 insertions(+), 315 deletions(-)
---
diff --git a/operations/workshop/lens-correct.c b/operations/workshop/lens-correct.c
index 163004f..cd559b5 100644
--- a/operations/workshop/lens-correct.c
+++ b/operations/workshop/lens-correct.c
@@ -15,6 +15,7 @@
*
* Copyright 2006 Ãyvind KolÃs <pippin gimp org>
* Copyright 2008 Bradley Broom <bmbroom gmail com>
+ * Copyright 2011 Robert Sasu <sasu robert gmail com>
*/
#include "config.h"
@@ -23,8 +24,58 @@
#ifdef GEGL_CHANT_PROPERTIES
-gegl_chant_pointer (lens_info_pointer, _("Model"),
- _("Pointer to LensCorrectionModel"))
+gegl_chant_string (type, _("Lens type:"),"none",
+ _("Write your lens model with majuscules"))
+
+gegl_chant_boolean (center, _("Center"), TRUE,
+ _("If you want center"))
+gegl_chant_int (cx, _("Lens center x"), -G_MAXINT, G_MAXINT, 0,
+ _("Coordinates of lens center"))
+gegl_chant_int (cy, _("Lens center y"), -G_MAXINT, G_MAXINT, 0,
+ _("Coordinates of lens center"))
+gegl_chant_double (rscale, _("Scale"), 0.001, 10.0, 0.5,
+ _("Scale of the image"))
+gegl_chant_boolean (correct, _("Autocorrect d values"), TRUE,
+ _("Autocorrect D values for lens correction models."))
+
+gegl_chant_double (focal, _("Focal of the camera"), 0.0, 300.0, 0.0,
+ _("Calculate b value from focal"))
+
+gegl_chant_double (red_a, _("Model red a:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (red_b, _("Model red b:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (red_c, _("Model red c:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (red_d, _("Model red d:"), 0.0, 2.0, 1.0,
+ _("Correction parameters for each color channel"))
+
+gegl_chant_double (green_a, _("Model green a:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (green_b, _("Model green b:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (green_c, _("Model green c:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (green_d, _("Model green d:"), 0.0, 2.0, 1.00,
+ _("Correction parameters for each color channel"))
+
+gegl_chant_double (blue_a, _("Model blue a:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (blue_b, _("Model blue b:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (blue_c, _("Model blue c:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for each color channel"))
+gegl_chant_double (blue_d, _("Model blue d:"), 0.0, 2.0, 1.0,
+ _("Correction parameters for each color channel"))
+
+gegl_chant_double (alpha_a, _("Model alpha a:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for alpha channel"))
+gegl_chant_double (alpha_b, _("Model alpha b:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for alpha channel"))
+gegl_chant_double (alpha_c, _("Model alpha c:"), -1.0, 1.0, 0.0,
+ _("Correction parameters for alpha channel"))
+gegl_chant_double (alpha_d, _("Model alpha d:"), 0.0, 2.0, 1.0,
+ _("Correction parameters for alpha channel"))
#else
@@ -35,350 +86,225 @@ gegl_chant_pointer (lens_info_pointer, _("Model"),
#include <math.h>
#include "lens-correct.h"
-#if 0
-#define TRACE /* Define this to see basic tracing info. */
-#endif
+#include <stdio.h>
-/* 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)
+make_lens (LensCorrectionModel *lens,
+ GeglChantO *o,
+ GeglRectangle boundary)
{
- double r, radj;
-
- 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;
+ lens->BB.x = boundary.x;
+ lens->BB.y = boundary.y;
+ lens->BB.width = boundary.width;
+ lens->BB.height = boundary.height;
+
+ if (o->center)
+ {
+ o->cx = (boundary.x + boundary.width) / 2;
+ o->cy = (boundary.y + boundary.height) / 2;
+ }
+
+ lens->cx = o->cx;
+ lens->cy = o->cy;
+
+ lens->rscale = o->rscale;
+
+ lens->red.a = o->red_a;
+ lens->red.b = o->red_b;
+ lens->red.c = o->red_c;
+
+ if (o->correct)
+ lens->red.d = 1 - o->red_a - o->red_b - o->red_c;
+ else
+ lens->red.d = o->red_d;
+
+ lens->green.a = o->green_a;
+ lens->green.b = o->green_b;
+ lens->green.c = o->green_c;
+
+ if (o->correct)
+ lens->green.d = 1 - o->green_a - o->green_b - o->green_c;
+ else
+ lens->green.d = o->green_d;
+
+ lens->blue.a = o->blue_a;
+ lens->blue.b = o->blue_b;
+ lens->blue.c = o->blue_c;
+
+ if (o->correct)
+ lens->blue.d = 1 - o->blue_a - o->blue_b - o->blue_c;
+ else
+ lens->blue.d = o->blue_d;
+
+ lens->alpha.a = o->alpha_a;
+ lens->alpha.b = o->alpha_b;
+ lens->alpha.c = o->alpha_c;
+
+ if (o->correct)
+ lens->alpha.d = 1 - o->alpha_a - o->alpha_b - o->alpha_c;
+ else
+ lens->alpha.d = o->red_d;
+
+ if (o->focal!=0.0)
+ {
+ gdouble f = o->focal;
+ lens->red.b = lens->green.b = lens->blue.b = lens->alpha.b
+ = 0.000005142 * f*f*f - 0.000380839 * f*f + 0.009606325 * f - 0.075316854;
+ }
}
-/* 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)
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
{
- /* 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;
- }
-}
+ GeglRectangle result = {0,0,0,0};
+ GeglRectangle *in_rect;
-/* 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);
+ in_rect = gegl_operation_source_get_bounding_box (operation, "input");
+ if (!in_rect)
+ return result;
+
+ return *in_rect;
+}
-/* 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)
+get_required_for_output (GeglOperation *operation,
+ const gchar *input_pad,
+ const GeglRectangle *roi)
{
- 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;
+ return get_bounding_box (operation);
}
-/* 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 (LensCorrectionModel *oip,
- GeglBuffer *src,
- GeglBuffer *dst)
+prepare (GeglOperation *operation)
{
- 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_new0 (gfloat, gegl_buffer_get_pixel_count (src) * 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_new0 (gfloat, gegl_buffer_get_pixel_count (dst) * 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
+ gegl_operation_set_format (operation, "input", babl_format ("RGBA float"));
+ gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
}
-/*****************************************************************************/
-
-/* Compute the region for which this operation is defined.
- */
-static GeglRectangle
-get_bounding_box (GeglOperation *operation)
+static void
+find_src_pixel (LensCorrectionModel *lcip, ChannelCorrectionModel *pp,
+ gfloat x, gfloat y, gfloat *srcx, gfloat *srcy)
{
- GeglRectangle result = {0,0,0,0};
- GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input");
- GeglChantO *area = GEGL_CHANT_PROPERTIES (operation);
-
- #ifdef TRACE
- g_warning ("> get_bounding_box 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_bounding_box result = %dx%d+%d+%d", result.width, result.height, result.x, result.y);
- #endif
- return result;
-}
+ gdouble r, radj;
+
+ 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;
-/* Compute the input rectangle required to compute the specified region of interest (roi).
- */
-static GeglRectangle
-get_required_for_output (GeglOperation *operation,
- const gchar *input_pad,
- const GeglRectangle *roi)
-{
- GeglChantO *area = GEGL_CHANT_PROPERTIES (operation);
- GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
- #ifdef TRACE
- g_warning ("> get_required_for_output 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 ("< get_required_for_output 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)
+lens_distort_newl (gfloat *src_buf,
+ gfloat *dst_buf,
+ const GeglRectangle *extended,
+ const GeglRectangle *result,
+ const GeglRectangle *boundary,
+ LensCorrectionModel *lens,
+ gint xx,
+ gint yy,
+ GeglBuffer *input)
{
- #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
+ gfloat temp[4];
+ gint tmpx, tmpy, x, y, rgb;
+ gint offset;
+
+ ChannelCorrectionModel ccm[3];
+
+ /* Compute each dst pixel in turn and store into dst buffer. */
+ ccm[0] = lens->red;
+ ccm[1] = lens->green;
+ ccm[2] = lens->blue;
+
+ for (rgb = 0; rgb < 4; rgb++)
+ {
+ gfloat gx, gy;
+ gfloat val = 0.0;
+ gfloat wx[2], wy[2], wt = 0.0;
+
+ find_src_pixel (lens, &ccm[rgb], (gfloat)xx, (gfloat)yy, &gx, &gy);
+ tmpx = (gint) gx;
+ tmpy = (gint) gy;
+
+ wx[1] = gx - tmpx;
+ wx[0] = 1.0 - wx[1];
+ wy[1] = gy - tmpy;
+ wy[0] = 1.0 - wy[1];
+
+ for (x = 0; x < 2; x++)
+ {
+ for (y = 0; y < 2; y++)
+ {
+ if (tmpx+x >= extended->x && tmpx+x < extended->x + extended->width
+ && tmpy+y >= extended->y && tmpy+y < extended->y + extended->height)
+ {
+ offset = (tmpy + y - extended->y) * extended->width * 4 +
+ (tmpx + x - extended->x) * 4 + rgb;
+ val += src_buf[offset] * wx[x] * wy[y];
+ wt += wx[x] * wy[y];
+ }
+ else if (tmpx+x >= boundary->x &&
+ tmpx+x < boundary->x + boundary->width &&
+ tmpy+y >= boundary->y &&
+ tmpy+y < boundary->y + boundary->height)
+ {
+ gfloat color[4];
+ gegl_buffer_sample (input, tmpx+x, tmpy+y, NULL, color,
+ babl_format ("RGBA float"),
+ GEGL_INTERPOLATION_NEAREST);
+ val += color[rgb] * wx[x] * wy[y];
+ wt += wx[x] * wy[y];
+ }
+ }
+ }
+ if (wt <= 0)
+ {
+ temp [rgb] = 0.0;
+ }
+ else
+ {
+ temp [rgb] = val / wt;
+ }
+ }
+
+ offset = (yy - result->y) * result->width * 4 + (xx - result->x) * 4;
+ for (x=0; x<4; x++)
+ dst_buf[offset++] = temp[x];
}
-/* Perform the specified operation.
- */
static gboolean
process (GeglOperation *operation,
GeglBuffer *input,
GeglBuffer *output,
const GeglRectangle *result)
{
- GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ LensCorrectionModel lens;
+ GeglRectangle boundary = *gegl_operation_source_get_bounding_box
+ (operation, "input");
- copy_through_lens (o->lens_info_pointer, input, output);
+ gint x, y;
+ gfloat *src_buf, *dst_buf;
+ src_buf = g_new0 (gfloat, result->width * result->height * 4);
+ dst_buf = g_new0 (gfloat, result->width * result->height * 4);
+
+ make_lens (&lens, o, boundary);
+
+ gegl_buffer_get (input, 1.0, result, babl_format ("RGBA float"),
+ src_buf, GEGL_AUTO_ROWSTRIDE);
+
+ for (y = result->y; y < result->y + result->height; y++)
+ for (x = result->x; x < result->x + result->width; x++)
+ {
+ lens_distort_newl (src_buf, dst_buf, result,
+ result, &boundary, &lens, x, y, input);
+ }
+
+ gegl_buffer_set (output, result, babl_format ("RGBA float"),
+ dst_buf, GEGL_AUTO_ROWSTRIDE);
+
+ g_free (dst_buf);
+ g_free (src_buf);
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]