123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- /* The GIMP -- an image manipulation program
- * Copyright (C) 1995 Spencer Kimball and Peter Mattis
- *
- * gimphistogram module Copyright (C) 1999 Jay Cox <jaycox@earthlink.net>
- *
- * 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "config.h"
- #ifdef ENABLE_MP
- #include <pthread.h>
- #endif /* ENABLE_MP */
- #include <glib.h>
- #include <libgimp/gimpmath.h>
- #include "gimphistogram.h"
- #include "pixel_region.h"
- #include "gimpdrawable.h"
- #include "channel.h"
- #include "gimpimage.h"
- #include "gimprc.h"
- struct _GimpHistogram
- {
- gint bins;
- gdouble **values;
- gint nchannels;
- #ifdef ENABLE_MP
- pthread_mutex_t mutex;
- gint nthreads;
- gdouble ***tmp_values;
- gchar *tmp_slots;
- #endif /* ENABLE_MP */
- };
- GimpHistogram *
- gimp_histogram_new (void)
- {
- GimpHistogram *histogram;
- histogram = g_new0 (GimpHistogram, 1);
- histogram->bins = 0;
- histogram->values = NULL;
- histogram->nchannels = 0;
- #ifdef ENABLE_MP
- histogram->nthreads = 0;
- histogram->tmp_values = NULL;
- histogram->tmp_slots = NULL;
- #endif /* ENABLE_MP */
- return histogram;
- }
- void
- gimp_histogram_free (GimpHistogram *histogram)
- {
- gint i;
- if (histogram->values)
- {
- for (i = 0; i < histogram->nchannels; i++)
- g_free (histogram->values[i]);
- g_free (histogram->values);
- }
- g_free (histogram);
- }
- static void
- gimp_histogram_calculate_sub_region (GimpHistogram *histogram,
- PixelRegion *region,
- PixelRegion *mask)
- {
- const guchar *src, *msrc;
- const guchar *m, *s;
- gdouble **values;
- gint h, w, max;
- #ifdef ENABLE_MP
- gint slot = 0;
- /* find an unused temporary slot to put our results in and lock it */
- pthread_mutex_lock (&histogram->mutex);
- {
- while (histogram->tmp_slots[slot])
- slot++;
- values = histogram->tmp_values[slot];
- histogram->tmp_slots[slot] = 1;
- }
- pthread_mutex_unlock (&histogram->mutex);
- #else /* !ENABLE_MP */
- values = histogram->values;
- #endif
- h = region->h;
- w = region->w;
- if (mask)
- {
- gdouble masked;
- src = region->data;
- msrc = mask->data;
- while (h--)
- {
- s = src;
- m = msrc;
- w = region->w;
- switch(region->bytes)
- {
- case 1:
- while (w--)
- {
- masked = m[0] / 255.0;
- values[0][s[0]] += masked;
- s += 1;
- m += 1;
- }
- break;
- case 2:
- while (w--)
- {
- masked = m[0] / 255.0;
- values[0][s[0]] += masked;
- values[1][s[1]] += masked;
- s += 2;
- m += 1;
- }
- break;
- case 3: /* calculate seperate value values */
- while (w--)
- {
- masked = m[0] / 255.0;
- values[1][s[0]] += masked;
- values[2][s[1]] += masked;
- values[3][s[2]] += masked;
- max = (s[0] > s[1]) ? s[0] : s[1];
- if (s[2] > max)
- values[0][s[2]] += masked;
- else
- values[0][max] += masked;
- s += 3;
- m += 1;
- }
- break;
- case 4: /* calculate seperate value values */
- while (w--)
- {
- masked = m[0] / 255.0;
- values[1][s[0]] += masked;
- values[2][s[1]] += masked;
- values[3][s[2]] += masked;
- values[4][s[3]] += masked;
- max = (s[0] > s[1]) ? s[0] : s[1];
- if (s[2] > max)
- values[0][s[2]] += masked;
- else
- values[0][max] += masked;
- s += 3;
- m += 1;
- }
- break;
- }
- src += region->rowstride;
- msrc += mask->rowstride;
- }
- }
- else /* no mask */
- {
- src = region->data;
- while (h--)
- {
- s = src;
- w = region->w;
- switch(region->bytes)
- {
- case 1:
- while (w--)
- {
- values[0][s[0]] += 1.0;
- s += 1;
- }
- break;
- case 2:
- while (w--)
- {
- values[0][s[0]] += 1.0;
- values[1][s[1]] += 1.0;
- s += 2;
- }
- break;
- case 3: /* calculate seperate value values */
- while (w--)
- {
- values[1][s[0]] += 1.0;
- values[2][s[1]] += 1.0;
- values[3][s[2]] += 1.0;
- max = (s[0] > s[1]) ? s[0] : s[1];
- if (s[2] > max)
- values[0][s[2]] += 1.0;
- else
- values[0][max] += 1.0;
- s += 3;
- }
- break;
- case 4: /* calculate seperate value values */
- while (w--)
- {
- values[1][s[0]] += 1.0;
- values[2][s[1]] += 1.0;
- values[3][s[2]] += 1.0;
- values[4][s[3]] += 1.0;
- max = (s[0] > s[1]) ? s[0] : s[1];
- if (s[2] > max)
- values[0][s[2]] += 1.0;
- else
- values[0][max] += 1.0;
- s += 4;
- }
- break;
- }
- src += region->rowstride;
- }
- }
- #ifdef ENABLE_MP
- /* unlock this slot */
- /* we shouldn't have to use mutex locks here */
- pthread_mutex_lock (&histogram->mutex);
- histogram->tmp_slots[slot] = 0;
- pthread_mutex_unlock (&histogram->mutex);
- #endif
- }
- static void
- gimp_histogram_alloc (GimpHistogram *histogram,
- gint bytes)
- {
- gint i;
- if (bytes + 1 != histogram->nchannels)
- {
- if (histogram->values)
- {
- for (i = 0; i < histogram->nchannels; i++)
- g_free (histogram->values[i]);
- g_free (histogram->values);
- }
- histogram->nchannels = bytes + 1;
- histogram->values = g_new0 (gdouble *, histogram->nchannels);
- for (i = 0; i < histogram->nchannels; i++)
- histogram->values[i] = g_new (double, 256);
- }
- }
- void
- gimp_histogram_calculate (GimpHistogram *histogram,
- PixelRegion *region,
- PixelRegion *mask)
- {
- gint i, j;
- #ifdef ENABLE_MP
- gint k;
- #endif
- gimp_histogram_alloc (histogram, region->bytes);
- #ifdef ENABLE_MP
- pthread_mutex_init (&histogram->mutex, NULL);
- histogram->tmp_slots = g_new0 (gchar, num_processors);
- histogram->tmp_values = g_new0 (gdouble **, num_processors);
- for (i = 0; i < num_processors; i++)
- {
- histogram->tmp_values[i] = g_new0 (double *, histogram->nchannels);
- histogram->tmp_slots[i] = 0;
- for (j = 0; j < histogram->nchannels; j++)
- {
- histogram->tmp_values[i][j] = g_new0 (gdouble, 256);
- for (k = 0; k < 256; k++)
- histogram->tmp_values[i][j][k] = 0.0;
- }
- }
- #endif
- for (i = 0; i < histogram->nchannels; i++)
- for (j = 0; j < 256; j++)
- histogram->values[i][j] = 0.0;
- pixel_regions_process_parallel ((p_func)gimp_histogram_calculate_sub_region,
- histogram, 2, region, mask);
- #ifdef ENABLE_MP
- /* add up all the tmp buffers and free their memmory */
- for (i = 0; i < num_processors; i++)
- {
- for (j = 0; j < histogram->nchannels; j++)
- {
- for (k = 0; k < 256; k++)
- histogram->values[j][k] += histogram->tmp_values[i][j][k];
- g_free (histogram->tmp_values[i][j]);
- }
- g_free (histogram->tmp_values[i]);
- }
- g_free (histogram->tmp_values);
- g_free (histogram->tmp_slots);
- #endif
- }
- void
- gimp_histogram_calculate_drawable (GimpHistogram *histogram,
- GimpDrawable *drawable)
- {
- PixelRegion region;
- PixelRegion mask;
- gint x1, y1, x2, y2;
- gint off_x, off_y;
- gboolean no_mask;
- no_mask = (drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2) == FALSE);
- pixel_region_init (®ion, gimp_drawable_data (drawable), x1, y1,
- (x2 - x1), (y2 - y1), FALSE);
- if (!no_mask)
- {
- Channel *sel_mask;
- GimpImage *gimage;
- gimage = gimp_drawable_gimage (drawable);
- sel_mask = gimp_image_get_mask (gimage);
- drawable_offsets (drawable, &off_x, &off_y);
- pixel_region_init (&mask, gimp_drawable_data (GIMP_DRAWABLE (sel_mask)),
- x1 + off_x, y1 + off_y, (x2 - x1), (y2 - y1), FALSE);
- gimp_histogram_calculate (histogram, ®ion, &mask);
- }
- else
- {
- gimp_histogram_calculate (histogram, ®ion, NULL);
- }
- }
- gdouble
- gimp_histogram_get_maximum (GimpHistogram *histogram,
- GimpHistogramChannel channel)
- {
- gdouble max = 0.0;
- gint x;
- for (x = 0; x < 256; x++)
- if (histogram->values[channel][x] > max)
- max = histogram->values[channel][x];
- return max;
- }
- gdouble
- gimp_histogram_get_value (GimpHistogram *histogram,
- GimpHistogramChannel channel,
- gint bin)
- {
- if (channel < histogram->nchannels && bin >= 0 && bin < 256)
- return histogram->values[channel][bin];
- return 0.0;
- }
- gdouble
- gimp_histogram_get_channel (GimpHistogram *histogram,
- GimpHistogramChannel channel,
- gint bin)
- {
- if (histogram->nchannels > 3)
- return gimp_histogram_get_value (histogram, channel + 1, bin);
- else
- return gimp_histogram_get_value (histogram, channel , bin);
- }
- gint
- gimp_histogram_nchannels (GimpHistogram *histogram)
- {
- return histogram->nchannels - 1;
- }
- gdouble
- gimp_histogram_get_count (GimpHistogram *histogram,
- gint start,
- gint end)
- {
- gint i;
- gdouble count = 0.0;
- for (i = start; i <= end; i++)
- count += histogram->values[0][i];
- return count;
- }
- gdouble
- gimp_histogram_get_mean (GimpHistogram *histogram,
- GimpHistogramChannel channel,
- gint start,
- gint end)
- {
- gint i;
- gdouble mean = 0.0;
- gdouble count;
- for (i = start; i <= end; i++)
- mean += i * histogram->values[channel][i];
- count = gimp_histogram_get_count (histogram, start, end);
- if (count > 0.0)
- return mean / count;
- return mean;
- }
- gint
- gimp_histogram_get_median (GimpHistogram *histogram,
- GimpHistogramChannel channel,
- gint start,
- gint end)
- {
- gint i;
- gdouble sum = 0.0;
- gdouble count;
- count = gimp_histogram_get_count (histogram, start, end);
- for (i = start; i <= end; i++)
- {
- sum += histogram->values[channel][i];
- if (sum * 2 > count)
- return i;
- }
- return -1;
- }
- gdouble
- gimp_histogram_get_std_dev (GimpHistogram *histogram,
- GimpHistogramChannel channel,
- gint start,
- gint end)
- {
- gint i;
- gdouble dev = 0.0;
- gdouble count;
- gdouble mean;
- mean = gimp_histogram_get_mean (histogram, channel, start, end);
- count = gimp_histogram_get_count (histogram, start, end);
- if (count == 0.0)
- count = 1.0;
- for (i = start; i <= end; i++)
- dev += gimp_histogram_get_value (histogram, channel, i) *
- (i - mean) * (i - mean);
- return sqrt (dev / count);
- }
|