change size of brush or restart gimp ,
but if it work properly it put to target lighter or darker smudges , i see
that old heal algoritm works better for me now
i am copy this heal tool (in attachment app/paint/gimpheal.h and .c ) to the fresh checkout gimp
and this is working perfectly, no artefacts no smudget but only perfect result, i dont know about version of this file
PS: sorry for my mail client drop subject and i create chaos in mailing list i am sorry
--
MSc. Miroslav Talasek
Developer, Team leader
Seznam.cz, a.s.
Prague
Czech Republic
tel.:+420 234 694 722
fax: +420 234 694 115
gsm: +420 608 934 724
jabber: mirecta@xxxxxxxxx
work-email: miroslav.talasek@xxxxxxxxxxxxxxx
email: miroslav.talasek@xxxxxxxxx
web:http://photo.talasek.sk
---------- Původní zpráva ----------
Od: gimp-developer-list-request@xxxxxxxxx
Datum: 17. 4. 2012
Předmět: gimp-developer-list Digest, Vol 7, Issue 30
Send gimp-developer-list mailing list submissions to
gimp-developer-list@xxxxxxxxx
To subscribe or unsubscribe via the World Wide Web, visit
http://mail.gnome.org/mailman/listinfo/gimp-developer-list
or, via email, send a message with subject or body 'help' to
gimp-developer-list-request@xxxxxxxxx
You can reach the person managing the list at
gimp-developer-list-owner@xxxxxxxxx
When replying, please edit your Subject line so it is more specific
than "Re: Contents of gimp-developer-list digest..."
Today's Topics:
1. Re: gimp 2.8rc heal tool (Alexandre Prokoudine)
----------------------------------------------------------------------
Message: 1
Date: Tue, 17 Apr 2012 14:48:50 +0400
From: Alexandre Prokoudine <alexandre.prokoudine@xxxxxxxxx>
To: gimp-developer <gimp-developer-list@xxxxxxxxx>
Subject: Re: [Gimp-developer] gimp 2.8rc heal tool
Message-ID:
<CAFjkzc22ZcAH8HTS=Dk4FhLmnRQc5xtEnnBJ+56d6eq-ruXqWQ@xxxxxxxxxxxxxx>
Content-Type: text/plain; charset=ISO-8859-1
2012/4/17 miroslav talasek wrote:
> new heal? tool algorithm doesnt work properly , i retouch skin on face but
> healing tool make black artefacts
Interesting. It was suposed to be fixed in 2.7.5.
Alexandre Prokoudine
http://libregraphicsworld.org
------------------------------
_______________________________________________
gimp-developer-list mailing list
gimp-developer-list@xxxxxxxxx
http://mail.gnome.org/mailman/listinfo/gimp-developer-list
End of gimp-developer-list Digest, Vol 7, Issue 30
**************************************************
/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "config.h" #include <string.h> #include <gegl.h> #include "libgimpbase/gimpbase.h" #include "libgimpmath/gimpmath.h" #include "paint-types.h" #include "paint-funcs/paint-funcs.h" #include "base/pixel-region.h" #include "base/temp-buf.h" #include "core/gimpbrush.h" #include "core/gimpdrawable.h" #include "core/gimpdynamics.h" #include "core/gimpdynamicsoutput.h" #include "core/gimperror.h" #include "core/gimpimage.h" #include "core/gimppickable.h" #include "gimpheal.h" #include "gimpsourceoptions.h" #include "gimp-intl.h" /* NOTES: * * I had the code working for healing from a pattern, but the results look * terrible and I can't see a use for it right now. */ static gboolean gimp_heal_start (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, GError **error); static void gimp_heal_substitute_0_for_1 (PixelRegion *pr); static void gimp_heal_divide (PixelRegion *topPR, PixelRegion *bottomPR, gdouble *result); static void gimp_heal_multiply (gdouble *first, PixelRegion *secondPR, PixelRegion *resultPR); static gdouble gimp_heal_laplace_iteration (gdouble *matrix, gint height, gint depth, gint width, gdouble *solution, guchar *mask); static void gimp_heal_laplace_loop (gdouble *matrix, gint height, gint depth, gint width, gdouble *solution, guchar *mask); static PixelRegion *gimp_heal_region (PixelRegion *tempPR, PixelRegion *srcPR, const TempBuf *mask_buf); static void gimp_heal_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity, GimpPickable *src_pickable, PixelRegion *srcPR, gint src_offset_x, gint src_offset_y, TempBuf *paint_area, gint paint_area_offset_x, gint paint_area_offset_y, gint paint_area_width, gint paint_area_height); G_DEFINE_TYPE (GimpHeal, gimp_heal, GIMP_TYPE_SOURCE_CORE) #define parent_class gimp_heal_parent_class void gimp_heal_register (Gimp *gimp, GimpPaintRegisterCallback callback) { (* callback) (gimp, GIMP_TYPE_HEAL, GIMP_TYPE_SOURCE_OPTIONS, "gimp-heal", _("Heal"), "gimp-tool-heal"); } static void gimp_heal_class_init (GimpHealClass *klass) { GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass); GimpSourceCoreClass *source_core_class = GIMP_SOURCE_CORE_CLASS (klass); paint_core_class->start = gimp_heal_start; source_core_class->motion = gimp_heal_motion; } static void gimp_heal_init (GimpHeal *heal) { } static gboolean gimp_heal_start (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, GError **error) { GimpSourceCore *source_core = GIMP_SOURCE_CORE (paint_core); if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable, paint_options, coords, error)) { return FALSE; } if (! source_core->set_source && gimp_drawable_is_indexed (drawable)) { g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, _("Healing does not operate on indexed layers.")); return FALSE; } return TRUE; } /* * Substitute any zeros in the input PixelRegion for ones. This is needed by * the algorithm to avoid division by zero, and to get a more realistic image * since multiplying by zero is often incorrect (i.e., healing from a dark to * a light region will have incorrect spots of zero) */ static void gimp_heal_substitute_0_for_1 (PixelRegion *pr) { gint i, j, k; gint height = pr->h; gint width = pr->w; gint depth = pr->bytes; guchar *pr_data = pr->data; guchar *p; for (i = 0; i < height; i++) { p = pr_data; for (j = 0; j < width; j++) { for (k = 0; k < depth; k++) { if (p[k] == 0) p[k] = 1; } p += depth; } pr_data += pr->rowstride; } } /* * Divide topPR by bottomPR and store the result as a double */ static void gimp_heal_divide (PixelRegion *topPR, PixelRegion *bottomPR, gdouble *result) { gint i, j, k; gint height = topPR->h; gint width = topPR->w; gint depth = topPR->bytes; guchar *t_data = topPR->data; guchar *b_data = bottomPR->data; guchar *t; guchar *b; gdouble *r = result; g_assert (topPR->bytes == bottomPR->bytes); for (i = 0; i < height; i++) { t = t_data; b = b_data; for (j = 0; j < width; j++) { for (k = 0; k < depth; k++) { r[k] = (gdouble) (t[k]) / (gdouble) (b[k]); } t += depth; b += depth; r += depth; } t_data += topPR->rowstride; b_data += bottomPR->rowstride; } } /* * multiply first by secondPR and store the result as a PixelRegion */ static void gimp_heal_multiply (gdouble *first, PixelRegion *secondPR, PixelRegion *resultPR) { gint i, j, k; gint height = secondPR->h; gint width = secondPR->w; gint depth = secondPR->bytes; guchar *s_data = secondPR->data; guchar *r_data = resultPR->data; gdouble *f = first; guchar *s; guchar *r; g_assert (secondPR->bytes == resultPR->bytes); for (i = 0; i < height; i++) { s = s_data; r = r_data; for (j = 0; j < width; j++) { for (k = 0; k < depth; k++) { r[k] = (guchar) CLAMP0255 (ROUND (((gdouble) (f[k])) * ((gdouble) (s[k])))); } f += depth; s += depth; r += depth; } s_data += secondPR->rowstride; r_data += resultPR->rowstride; } } /* * Perform one iteration of the laplace solver for matrix. Store the * result in solution and return the square of the cummulative error * of the solution. */ static gdouble gimp_heal_laplace_iteration (gdouble *matrix, gint height, gint depth, gint width, gdouble *solution, guchar *mask) { const gint rowstride = width * depth; gint i, j, k; gdouble tmp, diff; gdouble err = 0.0; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if ((0 == *mask) || (i == 0) || (i == (height - 1)) || (j == 0) || (j == (width - 1))) { /* do nothing at the boundary or outside mask */ for (k = 0; k < depth; k++) *(solution + k) = *(matrix + k); } else { /* calculate the mean of four neighbours for all color channels */ /* v[i][j] = 0.45 * (v[i][j-1]+v[i][j+1]+v[i-1][j]+v[i+1][j]) */ for (k = 0; k < depth; k++) { tmp = *(solution + k); *(solution + k) = 0.25 * ( *(matrix - depth + k) /* west */ + *(matrix + depth + k) /* east */ + *(matrix - rowstride + k) /* north */ + *(matrix + rowstride + k)); /* south */ diff = *(solution + k) - tmp; err += diff*diff; } } /* advance pointers to data */ matrix += depth; solution += depth; mask++; } } return err; } /* * Solve the laplace equation for matrix and store the result in solution. */ static void gimp_heal_laplace_loop (gdouble *matrix, gint height, gint depth, gint width, gdouble *solution, guchar *mask) { #define EPSILON 0.0001 #define MAX_ITER 500 gint i; /* repeat until convergence or max iterations */ for (i = 0; i < MAX_ITER; i++) { gdouble sqr_err; /* do one iteration and store the amount of error */ sqr_err = gimp_heal_laplace_iteration (matrix, height, depth, width, solution, mask); /* copy solution to matrix */ memcpy (matrix, solution, width * height * depth * sizeof (double)); if (sqr_err < SQR (EPSILON)) break; } } /* * Algorithm Design: * * T. Georgiev, "Image Reconstruction Invariant to Relighting", EUROGRAPHICS * 2005, http://www.tgeorgiev.net/ */ static PixelRegion * gimp_heal_region (PixelRegion *tempPR, PixelRegion *srcPR, const TempBuf *mask_buf) { gdouble *i_1 = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w); gdouble *i_2 = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w); guchar *mask = temp_buf_get_data (mask_buf); /* substitute 0's for 1's for the division and multiplication operations that * come later */ gimp_heal_substitute_0_for_1 (srcPR); /* divide tempPR by srcPR and store the result as a double in i_1 */ gimp_heal_divide (tempPR, srcPR, i_1); /* FIXME: is a faster implementation needed? */ gimp_heal_laplace_loop (i_1, tempPR->h, tempPR->bytes, tempPR->w, i_2, mask); /* multiply a double by srcPR and store in tempPR */ gimp_heal_multiply (i_2, srcPR, tempPR); g_free (i_1); g_free (i_2); return tempPR; } static void gimp_heal_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity, GimpPickable *src_pickable, PixelRegion *srcPR, gint src_offset_x, gint src_offset_y, TempBuf *paint_area, gint paint_area_offset_x, gint paint_area_offset_y, gint paint_area_width, gint paint_area_height) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpContext *context = GIMP_CONTEXT (paint_options); GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics; GimpDynamicsOutput *hardness_output; GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); TempBuf *src; TempBuf *temp; PixelRegion origPR; PixelRegion tempPR; PixelRegion destPR; GimpImageType src_type; const TempBuf *mask_buf; gdouble fade_point; gdouble hardness; hardness_output = gimp_dynamics_get_output (dynamics, GIMP_DYNAMICS_OUTPUT_HARDNESS); fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); hardness = gimp_dynamics_output_get_linear_value (hardness_output, coords, paint_options, fade_point); mask_buf = gimp_brush_core_get_brush_mask (GIMP_BRUSH_CORE (source_core), coords, GIMP_BRUSH_HARD, hardness); src_type = gimp_pickable_get_image_type (src_pickable); /* we need the source area with alpha and we modify it, so make a copy */ src = temp_buf_new (srcPR->w, srcPR->h, GIMP_IMAGE_TYPE_BYTES (GIMP_IMAGE_TYPE_WITH_ALPHA (src_type)), 0, 0, NULL); pixel_region_init_temp_buf (&tempPR, src, 0, 0, src->width, src->height); /* * the effect of the following is to copy the contents of the source * region to the "src" temp-buf, adding an alpha channel if necessary */ if (GIMP_IMAGE_TYPE_HAS_ALPHA (src_type)) copy_region (srcPR, &tempPR); else add_alpha_region (srcPR, &tempPR); /* reinitialize srcPR */ pixel_region_init_temp_buf (srcPR, src, 0, 0, src->width, src->height); if (GIMP_IMAGE_TYPE_WITH_ALPHA (src_type) != gimp_drawable_type_with_alpha (drawable)) { GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); TempBuf *temp2; gboolean new_buf; temp2 = gimp_image_transform_temp_buf (image, gimp_drawable_type_with_alpha (drawable), src, &new_buf); if (new_buf) temp_buf_free (src); src = temp2; } /* reinitialize srcPR */ pixel_region_init_temp_buf (srcPR, src, 0, 0, src->width, src->height); /* FIXME: the area under the cursor and the source area should be x% larger * than the brush size. Otherwise the brush must be a lot bigger than the * area to heal to get good results. Having the user pick such a large brush * is perhaps counter-intutitive? */ pixel_region_init (&origPR, gimp_drawable_get_tiles (drawable), paint_area->x, paint_area->y, paint_area->width, paint_area->height, FALSE); temp = temp_buf_new (origPR.w, origPR.h, gimp_drawable_bytes_with_alpha (drawable), 0, 0, NULL); pixel_region_init_temp_buf (&tempPR, temp, 0, 0, temp->width, temp->height); if (gimp_drawable_has_alpha (drawable)) copy_region (&origPR, &tempPR); else add_alpha_region (&origPR, &tempPR); /* reinitialize tempPR */ pixel_region_init_temp_buf (&tempPR, temp, 0, 0, temp->width, temp->height); /* now tempPR holds the data under the cursor and * srcPR holds the area to sample from */ /* get the destination to paint to */ pixel_region_init_temp_buf (&destPR, paint_area, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); /* check that srcPR, tempPR, destPR, and mask_buf are the same size */ if ((srcPR->w != tempPR.w) || (srcPR->w != destPR.w) || (srcPR->h != tempPR.h) || (srcPR->h != destPR.h) || (srcPR->h != mask_buf->height) || (srcPR->w != mask_buf->width)) { /* this generally means that the source point has hit the edge of the layer, so it is not an error and we should not complain, just don't do anything */ temp_buf_free (src); temp_buf_free (temp); return; } /* heal tempPR using srcPR */ gimp_heal_region (&tempPR, srcPR, mask_buf); temp_buf_free (src); /* reinitialize tempPR */ pixel_region_init_temp_buf (&tempPR, temp, 0, 0, temp->width, temp->height); copy_region (&tempPR, &destPR); temp_buf_free (temp); /* replace the canvas with our healed data */ gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), hardness, GIMP_PAINT_INCREMENTAL); }
/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __GIMP_HEAL_H__ #define __GIMP_HEAL_H__ #include "gimpsourcecore.h" #define GIMP_TYPE_HEAL (gimp_heal_get_type ()) #define GIMP_HEAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HEAL, GimpHeal)) #define GIMP_HEAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HEAL, GimpHealClass)) #define GIMP_IS_HEAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HEAL)) #define GIMP_IS_HEAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HEAL)) #define GIMP_HEAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HEAL, GimpHealClass)) typedef struct _GimpHealClass GimpHealClass; struct _GimpHeal { GimpSourceCore parent_instance; }; struct _GimpHealClass { GimpSourceCoreClass parent_class; }; void gimp_heal_register (Gimp *gimp, GimpPaintRegisterCallback callback); GType gimp_heal_get_type (void) G_GNUC_CONST; #endif /* __GIMP_HEAL_H__ */
_______________________________________________ gimp-developer-list mailing list gimp-developer-list@xxxxxxxxx http://mail.gnome.org/mailman/listinfo/gimp-developer-list