1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimphistogram module Copyright (C) 1999 Jay Cox <jaycox@gimp.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "config.h"
21 
22 #include <string.h>
23 #include <cairo.h>
24 #include <gegl.h>
25 #include <gdk-pixbuf/gdk-pixbuf.h>
26 
27 #include "libgimpmath/gimpmath.h"
28 #include "libgimpcolor/gimpcolor.h"
29 
30 #include "core-types.h"
31 
32 #include "gegl/gimp-babl.h"
33 #include "gegl/gimp-gegl-loops.h"
34 
35 #include "gimp-atomic.h"
36 #include "gimp-parallel.h"
37 #include "gimpasync.h"
38 #include "gimphistogram.h"
39 #include "gimpwaitable.h"
40 
41 
42 #define MAX_N_COMPONENTS   4
43 #define N_DERIVED_CHANNELS 2
44 
45 #define PIXELS_PER_THREAD \
46   (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */)
47 
48 
49 enum
50 {
51   PROP_0,
52   PROP_N_COMPONENTS,
53   PROP_N_BINS,
54   PROP_VALUES
55 };
56 
57 struct _GimpHistogramPrivate
58 {
59   gboolean   linear;
60   gint       n_channels;
61   gint       n_bins;
62   gdouble   *values;
63   GimpAsync *calculate_async;
64 };
65 
66 typedef struct
67 {
68   /*  input  */
69   GimpHistogram *histogram;
70   GeglBuffer    *buffer;
71   GeglRectangle  buffer_rect;
72   GeglBuffer    *mask;
73   GeglRectangle  mask_rect;
74 
75   /*  output  */
76   gint           n_components;
77   gint           n_bins;
78   gdouble       *values;
79 } CalculateContext;
80 
81 typedef struct
82 {
83   GimpAsync        *async;
84   CalculateContext *context;
85 
86   const Babl       *format;
87   GSList           *values_list;
88 } CalculateData;
89 
90 
91 /*  local function prototypes  */
92 
93 static void       gimp_histogram_finalize                 (GObject              *object);
94 static void       gimp_histogram_set_property             (GObject              *object,
95                                                            guint                 property_id,
96                                                            const GValue         *value,
97                                                            GParamSpec           *pspec);
98 static void       gimp_histogram_get_property             (GObject              *object,
99                                                            guint                 property_id,
100                                                            GValue               *value,
101                                                            GParamSpec           *pspec);
102 
103 static gint64     gimp_histogram_get_memsize              (GimpObject           *object,
104                                                            gint64               *gui_size);
105 
106 static gboolean   gimp_histogram_map_channel              (GimpHistogram        *histogram,
107                                                            GimpHistogramChannel *channel);
108 
109 static void       gimp_histogram_set_values               (GimpHistogram        *histogram,
110                                                            gint                  n_components,
111                                                            gint                  n_bins,
112                                                            gdouble              *values);
113 
114 static void       gimp_histogram_calculate_internal       (GimpAsync            *async,
115                                                            CalculateContext     *context);
116 static void       gimp_histogram_calculate_area           (const GeglRectangle  *area,
117                                                            CalculateData        *data);
118 static void       gimp_histogram_calculate_async_callback (GimpAsync            *async,
119                                                            CalculateContext     *context);
120 
121 
G_DEFINE_TYPE_WITH_PRIVATE(GimpHistogram,gimp_histogram,GIMP_TYPE_OBJECT)122 G_DEFINE_TYPE_WITH_PRIVATE (GimpHistogram, gimp_histogram, GIMP_TYPE_OBJECT)
123 
124 #define parent_class gimp_histogram_parent_class
125 
126 
127 static void
128 gimp_histogram_class_init (GimpHistogramClass *klass)
129 {
130   GObjectClass      *object_class      = G_OBJECT_CLASS (klass);
131   GimpObjectClass   *gimp_object_class = GIMP_OBJECT_CLASS (klass);
132 
133   object_class->finalize         = gimp_histogram_finalize;
134   object_class->set_property     = gimp_histogram_set_property;
135   object_class->get_property     = gimp_histogram_get_property;
136 
137   gimp_object_class->get_memsize = gimp_histogram_get_memsize;
138 
139   g_object_class_install_property (object_class, PROP_N_COMPONENTS,
140                                    g_param_spec_int ("n-components", NULL, NULL,
141                                                      0, MAX_N_COMPONENTS, 0,
142                                                      GIMP_PARAM_READABLE));
143 
144   g_object_class_install_property (object_class, PROP_N_BINS,
145                                    g_param_spec_int ("n-bins", NULL, NULL,
146                                                      256, 1024, 1024,
147                                                      GIMP_PARAM_READABLE));
148 
149   /* this is just for notifications */
150   g_object_class_install_property (object_class, PROP_VALUES,
151                                    g_param_spec_boolean ("values", NULL, NULL,
152                                                          FALSE,
153                                                          G_PARAM_READABLE));
154 }
155 
156 static void
gimp_histogram_init(GimpHistogram * histogram)157 gimp_histogram_init (GimpHistogram *histogram)
158 {
159   histogram->priv = gimp_histogram_get_instance_private (histogram);
160 }
161 
162 static void
gimp_histogram_finalize(GObject * object)163 gimp_histogram_finalize (GObject *object)
164 {
165   GimpHistogram *histogram = GIMP_HISTOGRAM (object);
166 
167   gimp_histogram_clear_values (histogram, 0);
168 
169   G_OBJECT_CLASS (parent_class)->finalize (object);
170 }
171 
172 static void
gimp_histogram_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)173 gimp_histogram_set_property (GObject      *object,
174                              guint         property_id,
175                              const GValue *value,
176                              GParamSpec   *pspec)
177 {
178   switch (property_id)
179     {
180     default:
181       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
182       break;
183     }
184 }
185 
186 static void
gimp_histogram_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)187 gimp_histogram_get_property (GObject    *object,
188                              guint       property_id,
189                              GValue     *value,
190                              GParamSpec *pspec)
191 {
192   GimpHistogram *histogram = GIMP_HISTOGRAM (object);
193 
194   switch (property_id)
195     {
196     case PROP_N_COMPONENTS:
197       g_value_set_int (value, gimp_histogram_n_components (histogram));
198       break;
199 
200     case PROP_N_BINS:
201       g_value_set_int (value, histogram->priv->n_bins);
202       break;
203 
204     case PROP_VALUES:
205       /* return a silly boolean */
206       g_value_set_boolean (value, histogram->priv->values != NULL);
207       break;
208 
209     default:
210       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
211       break;
212     }
213 }
214 
215 static gint64
gimp_histogram_get_memsize(GimpObject * object,gint64 * gui_size)216 gimp_histogram_get_memsize (GimpObject *object,
217                             gint64     *gui_size)
218 {
219   GimpHistogram *histogram = GIMP_HISTOGRAM (object);
220   gint64         memsize   = 0;
221 
222   if (histogram->priv->values)
223     memsize += (histogram->priv->n_channels *
224                 histogram->priv->n_bins * sizeof (gdouble));
225 
226   return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
227                                                                   gui_size);
228 }
229 
230 /*  public functions  */
231 
232 GimpHistogram *
gimp_histogram_new(gboolean linear)233 gimp_histogram_new (gboolean linear)
234 {
235   GimpHistogram *histogram = g_object_new (GIMP_TYPE_HISTOGRAM, NULL);
236 
237   histogram->priv->linear = linear;
238 
239   return histogram;
240 }
241 
242 /**
243  * gimp_histogram_duplicate:
244  * @histogram: a %GimpHistogram
245  *
246  * Creates a duplicate of @histogram. The duplicate has a reference
247  * count of 1 and contains the values from @histogram.
248  *
249  * Return value: a newly allocated %GimpHistogram
250  **/
251 GimpHistogram *
gimp_histogram_duplicate(GimpHistogram * histogram)252 gimp_histogram_duplicate (GimpHistogram *histogram)
253 {
254   GimpHistogram *dup;
255 
256   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), NULL);
257 
258   if (histogram->priv->calculate_async)
259     gimp_waitable_wait (GIMP_WAITABLE (histogram->priv->calculate_async));
260 
261   dup = gimp_histogram_new (histogram->priv->linear);
262 
263   dup->priv->n_channels = histogram->priv->n_channels;
264   dup->priv->n_bins     = histogram->priv->n_bins;
265   dup->priv->values     = g_memdup (histogram->priv->values,
266                                     sizeof (gdouble) *
267                                     dup->priv->n_channels *
268                                     dup->priv->n_bins);
269 
270   return dup;
271 }
272 
273 void
gimp_histogram_calculate(GimpHistogram * histogram,GeglBuffer * buffer,const GeglRectangle * buffer_rect,GeglBuffer * mask,const GeglRectangle * mask_rect)274 gimp_histogram_calculate (GimpHistogram       *histogram,
275                           GeglBuffer          *buffer,
276                           const GeglRectangle *buffer_rect,
277                           GeglBuffer          *mask,
278                           const GeglRectangle *mask_rect)
279 {
280   CalculateContext context = {};
281 
282   g_return_if_fail (GIMP_IS_HISTOGRAM (histogram));
283   g_return_if_fail (GEGL_IS_BUFFER (buffer));
284   g_return_if_fail (buffer_rect != NULL);
285 
286   if (histogram->priv->calculate_async)
287     gimp_async_cancel_and_wait (histogram->priv->calculate_async);
288 
289   context.histogram   = histogram;
290   context.buffer      = buffer;
291   context.buffer_rect = *buffer_rect;
292 
293   if (mask)
294     {
295       context.mask = mask;
296 
297       if (mask_rect)
298         context.mask_rect = *mask_rect;
299       else
300         context.mask_rect = *gegl_buffer_get_extent (mask);
301     }
302 
303   gimp_histogram_calculate_internal (NULL, &context);
304 
305   gimp_histogram_set_values (histogram,
306                              context.n_components, context.n_bins,
307                              context.values);
308 }
309 
310 GimpAsync *
gimp_histogram_calculate_async(GimpHistogram * histogram,GeglBuffer * buffer,const GeglRectangle * buffer_rect,GeglBuffer * mask,const GeglRectangle * mask_rect)311 gimp_histogram_calculate_async (GimpHistogram       *histogram,
312                                 GeglBuffer          *buffer,
313                                 const GeglRectangle *buffer_rect,
314                                 GeglBuffer          *mask,
315                                 const GeglRectangle *mask_rect)
316 {
317   CalculateContext *context;
318   GeglRectangle     rect;
319 
320   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), NULL);
321   g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
322   g_return_val_if_fail (buffer_rect != NULL, NULL);
323 
324   if (histogram->priv->calculate_async)
325     gimp_async_cancel_and_wait (histogram->priv->calculate_async);
326 
327   gegl_rectangle_align_to_buffer (&rect, buffer_rect, buffer,
328                                   GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
329 
330   context = g_slice_new0 (CalculateContext);
331 
332   context->histogram   = histogram;
333   context->buffer      = gegl_buffer_new (&rect,
334                                           gegl_buffer_get_format (buffer));
335   context->buffer_rect = *buffer_rect;
336 
337   gimp_gegl_buffer_copy (buffer, &rect, GEGL_ABYSS_NONE,
338                          context->buffer, NULL);
339 
340   if (mask)
341     {
342       if (mask_rect)
343         context->mask_rect = *mask_rect;
344       else
345         context->mask_rect = *gegl_buffer_get_extent (mask);
346 
347       gegl_rectangle_align_to_buffer (&rect, &context->mask_rect, mask,
348                                       GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
349 
350       context->mask = gegl_buffer_new (&rect, gegl_buffer_get_format (mask));
351 
352       gimp_gegl_buffer_copy (mask, &rect, GEGL_ABYSS_NONE,
353                              context->mask, NULL);
354     }
355 
356   histogram->priv->calculate_async = gimp_parallel_run_async (
357     (GimpRunAsyncFunc) gimp_histogram_calculate_internal,
358     context);
359 
360   gimp_async_add_callback (
361     histogram->priv->calculate_async,
362     (GimpAsyncCallback) gimp_histogram_calculate_async_callback,
363     context);
364 
365   return histogram->priv->calculate_async;
366 }
367 
368 void
gimp_histogram_clear_values(GimpHistogram * histogram,gint n_components)369 gimp_histogram_clear_values (GimpHistogram *histogram,
370                              gint           n_components)
371 {
372   g_return_if_fail (GIMP_IS_HISTOGRAM (histogram));
373 
374   if (histogram->priv->calculate_async)
375     gimp_async_cancel_and_wait (histogram->priv->calculate_async);
376 
377   gimp_histogram_set_values (histogram, n_components, 0, NULL);
378 }
379 
380 
381 #define HISTOGRAM_VALUE(c,i) (priv->values[(c) * priv->n_bins + (i)])
382 
383 
384 gdouble
gimp_histogram_get_maximum(GimpHistogram * histogram,GimpHistogramChannel channel)385 gimp_histogram_get_maximum (GimpHistogram        *histogram,
386                             GimpHistogramChannel  channel)
387 {
388   GimpHistogramPrivate *priv;
389   gdouble               max = 0.0;
390   gint                  x;
391 
392   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0.0);
393 
394   priv = histogram->priv;
395 
396   if (! priv->values ||
397       ! gimp_histogram_map_channel (histogram, &channel))
398     {
399       return 0.0;
400     }
401 
402   if (channel == GIMP_HISTOGRAM_RGB)
403     {
404       for (x = 0; x < priv->n_bins; x++)
405         {
406           max = MAX (max, HISTOGRAM_VALUE (GIMP_HISTOGRAM_RED,   x));
407           max = MAX (max, HISTOGRAM_VALUE (GIMP_HISTOGRAM_GREEN, x));
408           max = MAX (max, HISTOGRAM_VALUE (GIMP_HISTOGRAM_BLUE,  x));
409         }
410     }
411   else
412     {
413       for (x = 0; x < priv->n_bins; x++)
414         {
415           max = MAX (max, HISTOGRAM_VALUE (channel, x));
416         }
417     }
418 
419   return max;
420 }
421 
422 gdouble
gimp_histogram_get_value(GimpHistogram * histogram,GimpHistogramChannel channel,gint bin)423 gimp_histogram_get_value (GimpHistogram        *histogram,
424                           GimpHistogramChannel  channel,
425                           gint                  bin)
426 {
427   GimpHistogramPrivate *priv;
428 
429   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0.0);
430 
431   priv = histogram->priv;
432 
433   if (! priv->values                   ||
434       (bin < 0 || bin >= priv->n_bins) ||
435       ! gimp_histogram_map_channel (histogram, &channel))
436     {
437       return 0.0;
438     }
439 
440   if (channel == GIMP_HISTOGRAM_RGB)
441     {
442       gdouble min = HISTOGRAM_VALUE (GIMP_HISTOGRAM_RED, bin);
443 
444       min = MIN (min, HISTOGRAM_VALUE (GIMP_HISTOGRAM_GREEN, bin));
445 
446       return MIN (min, HISTOGRAM_VALUE (GIMP_HISTOGRAM_BLUE, bin));
447     }
448   else
449     {
450       return HISTOGRAM_VALUE (channel, bin);
451     }
452 }
453 
454 gdouble
gimp_histogram_get_component(GimpHistogram * histogram,gint component,gint bin)455 gimp_histogram_get_component (GimpHistogram *histogram,
456                               gint           component,
457                               gint           bin)
458 {
459   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0.0);
460 
461   if (gimp_histogram_n_components (histogram) > 2)
462     component++;
463 
464   return gimp_histogram_get_value (histogram, component, bin);
465 }
466 
467 gint
gimp_histogram_n_components(GimpHistogram * histogram)468 gimp_histogram_n_components (GimpHistogram *histogram)
469 {
470   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0);
471 
472   if (histogram->priv->n_channels > 0)
473     return histogram->priv->n_channels - N_DERIVED_CHANNELS;
474   else
475     return 0;
476 }
477 
478 gint
gimp_histogram_n_bins(GimpHistogram * histogram)479 gimp_histogram_n_bins (GimpHistogram *histogram)
480 {
481   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0);
482 
483   return histogram->priv->n_bins;
484 }
485 
486 gboolean
gimp_histogram_has_channel(GimpHistogram * histogram,GimpHistogramChannel channel)487 gimp_histogram_has_channel (GimpHistogram        *histogram,
488                             GimpHistogramChannel  channel)
489 {
490   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), FALSE);
491 
492   switch (channel)
493     {
494     case GIMP_HISTOGRAM_VALUE:
495       return TRUE;
496 
497     case GIMP_HISTOGRAM_RED:
498     case GIMP_HISTOGRAM_GREEN:
499     case GIMP_HISTOGRAM_BLUE:
500     case GIMP_HISTOGRAM_LUMINANCE:
501     case GIMP_HISTOGRAM_RGB:
502       return gimp_histogram_n_components (histogram) >= 3;
503 
504     case GIMP_HISTOGRAM_ALPHA:
505       return gimp_histogram_n_components (histogram) == 2 ||
506              gimp_histogram_n_components (histogram) == 4;
507     }
508 
509   g_return_val_if_reached (FALSE);
510 }
511 
512 gdouble
gimp_histogram_get_count(GimpHistogram * histogram,GimpHistogramChannel channel,gint start,gint end)513 gimp_histogram_get_count (GimpHistogram        *histogram,
514                           GimpHistogramChannel  channel,
515                           gint                  start,
516                           gint                  end)
517 {
518   GimpHistogramPrivate *priv;
519   gint                  i;
520   gdouble               count = 0.0;
521 
522   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0.0);
523 
524   priv = histogram->priv;
525 
526   if (! priv->values ||
527       start > end    ||
528       ! gimp_histogram_map_channel (histogram, &channel))
529     {
530       return 0.0;
531     }
532 
533   if (channel == GIMP_HISTOGRAM_RGB)
534     return (gimp_histogram_get_count (histogram,
535                                       GIMP_HISTOGRAM_RED, start, end)   +
536             gimp_histogram_get_count (histogram,
537                                       GIMP_HISTOGRAM_GREEN, start, end) +
538             gimp_histogram_get_count (histogram,
539                                       GIMP_HISTOGRAM_BLUE, start, end));
540 
541   start = CLAMP (start, 0, priv->n_bins - 1);
542   end   = CLAMP (end,   0, priv->n_bins - 1);
543 
544   for (i = start; i <= end; i++)
545     count += HISTOGRAM_VALUE (channel, i);
546 
547   return count;
548 }
549 
550 gdouble
gimp_histogram_get_mean(GimpHistogram * histogram,GimpHistogramChannel channel,gint start,gint end)551 gimp_histogram_get_mean (GimpHistogram        *histogram,
552                          GimpHistogramChannel  channel,
553                          gint                  start,
554                          gint                  end)
555 {
556   GimpHistogramPrivate *priv;
557   gint                  i;
558   gdouble               mean = 0.0;
559   gdouble               count;
560 
561   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0.0);
562 
563   priv = histogram->priv;
564 
565   if (! priv->values ||
566       start > end    ||
567       ! gimp_histogram_map_channel (histogram, &channel))
568     {
569       return 0.0;
570     }
571 
572   start = CLAMP (start, 0, priv->n_bins - 1);
573   end   = CLAMP (end,   0, priv->n_bins - 1);
574 
575   if (channel == GIMP_HISTOGRAM_RGB)
576     {
577       for (i = start; i <= end; i++)
578         {
579           gdouble factor = (gdouble) i / (gdouble)  (priv->n_bins - 1);
580 
581           mean += (factor * HISTOGRAM_VALUE (GIMP_HISTOGRAM_RED,   i) +
582                    factor * HISTOGRAM_VALUE (GIMP_HISTOGRAM_GREEN, i) +
583                    factor * HISTOGRAM_VALUE (GIMP_HISTOGRAM_BLUE,  i));
584         }
585     }
586   else
587     {
588       for (i = start; i <= end; i++)
589         {
590           gdouble factor = (gdouble) i / (gdouble)  (priv->n_bins - 1);
591 
592           mean += factor * HISTOGRAM_VALUE (channel, i);
593         }
594     }
595 
596   count = gimp_histogram_get_count (histogram, channel, start, end);
597 
598   if (count > 0.0)
599     return mean / count;
600 
601   return mean;
602 }
603 
604 gdouble
gimp_histogram_get_median(GimpHistogram * histogram,GimpHistogramChannel channel,gint start,gint end)605 gimp_histogram_get_median (GimpHistogram         *histogram,
606                            GimpHistogramChannel   channel,
607                            gint                   start,
608                            gint                   end)
609 {
610   GimpHistogramPrivate *priv;
611   gint                  i;
612   gdouble               sum = 0.0;
613   gdouble               count;
614 
615   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), -1.0);
616 
617   priv = histogram->priv;
618 
619   if (! priv->values ||
620       start > end    ||
621       ! gimp_histogram_map_channel (histogram, &channel))
622     {
623       return 0.0;
624     }
625 
626   start = CLAMP (start, 0, priv->n_bins - 1);
627   end   = CLAMP (end,   0, priv->n_bins - 1);
628 
629   count = gimp_histogram_get_count (histogram, channel, start, end);
630 
631   if (channel == GIMP_HISTOGRAM_RGB)
632     {
633       for (i = start; i <= end; i++)
634         {
635           sum += (HISTOGRAM_VALUE (GIMP_HISTOGRAM_RED,   i) +
636                   HISTOGRAM_VALUE (GIMP_HISTOGRAM_GREEN, i) +
637                   HISTOGRAM_VALUE (GIMP_HISTOGRAM_BLUE,  i));
638 
639           if (sum * 2 > count)
640             return ((gdouble) i / (gdouble)  (priv->n_bins - 1));
641         }
642     }
643   else
644     {
645       for (i = start; i <= end; i++)
646         {
647           sum += HISTOGRAM_VALUE (channel, i);
648 
649           if (sum * 2 > count)
650             return ((gdouble) i / (gdouble)  (priv->n_bins - 1));
651         }
652     }
653 
654   return -1.0;
655 }
656 
657 /*
658  * adapted from GNU ocrad 0.14 : page_image_io.cc : otsu_th
659  *
660  *  N. Otsu, "A threshold selection method from gray-level histograms,"
661  *  IEEE Trans. Systems, Man, and Cybernetics, vol. 9, no. 1, pp. 62-66, 1979.
662  */
663 gdouble
gimp_histogram_get_threshold(GimpHistogram * histogram,GimpHistogramChannel channel,gint start,gint end)664 gimp_histogram_get_threshold (GimpHistogram        *histogram,
665                               GimpHistogramChannel  channel,
666                               gint                  start,
667                               gint                  end)
668 {
669   GimpHistogramPrivate *priv;
670   gint                 i;
671   gint                 maxval;
672   gdouble             *hist      = NULL;
673   gdouble             *chist     = NULL;
674   gdouble             *cmom      = NULL;
675   gdouble              hist_max  = 0.0;
676   gdouble              chist_max = 0.0;
677   gdouble              cmom_max  = 0.0;
678   gdouble              bvar_max  = 0.0;
679   gint                 threshold = 127;
680 
681   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), -1);
682 
683   priv = histogram->priv;
684 
685   if (! priv->values ||
686       start > end    ||
687       ! gimp_histogram_map_channel (histogram, &channel))
688     {
689       return 0;
690     }
691 
692   start = CLAMP (start, 0, priv->n_bins - 1);
693   end   = CLAMP (end,   0, priv->n_bins - 1);
694 
695   maxval = end - start;
696 
697   hist  = g_newa (gdouble, maxval + 1);
698   chist = g_newa (gdouble, maxval + 1);
699   cmom  = g_newa (gdouble, maxval + 1);
700 
701   if (channel == GIMP_HISTOGRAM_RGB)
702     {
703       for (i = start; i <= end; i++)
704         hist[i - start] = (HISTOGRAM_VALUE (GIMP_HISTOGRAM_RED,   i) +
705                            HISTOGRAM_VALUE (GIMP_HISTOGRAM_GREEN, i) +
706                            HISTOGRAM_VALUE (GIMP_HISTOGRAM_BLUE,  i));
707     }
708   else
709     {
710       for (i = start; i <= end; i++)
711         hist[i - start] = HISTOGRAM_VALUE (channel, i);
712     }
713 
714   hist_max = hist[0];
715   chist[0] = hist[0];
716   cmom[0] = 0;
717 
718   for (i = 1; i <= maxval; i++)
719     {
720       if (hist[i] > hist_max)
721         hist_max = hist[i];
722 
723       chist[i] = chist[i-1] + hist[i];
724       cmom[i] = cmom[i-1] + i * hist[i];
725     }
726 
727   chist_max = chist[maxval];
728   cmom_max = cmom[maxval];
729   bvar_max = 0;
730 
731   for (i = 0; i < maxval; ++i)
732     {
733       if (chist[i] > 0 && chist[i] < chist_max)
734         {
735           gdouble bvar;
736 
737           bvar = (gdouble) cmom[i] / chist[i];
738           bvar -= (cmom_max - cmom[i]) / (chist_max - chist[i]);
739           bvar *= bvar;
740           bvar *= chist[i];
741           bvar *= chist_max - chist[i];
742 
743           if (bvar > bvar_max)
744             {
745               bvar_max = bvar;
746               threshold = start + i;
747             }
748         }
749     }
750 
751   return threshold;
752 }
753 
754 gdouble
gimp_histogram_get_std_dev(GimpHistogram * histogram,GimpHistogramChannel channel,gint start,gint end)755 gimp_histogram_get_std_dev (GimpHistogram        *histogram,
756                             GimpHistogramChannel  channel,
757                             gint                  start,
758                             gint                  end)
759 {
760   GimpHistogramPrivate *priv;
761   gint                  i;
762   gdouble               dev = 0.0;
763   gdouble               count;
764   gdouble               mean;
765 
766   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), 0.0);
767 
768   priv = histogram->priv;
769 
770   if (! priv->values ||
771       start > end    ||
772       ! gimp_histogram_map_channel (histogram, &channel))
773     {
774       return 0.0;
775     }
776 
777   mean  = gimp_histogram_get_mean  (histogram, channel, start, end);
778   count = gimp_histogram_get_count (histogram, channel, start, end);
779 
780   if (count == 0.0)
781     count = 1.0;
782 
783   for (i = start; i <= end; i++)
784     {
785       gdouble value;
786 
787       if (channel == GIMP_HISTOGRAM_RGB)
788         {
789           value = (HISTOGRAM_VALUE (GIMP_HISTOGRAM_RED,   i) +
790                    HISTOGRAM_VALUE (GIMP_HISTOGRAM_GREEN, i) +
791                    HISTOGRAM_VALUE (GIMP_HISTOGRAM_BLUE,  i));
792         }
793       else
794         {
795           value = gimp_histogram_get_value (histogram, channel, i);
796         }
797 
798       dev += value * SQR (((gdouble) i / (gdouble)  (priv->n_bins - 1)) - mean);
799     }
800 
801   return sqrt (dev / count);
802 }
803 
804 
805 /*  private functions  */
806 
807 static gboolean
gimp_histogram_map_channel(GimpHistogram * histogram,GimpHistogramChannel * channel)808 gimp_histogram_map_channel (GimpHistogram        *histogram,
809                             GimpHistogramChannel *channel)
810 {
811   GimpHistogramPrivate *priv = histogram->priv;
812 
813   if (*channel == GIMP_HISTOGRAM_RGB)
814     return gimp_histogram_n_components (histogram) >= 3;
815 
816   switch (*channel)
817     {
818     case GIMP_HISTOGRAM_ALPHA:
819       if (gimp_histogram_n_components (histogram) == 2)
820         *channel = 1;
821       break;
822 
823     case GIMP_HISTOGRAM_LUMINANCE:
824       *channel = gimp_histogram_n_components (histogram) + 1;
825       break;
826 
827     default:
828       break;
829     }
830 
831   return *channel < priv->n_channels;
832 }
833 
834 static void
gimp_histogram_set_values(GimpHistogram * histogram,gint n_components,gint n_bins,gdouble * values)835 gimp_histogram_set_values (GimpHistogram *histogram,
836                            gint           n_components,
837                            gint           n_bins,
838                            gdouble       *values)
839 {
840   GimpHistogramPrivate *priv                = histogram->priv;
841   gint                  n_channels          = n_components;
842   gboolean              notify_n_components = FALSE;
843   gboolean              notify_n_bins       = FALSE;
844 
845   if (n_channels > 0)
846     n_channels += N_DERIVED_CHANNELS;
847 
848   if (n_channels != priv->n_channels)
849     {
850       priv->n_channels = n_channels;
851 
852       notify_n_components = TRUE;
853     }
854 
855   if (n_bins != priv->n_bins)
856     {
857       priv->n_bins = n_bins;
858 
859       notify_n_bins = TRUE;
860     }
861 
862   if (values != priv->values)
863     {
864       if (priv->values)
865         g_free (priv->values);
866 
867       priv->values = values;
868     }
869 
870   if (notify_n_components)
871     g_object_notify (G_OBJECT (histogram), "n-components");
872 
873   if (notify_n_bins)
874     g_object_notify (G_OBJECT (histogram), "n-bins");
875 
876   g_object_notify (G_OBJECT (histogram), "values");
877 }
878 
879 static void
gimp_histogram_calculate_internal(GimpAsync * async,CalculateContext * context)880 gimp_histogram_calculate_internal (GimpAsync        *async,
881                                    CalculateContext *context)
882 {
883   CalculateData         data;
884   GimpHistogramPrivate *priv;
885   const Babl           *format;
886 
887   priv = context->histogram->priv;
888 
889   format = gegl_buffer_get_format (context->buffer);
890 
891   if (babl_format_get_type (format, 0) == babl_type ("u8"))
892     context->n_bins = 256;
893   else
894     context->n_bins = 1024;
895 
896   if (babl_format_is_palette (format))
897     {
898       if (babl_format_has_alpha (format))
899         {
900           if (priv->linear)
901             format = babl_format ("RGB float");
902           else
903             format = babl_format ("R'G'B' float");
904         }
905       else
906         {
907           if (priv->linear)
908             format = babl_format ("RGBA float");
909           else
910             format = babl_format ("R'G'B'A float");
911         }
912     }
913   else
914     {
915       const Babl *model = babl_format_get_model (format);
916 
917       if (model == babl_model ("Y") ||
918           model == babl_model ("Y'"))
919         {
920           if (priv->linear)
921             format = babl_format ("Y float");
922           else
923             format = babl_format ("Y' float");
924         }
925       else if (model == babl_model ("YA") ||
926                model == babl_model ("Y'A"))
927         {
928           if (priv->linear)
929             format = babl_format ("YA float");
930           else
931             format = babl_format ("Y'A float");
932         }
933       else if (model == babl_model ("RGB") ||
934                model == babl_model ("R'G'B'"))
935         {
936           if (priv->linear)
937             format = babl_format ("RGB float");
938           else
939             format = babl_format ("R'G'B' float");
940         }
941       else if (model == babl_model ("RGBA") ||
942                model == babl_model ("R'G'B'A"))
943         {
944           if (priv->linear)
945             format = babl_format ("RGBA float");
946           else
947             format = babl_format ("R'G'B'A float");
948         }
949       else
950         {
951           if (async)
952             gimp_async_abort (async);
953 
954           g_return_if_reached ();
955         }
956     }
957 
958   context->n_components = babl_format_get_n_components (format);
959 
960   data.async       = async;
961   data.context     = context;
962   data.format      = format;
963   data.values_list = NULL;
964 
965   gegl_parallel_distribute_area (
966     &context->buffer_rect, PIXELS_PER_THREAD, GEGL_SPLIT_STRATEGY_AUTO,
967     (GeglParallelDistributeAreaFunc) gimp_histogram_calculate_area,
968     &data);
969 
970   if (! async || ! gimp_async_is_canceled (async))
971     {
972       gdouble *total_values = NULL;
973       gint     n_values     = (context->n_components + N_DERIVED_CHANNELS) *
974                               context->n_bins;
975       GSList  *iter;
976 
977       for (iter = data.values_list; iter; iter = g_slist_next (iter))
978         {
979           gdouble *values = iter->data;
980 
981           if (! total_values)
982             {
983               total_values = values;
984             }
985           else
986             {
987               gint i;
988 
989               for (i = 0; i < n_values; i++)
990                 total_values[i] += values[i];
991 
992               g_free (values);
993             }
994         }
995 
996       g_slist_free (data.values_list);
997 
998       context->values = total_values;
999 
1000       if (async)
1001         gimp_async_finish (async, NULL);
1002     }
1003   else
1004     {
1005       g_slist_free_full (data.values_list, g_free);
1006 
1007       if (async)
1008         gimp_async_abort (async);
1009     }
1010 }
1011 
1012 static void
gimp_histogram_calculate_area(const GeglRectangle * area,CalculateData * data)1013 gimp_histogram_calculate_area (const GeglRectangle *area,
1014                                CalculateData       *data)
1015 {
1016   GimpAsync            *async;
1017   CalculateContext     *context;
1018   GeglBufferIterator   *iter;
1019   gdouble              *values;
1020   gint                  n_components;
1021   gint                  n_bins;
1022   gfloat                n_bins_1f;
1023   gfloat                temp;
1024 
1025   async   = data->async;
1026   context = data->context;
1027 
1028   n_bins       = context->n_bins;
1029   n_components = context->n_components;
1030 
1031   values = g_new0 (gdouble, (n_components + N_DERIVED_CHANNELS) * n_bins);
1032   gimp_atomic_slist_push_head (&data->values_list, values);
1033 
1034   iter = gegl_buffer_iterator_new (context->buffer, area, 0,
1035                                    data->format,
1036                                    GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
1037 
1038   if (context->mask)
1039     {
1040       GeglRectangle mask_area = *area;
1041 
1042       mask_area.x += context->mask_rect.x - context->buffer_rect.x;
1043       mask_area.y += context->mask_rect.y - context->buffer_rect.y;
1044 
1045       gegl_buffer_iterator_add (iter, context->mask, &mask_area, 0,
1046                                 babl_format ("Y float"),
1047                                 GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
1048     }
1049 
1050   n_bins_1f = n_bins - 1;
1051 
1052 #define VALUE(c,i) (*(temp = (i) * n_bins_1f,                                  \
1053                       &values[(c) * n_bins +                                   \
1054                               SIGNED_ROUND (SAFE_CLAMP (temp,                  \
1055                                                         0.0f,                  \
1056                                                         n_bins_1f))]))
1057 
1058 #define CHECK_CANCELED(length)                                                 \
1059   G_STMT_START                                                                 \
1060     {                                                                          \
1061       if ((length) % 128 == 0 && async && gimp_async_is_canceled (async))      \
1062         {                                                                      \
1063           gegl_buffer_iterator_stop (iter);                                    \
1064                                                                                \
1065           return;                                                              \
1066         }                                                                      \
1067     }                                                                          \
1068   G_STMT_END
1069 
1070   while (gegl_buffer_iterator_next (iter))
1071     {
1072       const gfloat *data   = iter->items[0].data;
1073       gint          length = iter->length;
1074       gfloat        max;
1075       gfloat        luminance;
1076 
1077       CHECK_CANCELED (0);
1078 
1079       if (context->mask)
1080         {
1081           const gfloat *mask_data = iter->items[1].data;
1082 
1083           switch (n_components)
1084             {
1085             case 1:
1086               while (length--)
1087                 {
1088                   const gdouble masked = *mask_data;
1089 
1090                   VALUE (0, data[0]) += masked;
1091 
1092                   data += n_components;
1093                   mask_data += 1;
1094 
1095                   CHECK_CANCELED (length);
1096                 }
1097               break;
1098 
1099             case 2:
1100               while (length--)
1101                 {
1102                   const gdouble masked = *mask_data;
1103                   const gdouble weight = data[1];
1104 
1105                   VALUE (0, data[0]) += weight * masked;
1106                   VALUE (1, data[1]) += masked;
1107 
1108                   data += n_components;
1109                   mask_data += 1;
1110 
1111                   CHECK_CANCELED (length);
1112                 }
1113               break;
1114 
1115             case 3: /* calculate separate value values */
1116               while (length--)
1117                 {
1118                   const gdouble masked = *mask_data;
1119 
1120                   VALUE (1, data[0]) += masked;
1121                   VALUE (2, data[1]) += masked;
1122                   VALUE (3, data[2]) += masked;
1123 
1124                   max = MAX (data[0], data[1]);
1125                   max = MAX (data[2], max);
1126                   VALUE (0, max) += masked;
1127 
1128                   luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
1129                   VALUE (4, luminance) += masked;
1130 
1131                   data += n_components;
1132                   mask_data += 1;
1133 
1134                   CHECK_CANCELED (length);
1135                 }
1136               break;
1137 
1138             case 4: /* calculate separate value values */
1139               while (length--)
1140                 {
1141                   const gdouble masked = *mask_data;
1142                   const gdouble weight = data[3];
1143 
1144                   VALUE (1, data[0]) += weight * masked;
1145                   VALUE (2, data[1]) += weight * masked;
1146                   VALUE (3, data[2]) += weight * masked;
1147                   VALUE (4, data[3]) += masked;
1148 
1149                   max = MAX (data[0], data[1]);
1150                   max = MAX (data[2], max);
1151                   VALUE (0, max) += weight * masked;
1152 
1153                   luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
1154                   VALUE (5, luminance) += weight * masked;
1155 
1156                   data += n_components;
1157                   mask_data += 1;
1158 
1159                   CHECK_CANCELED (length);
1160                 }
1161               break;
1162             }
1163         }
1164       else /* no mask */
1165         {
1166           switch (n_components)
1167             {
1168             case 1:
1169               while (length--)
1170                 {
1171                   VALUE (0, data[0]) += 1.0;
1172 
1173                   data += n_components;
1174 
1175                   CHECK_CANCELED (length);
1176                 }
1177               break;
1178 
1179             case 2:
1180               while (length--)
1181                 {
1182                   const gdouble weight = data[1];
1183 
1184                   VALUE (0, data[0]) += weight;
1185                   VALUE (1, data[1]) += 1.0;
1186 
1187                   data += n_components;
1188 
1189                   CHECK_CANCELED (length);
1190                 }
1191               break;
1192 
1193             case 3: /* calculate separate value values */
1194               while (length--)
1195                 {
1196                   VALUE (1, data[0]) += 1.0;
1197                   VALUE (2, data[1]) += 1.0;
1198                   VALUE (3, data[2]) += 1.0;
1199 
1200                   max = MAX (data[0], data[1]);
1201                   max = MAX (data[2], max);
1202                   VALUE (0, max) += 1.0;
1203 
1204                   luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
1205                   VALUE (4, luminance) += 1.0;
1206 
1207                   data += n_components;
1208 
1209                   CHECK_CANCELED (length);
1210                 }
1211               break;
1212 
1213             case 4: /* calculate separate value values */
1214               while (length--)
1215                 {
1216                   const gdouble weight = data[3];
1217 
1218                   VALUE (1, data[0]) += weight;
1219                   VALUE (2, data[1]) += weight;
1220                   VALUE (3, data[2]) += weight;
1221                   VALUE (4, data[3]) += 1.0;
1222 
1223                   max = MAX (data[0], data[1]);
1224                   max = MAX (data[2], max);
1225                   VALUE (0, max) += weight;
1226 
1227                   luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
1228                   VALUE (5, luminance) += weight;
1229 
1230                   data += n_components;
1231 
1232                   CHECK_CANCELED (length);
1233                 }
1234               break;
1235             }
1236         }
1237     }
1238 
1239 #undef VALUE
1240 #undef CHECK_CANCELED
1241 }
1242 
1243 static void
gimp_histogram_calculate_async_callback(GimpAsync * async,CalculateContext * context)1244 gimp_histogram_calculate_async_callback (GimpAsync        *async,
1245                                          CalculateContext *context)
1246 {
1247   context->histogram->priv->calculate_async = NULL;
1248 
1249   if (gimp_async_is_finished (async))
1250     {
1251       gimp_histogram_set_values (context->histogram,
1252                                  context->n_components, context->n_bins,
1253                                  context->values);
1254     }
1255 
1256   g_object_unref (context->buffer);
1257   if (context->mask)
1258     g_object_unref (context->mask);
1259 
1260   g_slice_free (CalculateContext, context);
1261 }
1262