Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* 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 2011 Barak Itkin <[email protected]>
- */
- #include "config.h"
- #include <glib/gi18n-lib.h>
- #ifdef GEGL_CHANT_PROPERTIES
- /* Needed to tril GEGL into thinking this OP can save a file */
- gegl_chant_string (path, _("File"), "",
- _("Target path and filename, use '-' for stdout."))
- gegl_chant_pointer (ptList, _("Points"),
- _("A GPtrArray* of struct {gint x, y;} containing the points"))
- gegl_chant_double (threshold, _("Threshold"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.1,
- _("The threshold for determining the difference between black and white (white >= thres)"))
- #else
- #define GEGL_CHANT_TYPE_SINK
- #define GEGL_CHANT_C_FILE "selection2points.c"
- #include "gegl-chant.h"
- #include <stdio.h>
- /* 0
- *
- * 7 N 1
- * ^
- * |
- * |
- * 6 W<----+---->E 2
- * | =====>X
- * | ||
- * v ||
- * 5 S 3 ||
- * vv
- * 4 Y
- */
- typedef enum {
- D_N = 0, /* 000 */
- D_NE = 1, /* 001 */
- D_E = 2, /* 010 */
- D_SE = 3, /* 011 */
- D_S = 4, /* 100 */
- D_SW = 5, /* 101 */
- D_W = 6, /* 110 */
- D_NW = 7 /* 111 */
- } DIRECTION;
- typedef struct {
- gint x, y;
- } SPoint;
- #define cwdirection(t) (((t)+1)%8)
- #define ccwdirection(t) (((t)+7)%8)
- #define oppositedirection(t) (((t)+4)%8)
- #define isSouth(s) (((s) == D_S) || ((s) == D_SE) || ((s) == D_SW))
- #define isNorth(s) (((s) == D_N) || ((s) == D_NE) || ((s) == D_NW))
- #define isEast(s) (((s) == D_NE) || ((s) == D_E) || ((s) == D_SE))
- #define isWest(s) (((s) == D_NW) || ((s) == D_W) || ((s) == D_SW))
- /**
- * Add a COPY of the given point into the array pts. The original point CAN
- * be freed later!
- */
- static void
- AddPoint (GPtrArray* pts, SPoint *pt)
- {
- SPoint *cpy = g_new (SPoint, 1);
- cpy->x = pt->x;
- cpy->y = pt->y;
- printf ("Added %d,%d\n", pt->x, pt->y);
- g_ptr_array_add (pts, cpy);
- }
- static inline void
- move (SPoint *pt, DIRECTION t, SPoint *dest)
- {
- dest->x = pt->x + (isEast(t) ? 1 : (isWest(t) ? -1 : 0));
- dest->y = pt->y + (isSouth(t) ? 1 : (isNorth(t) ? -1 : 0));
- }
- typedef struct
- {
- gint xmin, xmax;
- gint ymin, ymax;
- gint rowstride;
- gdouble threshold;
- gdouble *im;
- } OutlineProcPrivate;
- #define in_range(val,min,max) (((min) <= (val)) && ((val) <= (max)))
- static inline gboolean
- is_inside (OutlineProcPrivate *OPP, SPoint *pt)
- {
- return in_range (pt->x, OPP->xmin, OPP->xmax)
- && in_range (pt->y, OPP->ymin, OPP->ymax);
- }
- #define get_value(OPP,x,y) (((OPP)->im)[((y)-(OPP)->ymin)*(OPP)->rowstride+(x)-(OPP)->xmin])
- #define get_valuePT(OPP,pt) get_value(OPP,(pt)->x,(pt)->y)
- static inline gboolean
- is_white (OutlineProcPrivate *OPP, SPoint *pt)
- {
- return is_inside (OPP, pt) && get_valuePT (OPP,pt) >= OPP->threshold;
- }
- /* This function receives a white pixel (pt) and the direction of the movement
- * that lead to it (prevdirection). It will return the direction leading to the
- * next white pixel (while following the edges in CW order), and the pixel
- * itself would be stored in dest.
- *
- * The logic is simple:
- * 1. Try to continue in the same direction that lead us to the current pixel
- * 2. Dprev = oppposite(prevdirection)
- * 3. Dnow = cw(Dprev)
- * 4. While moving to Dnow is white:
- * 4.1. Dprev = Dnow
- * 4.2. Dnow = cw(D)
- * 5. Return the result - moving by Dprev
- */
- static inline
- DIRECTION walkCW (OutlineProcPrivate *OPP, DIRECTION prevdirection, SPoint *pt, SPoint *dest)
- {
- DIRECTION Dprev = oppositedirection(prevdirection);
- DIRECTION Dnow = cwdirection (Dprev);
- SPoint ptN, ptP;
- move (pt, Dprev, &ptP);
- move (pt, Dnow, &ptN);
- while (is_white (OPP, &ptN))
- {
- Dprev = Dnow;
- ptP.x = ptN.x;
- ptP.y = ptN.y;
- Dnow = cwdirection (Dprev);
- move (pt, Dnow, &ptN);
- }
- dest->x = ptP.x;
- dest->y = ptP.y;
- return Dprev;
- }
- #define pteq(pt1,pt2) (((pt1)->x == (pt2)->x) && ((pt1)->y == (pt2)->y))
- static void
- find_outline_ccw (OutlineProcPrivate *OPP, GPtrArray *pts)
- {
- gint x = OPP->xmin;
- gint y;
- gboolean found;
- SPoint START, pt, ptN;
- DIRECTION DIR, DIRN;
- /* First of all try to find a white pixel */
- for (y = OPP->ymin; y < OPP->ymax; y++)
- for (x = OPP->xmin; x < OPP->xmax; x++)
- if (get_value (OPP, x, y) >= OPP->threshold)
- {
- found = TRUE;
- break;
- }
- /* For now, assume a non empty selection */
- g_assert(found);
- pt.x = START.x = x;
- pt.y = START.y = y;
- DIR = D_NW;
- AddPoint (pts, &START);
- DIRN = walkCW(OPP, DIR,&pt,&ptN);
- while (! pteq(&ptN,&START))
- {
- AddPoint (pts, &ptN);
- pt.x = ptN.x;
- pt.y = ptN.y;
- DIR = DIRN;
- DIRN = walkCW(OPP, DIR,&pt,&ptN);
- }
- }
- static gboolean
- process (GeglOperation *operation,
- GeglBuffer *input,
- const GeglRectangle *result)
- {
- GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
- // const GeglRectangle *rect = gegl_buffer_get_extent (input);
- // TODO; get rid of this hack test leak
- GeglRectangle *rect = g_new(GeglRectangle, 1);
- rect->x = 0;
- rect->y = 0;
- rect->width = 50;
- rect->height = 50;
- OutlineProcPrivate *OPP = (OutlineProcPrivate *)o->chant_data;
- fprintf (stderr, "Rect %dx%d\n",rect->width,rect->height);
- if (OPP == NULL)
- {
- printf ("Allocating %d\n",sizeof(OutlineProcPrivate));
- OPP = o->chant_data = g_malloc (sizeof(OutlineProcPrivate));
- }
- OPP->xmin = rect->x;
- OPP->ymin = rect->y;
- OPP->xmax = rect->x + rect->width - 1;
- OPP->ymax = rect->y + rect->height - 1;
- OPP->threshold = o->threshold;
- OPP->im = g_new (gdouble,(rect->width) * rect->height);
- OPP->rowstride = rect->width;
- gegl_buffer_get (input, 1.0, rect, gegl_buffer_get_format (input), OPP->im, GEGL_AUTO_ROWSTRIDE);
- // TODO: remove me!
- o->ptList = g_ptr_array_new ();
- find_outline_ccw (OPP, o->ptList);
- gint x, y;
- /* First of all try to find a white pixel */
- for (y = OPP->ymin; y < OPP->ymax; y++)
- {
- for (x = OPP->xmin; x < OPP->xmax; x++)
- {
- if (get_value (OPP, x, y) >= OPP->threshold)
- printf ("1");
- else
- printf ("0");
- }
- printf("\n");
- }
- g_free (OPP->im);
- OPP->im = NULL;
- return TRUE;
- }
- static void
- finalize (GObject *object)
- {
- GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
- g_debug ("Finalizing!\n");
- if (o->chant_data)
- {
- g_free (o->chant_data);
- o->chant_data = NULL;
- }
- G_OBJECT_CLASS (gegl_chant_parent_class)->finalize (object);
- }
- static void
- prepare (GeglOperation *operation)
- {
- GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
- gegl_operation_set_format (operation, "input", babl_format("Y double"));
- // babl_format_new (babl_model ("RGBA"),
- // babl_type ("double"),
- // babl_component ("A"),
- // NULL));
- g_debug ("Preparing!\n");
- if (o->chant_data == NULL)
- {
- o->chant_data = g_slice_new (OutlineProcPrivate);
- }
- }
- static void
- gegl_chant_class_init (GeglChantClass *klass)
- {
- GeglOperationClass *operation_class;
- GeglOperationSinkClass *sink_class;
- operation_class = GEGL_OPERATION_CLASS (klass);
- sink_class = GEGL_OPERATION_SINK_CLASS (klass);
- sink_class->process = process;
- sink_class->needs_full = TRUE;
- operation_class->prepare = prepare;
- operation_class->name = "gegl:selection2points";
- operation_class->categories = "output";
- operation_class->description =
- _("Return the list of edge points of a white area in a black BG");
- G_OBJECT_CLASS(klass)->finalize = finalize;
- /* Needed to tril GEGL into thinking this OP can save a file */
- gegl_extension_handler_register_saver (".pts", "gegl:selection2points");
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment