/* ============================================================ * * 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 * * 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 #include #include // TQt includes. #include #include // KDE includes. #include // 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