diff options
Diffstat (limited to 'src/libs/histogram/imagehistogram.cpp')
-rw-r--r-- | src/libs/histogram/imagehistogram.cpp | 548 |
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 + |