summaryrefslogtreecommitdiffstats
path: root/src/libs/histogram/imagehistogram.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/histogram/imagehistogram.cpp')
-rw-r--r--src/libs/histogram/imagehistogram.cpp548
1 files changed, 548 insertions, 0 deletions
diff --git a/src/libs/histogram/imagehistogram.cpp b/src/libs/histogram/imagehistogram.cpp
new file mode 100644
index 00000000..bee55624
--- /dev/null
+++ b/src/libs/histogram/imagehistogram.cpp
@@ -0,0 +1,548 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-07-21
+ * Description : image histogram manipulation methods.
+ *
+ * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * Some code parts are inspired from gimp 2.0
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// C++ includes.
+
+#include <cstdio>
+#include <cmath>
+#include <cstring>
+
+// TQt includes.
+
+#include <tqobject.h>
+#include <tqevent.h>
+
+// KDE includes.
+
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "dimg.h"
+#include "imagehistogram.h"
+
+namespace Digikam
+{
+
+class ImageHistogramPriv
+{
+
+public:
+
+ // Using a structure instead a class is more fast
+ // (access with memset() and bytes manipulation).
+
+ struct double_packet
+ {
+ double value;
+ double red;
+ double green;
+ double blue;
+ double alpha;
+ };
+
+public:
+
+ ImageHistogramPriv()
+ {
+ parent = 0;
+ imageData = 0;
+ histogram = 0;
+ runningFlag = true;
+ }
+
+ /** The histogram data.*/
+ struct double_packet *histogram;
+
+ /** Image information.*/
+ uchar *imageData;
+ uint imageWidth;
+ uint imageHeight;
+
+ /** Numbers of histogram segments dependaing of image bytes depth*/
+ int histoSegments;
+
+ /** To post event from thread to parent.*/
+ TQObject *parent;
+
+ /** Used to stop thread during calculations.*/
+ bool runningFlag;
+};
+
+ImageHistogram::ImageHistogram(const DImg& image, TQObject *parent)
+ : TQThread()
+{
+ setup(image.bits(), image.width(), image.height(), image.sixteenBit(), parent);
+}
+
+ImageHistogram::ImageHistogram(uchar *i_data, uint i_w, uint i_h, bool i_sixteenBits, TQObject *parent)
+ : TQThread()
+{
+ setup(i_data, i_w, i_h, i_sixteenBits, parent);
+}
+
+void ImageHistogram::setup(uchar *i_data, uint i_w, uint i_h, bool i_sixteenBits, TQObject *parent)
+{
+ d = new ImageHistogramPriv;
+ d->imageData = i_data;
+ d->imageWidth = i_w;
+ d->imageHeight = i_h;
+ d->parent = parent;
+ d->histoSegments = i_sixteenBits ? 65536 : 256;
+
+ if (d->imageData && d->imageWidth && d->imageHeight)
+ {
+ if (d->parent)
+ start();
+ else
+ calcHistogramValues();
+ }
+ else
+ {
+ if (d->parent)
+ postProgress(false, false);
+ }
+}
+
+ImageHistogram::~ImageHistogram()
+{
+ stopCalcHistogramValues();
+
+ if (d->histogram)
+ delete [] d->histogram;
+
+ delete d;
+}
+
+int ImageHistogram::getHistogramSegment(void)
+{
+ return d->histoSegments;
+}
+
+void ImageHistogram::postProgress(bool starting, bool success)
+{
+ EventData *eventData = new EventData();
+ eventData->starting = starting;
+ eventData->success = success;
+ eventData->histogram = this;
+ TQApplication::postEvent(d->parent, new TQCustomEvent(TQEvent::User, eventData));
+}
+
+void ImageHistogram::stopCalcHistogramValues(void)
+{
+ d->runningFlag = false;
+ wait();
+}
+
+// List of threaded operations.
+
+void ImageHistogram::run()
+{
+ calcHistogramValues();
+}
+
+void ImageHistogram::calcHistogramValues()
+{
+ uint i;
+ int max;
+
+ if (d->parent)
+ postProgress(true, false);
+
+ d->histogram = new ImageHistogramPriv::double_packet[d->histoSegments];
+ memset(d->histogram, 0, d->histoSegments*sizeof(ImageHistogramPriv::double_packet));
+
+ if ( !d->histogram )
+ {
+ DWarning() << ("HistogramWidget::calcHistogramValues: Unable to allocate memory!") << endl;
+
+ if (d->parent)
+ postProgress(false, false);
+
+ return;
+ }
+
+ memset(d->histogram, 0, d->histoSegments*sizeof(struct ImageHistogramPriv::double_packet));
+
+ if (d->histoSegments == 65536) // 16 bits image.
+ {
+ unsigned short blue, green, red, alpha;
+ unsigned short *data = (unsigned short*)d->imageData;
+
+ for (i = 0 ; (i < d->imageHeight*d->imageWidth*4) && d->runningFlag ; i+=4)
+ {
+ blue = data[ i ];
+ green = data[i+1];
+ red = data[i+2];
+ alpha = data[i+3];
+
+ d->histogram[blue].blue++;
+ d->histogram[green].green++;
+ d->histogram[red].red++;
+ d->histogram[alpha].alpha++;
+
+ max = (blue > green) ? blue : green;
+
+ if (red > max)
+ d->histogram[red].value++;
+ else
+ d->histogram[max].value++;
+ }
+ }
+ else // 8 bits images.
+ {
+ uchar blue, green, red, alpha;
+ uchar *data = d->imageData;
+
+ for (i = 0 ; (i < d->imageHeight*d->imageWidth*4) && d->runningFlag ; i+=4)
+ {
+ blue = data[ i ];
+ green = data[i+1];
+ red = data[i+2];
+ alpha = data[i+3];
+
+ d->histogram[blue].blue++;
+ d->histogram[green].green++;
+ d->histogram[red].red++;
+ d->histogram[alpha].alpha++;
+
+ max = (blue > green) ? blue : green;
+
+ if (red > max)
+ d->histogram[red].value++;
+ else
+ d->histogram[max].value++;
+ }
+ }
+
+ if (d->parent && d->runningFlag)
+ postProgress(false, true);
+}
+
+double ImageHistogram::getCount(int channel, int start, int end)
+{
+ int i;
+ double count = 0.0;
+
+ if ( !d->histogram || start < 0 ||
+ end > d->histoSegments-1 || start > end )
+ return 0.0;
+
+ switch(channel)
+ {
+ case ImageHistogram::ValueChannel:
+ for (i = start ; i <= end ; i++)
+ count += d->histogram[i].value;
+ break;
+
+ case ImageHistogram::RedChannel:
+ for (i = start ; i <= end ; i++)
+ count += d->histogram[i].red;
+ break;
+
+ case ImageHistogram::GreenChannel:
+ for (i = start ; i <= end ; i++)
+ count += d->histogram[i].green;
+ break;
+
+ case ImageHistogram::BlueChannel:
+ for (i = start ; i <= end ; i++)
+ count += d->histogram[i].blue;
+ break;
+
+ case ImageHistogram::AlphaChannel:
+ for (i = start ; i <= end ; i++)
+ count += d->histogram[i].alpha;
+ break;
+
+ default:
+ return 0.0;
+ break;
+ }
+
+ return count;
+}
+
+double ImageHistogram::getPixels()
+{
+ if ( !d->histogram )
+ return 0.0;
+
+ return(d->imageWidth * d->imageHeight);
+}
+
+double ImageHistogram::getMean(int channel, int start, int end)
+{
+ int i;
+ double mean = 0.0;
+ double count;
+
+ if ( !d->histogram || start < 0 ||
+ end > d->histoSegments-1 || start > end )
+ return 0.0;
+
+ switch(channel)
+ {
+ case ImageHistogram::ValueChannel:
+ for (i = start ; i <= end ; i++)
+ mean += i * d->histogram[i].value;
+ break;
+
+ case ImageHistogram::RedChannel:
+ for (i = start ; i <= end ; i++)
+ mean += i * d->histogram[i].red;
+ break;
+
+ case ImageHistogram::GreenChannel:
+ for (i = start ; i <= end ; i++)
+ mean += i * d->histogram[i].green;
+ break;
+
+ case ImageHistogram::BlueChannel:
+ for (i = start ; i <= end ; i++)
+ mean += i * d->histogram[i].blue;
+ break;
+
+ case ImageHistogram::AlphaChannel:
+ for (i = start ; i <= end ; i++)
+ mean += i * d->histogram[i].alpha;
+ break;
+
+ default:
+ return 0.0;
+ break;
+ }
+
+ count = getCount(channel, start, end);
+
+ if (count > 0.0)
+ return mean / count;
+
+ return mean;
+}
+
+int ImageHistogram::getMedian(int channel, int start, int end)
+{
+ int i;
+ double sum = 0.0;
+ double count;
+
+ if ( !d->histogram || start < 0 ||
+ end > d->histoSegments-1 || start > end )
+ return 0;
+
+ count = getCount(channel, start, end);
+
+ switch(channel)
+ {
+ case ImageHistogram::ValueChannel:
+ for (i = start ; i <= end ; i++)
+ {
+ sum += d->histogram[i].value;
+ if (sum * 2 > count) return i;
+ }
+ break;
+
+ case ImageHistogram::RedChannel:
+ for (i = start ; i <= end ; i++)
+ {
+ sum += d->histogram[i].red;
+ if (sum * 2 > count) return i;
+ }
+ break;
+
+ case ImageHistogram::GreenChannel:
+ for (i = start ; i <= end ; i++)
+ {
+ sum += d->histogram[i].green;
+ if (sum * 2 > count) return i;
+ }
+ break;
+
+ case ImageHistogram::BlueChannel:
+ for (i = start ; i <= end ; i++)
+ {
+ sum += d->histogram[i].blue;
+ if (sum * 2 > count) return i;
+ }
+ break;
+
+ case ImageHistogram::AlphaChannel:
+ for (i = start ; i <= end ; i++)
+ {
+ sum += d->histogram[i].alpha;
+ if (sum * 2 > count) return i;
+ }
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+
+ return -1;
+}
+
+double ImageHistogram::getStdDev(int channel, int start, int end)
+{
+ int i;
+ double dev = 0.0;
+ double count;
+ double mean;
+
+ if ( !d->histogram || start < 0 ||
+ end > d->histoSegments-1 || start > end )
+ return 0.0;
+
+ mean = getMean(channel, start, end);
+ count = getCount(channel, start, end);
+
+ if (count == 0.0)
+ count = 1.0;
+
+ switch(channel)
+ {
+ case ImageHistogram::ValueChannel:
+ for (i = start ; i <= end ; i++)
+ dev += (i - mean) * (i - mean) * d->histogram[i].value;
+ break;
+
+ case ImageHistogram::RedChannel:
+ for (i = start ; i <= end ; i++)
+ dev += (i - mean) * (i - mean) * d->histogram[i].red;
+ break;
+
+ case ImageHistogram::GreenChannel:
+ for (i = start ; i <= end ; i++)
+ dev += (i - mean) * (i - mean) * d->histogram[i].green;
+ break;
+
+ case ImageHistogram::BlueChannel:
+ for (i = start ; i <= end ; i++)
+ dev += (i - mean) * (i - mean) * d->histogram[i].blue;
+ break;
+
+ case ImageHistogram::AlphaChannel:
+ for (i = start ; i <= end ; i++)
+ dev += (i - mean) * (i - mean) * d->histogram[i].alpha;
+ break;
+
+ default:
+ return 0.0;
+ break;
+ }
+
+ return sqrt(dev / count);
+}
+
+double ImageHistogram::getValue(int channel, int bin)
+{
+ double value;
+
+ if ( !d->histogram || bin < 0 || bin > d->histoSegments-1 )
+ return 0.0;
+
+ switch(channel)
+ {
+ case ImageHistogram::ValueChannel:
+ value = d->histogram[bin].value;
+ break;
+
+ case ImageHistogram::RedChannel:
+ value = d->histogram[bin].red;
+ break;
+
+ case ImageHistogram::GreenChannel:
+ value = d->histogram[bin].green;
+ break;
+
+ case ImageHistogram::BlueChannel:
+ value = d->histogram[bin].blue;
+ break;
+
+ case ImageHistogram::AlphaChannel:
+ value = d->histogram[bin].alpha;
+ break;
+
+ default:
+ return 0.0;
+ break;
+ }
+
+ return value;
+}
+
+double ImageHistogram::getMaximum(int channel)
+{
+ double max = 0.0;
+ int x;
+
+ if ( !d->histogram )
+ return 0.0;
+
+ switch(channel)
+ {
+ case ImageHistogram::ValueChannel:
+ for (x = 0 ; x < d->histoSegments ; x++)
+ if (d->histogram[x].value > max)
+ max = d->histogram[x].value;
+ break;
+
+ case ImageHistogram::RedChannel:
+ for (x = 0 ; x < d->histoSegments ; x++)
+ if (d->histogram[x].red > max)
+ max = d->histogram[x].red;
+ break;
+
+ case ImageHistogram::GreenChannel:
+ for (x = 0 ; x < d->histoSegments ; x++)
+ if (d->histogram[x].green > max)
+ max = d->histogram[x].green;
+ break;
+
+ case ImageHistogram::BlueChannel:
+ for (x = 0 ; x < d->histoSegments ; x++)
+ if (d->histogram[x].blue > max)
+ max = d->histogram[x].blue;
+ break;
+
+ case ImageHistogram::AlphaChannel:
+ for (x = 0 ; x < d->histoSegments ; x++)
+ if (d->histogram[x].alpha > max)
+ max = d->histogram[x].alpha;
+ break;
+
+ default:
+ return 0.0;
+ break;
+ }
+
+ return max;
+}
+
+} // NameSpace Digikam
+