/* * Copyright (c) 2004 Boudewijn Rempt * (c) 2005 Bart Coppens * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include // ### Debug #include "kis_types.h" #include "kis_histogram.h" #include "kis_paint_layer.h" #include "kis_iterators_pixel.h" #include "kis_colorspace.h" #include "kis_debug_areas.h" KisHistogram::KisHistogram(KisPaintLayerSP layer, KisHistogramProducerSP producer, const enumHistogramType type) { m_dev = layer->paintDevice(); m_type = type; m_producer = producer; m_selection = false; m_channel = 0; updateHistogram(); } KisHistogram::KisHistogram(KisPaintDeviceSP paintdev, KisHistogramProducerSP producer, const enumHistogramType type) { m_dev = paintdev; m_type = type; m_producer = producer; m_selection = false; m_channel = 0; updateHistogram(); } KisHistogram::~KisHistogram() { } void KisHistogram::updateHistogram() { Q_INT32 x,y,w,h; m_dev->exactBounds(x,y,w,h); KisRectIteratorPixel srcIt = m_dev->createRectIterator(x,y,w,h, false); KisColorSpace* cs = m_dev->colorSpace(); QTime t; t.start(); // Let the producer do it's work m_producer->clear(); int i; // Handle degenerate case (this happens with the accumulating histogram, // which has an empty device) if (srcIt.isDone()) { m_producer->addRegionToBin(0, 0, 0, cs); } else { while ( !srcIt.isDone() ) { i = srcIt.nConseqPixels(); m_producer->addRegionToBin(srcIt.rawData(), srcIt.selectionMask(), i, cs); srcIt += i; } } computeHistogram(); } void KisHistogram::computeHistogram() { m_completeCalculations = calculateForRange(m_producer->viewFrom(), m_producer->viewFrom() + m_producer->viewWidth()); if (m_selection) { m_selectionCalculations = calculateForRange(m_selFrom, m_selTo); } else { m_selectionCalculations.clear(); } #if 1 dump(); #endif } KisHistogram::Calculations KisHistogram::calculations() { return m_completeCalculations.at(m_channel); } KisHistogram::Calculations KisHistogram::selectionCalculations() { return m_selectionCalculations.at(m_channel); } QValueVector KisHistogram::calculateForRange(double from, double to) { QValueVector calculations; uint count = m_producer->channels().count(); for (uint i = 0; i < count; i++) { calculations.append(calculateSingleRange(i, from, to)); } return calculations; } KisHistogram::Calculations KisHistogram::calculateSingleRange(int channel, double from, double to) { Calculations c; // XXX If from == to, we only want a specific bin, handle that properly! double max = from, min = to, total = 0.0, mean = 0.0; //, median = 0.0, stddev = 0.0; Q_UINT32 high = 0, low = (Q_UINT32) -1, count = 0; if (m_producer->count() == 0) { // We won't get anything, even if a range is specified // XXX make sure all initial '0' values are correct here! return c; } Q_INT32 totbins = m_producer->numberOfBins(); Q_UINT32 current; // convert the double range into actual bins: double factor = static_cast(totbins) / m_producer->viewWidth(); Q_INT32 fromBin = static_cast((from - m_producer->viewFrom()) * factor); Q_INT32 toBin = fromBin + static_cast((to - from) * factor); // Min, max, count, low, high for (Q_INT32 i = fromBin; i < toBin; i++) { current = m_producer->getBinAt(channel, i); double pos = static_cast(i) / factor + from; if (current > high) high = current; if (current < low) low = current; if (current > 0) { if (pos < min) min = pos; if (pos > max) max = pos; } // We do the count here as well. // we can't use m_producer->count() for this, because of the range count += current; total += current * pos; } if (count > 0) mean = total / count; c.m_high = high; c.m_low = low; c.m_count = count; c.m_min = min; c.m_max = max; c.m_mean = mean; c.m_total = total; return c; } void KisHistogram::dump() { kdDebug(DBG_AREA_MATH) << "Histogram\n"; switch (m_type) { case LINEAR: kdDebug(DBG_AREA_MATH) << "Linear histogram\n"; break; case LOGARITHMIC: kdDebug(DBG_AREA_MATH) << "Logarithmic histogram\n"; } kdDebug(DBG_AREA_MATH) << "Dumping channel " << m_channel << endl; Calculations c = calculations(); /* for( int i = 0; i <256; ++i ) { kdDebug(DBG_AREA_MATH) << "Value " << QString().setNum(i) << ": " << QString().setNum(m_values[i]) << "\n"; }*/ kdDebug(DBG_AREA_MATH) << "\n"; kdDebug(DBG_AREA_MATH) << "Max: " << QString().setNum(c.getMax()) << "\n"; kdDebug(DBG_AREA_MATH) << "Min: " << QString().setNum(c.getMin()) << "\n"; kdDebug(DBG_AREA_MATH) << "High: " << QString().setNum(c.getHighest()) << "\n"; kdDebug(DBG_AREA_MATH) << "Low: " << QString().setNum(c.getLowest()) << "\n"; kdDebug(DBG_AREA_MATH) << "Mean: " << m_producer->positionToString(c.getMean()) << "\n"; kdDebug(DBG_AREA_MATH) << "Total: " << QString().setNum(c.getTotal()) << "\n"; // kdDebug(DBG_AREA_MATH) << "Median: " << QString().setNum(m_median) << "\n"; // kdDebug(DBG_AREA_MATH) << "Stddev: " << QString().setNum(m_stddev) << "\n"; // kdDebug(DBG_AREA_MATH) << "percentile: " << QString().setNum(m_percentile) << "\n"; kdDebug(DBG_AREA_MATH) << "\n"; }