26 const int beginBin =
static_cast<int>(begin *
static_cast<qreal
>(numberOfBins));
27 const int endBin =
static_cast<int>(end *
static_cast<qreal
>(numberOfBins)) + 1;
29 qreal numberOfSamples = 0.0;
32 for (
int i = beginBin; i < endBin; ++i) {
34 numberOfSamples += current;
35 meanSum += current *
static_cast<qreal
>(i);
38 const qreal mean = meanSum / (numberOfSamples *
static_cast<qreal
>(numberOfBins));
39 qreal probabilityAccumulator = 0.0;
42 for (
int i = beginBin; i < endBin; ++i) {
43 const qreal probability =
static_cast<qreal
>(histogram.
histogram->
getValue(i)) / numberOfSamples;
44 probabilityAccumulator += probability;
45 if (probabilityAccumulator >= 0.5) {
46 median =
static_cast<qreal
>(i) /
static_cast<qreal
>(numberOfBins);
51 return {mean, median};
55 qreal shadowsClipping,
56 qreal highlightsClipping)
65 Q_ASSERT(numberOfBins > 1);
74 qreal accumulator = 0.0;
75 for (
int i = 0; i < numberOfBins; ++i) {
76 const qreal sampleCountForBin =
static_cast<qreal
>(histogram.
histogram->
getValue(i));
77 const qreal probability = sampleCountForBin / totalNumberOfSamples;
79 accumulator += probability;
80 if (accumulator > shadowsClipping) {
86 int whitePoint = numberOfBins - 1;
88 for (
int i = numberOfBins - 1; i >= 0; --i) {
89 const qreal sampleCountForBin =
static_cast<qreal
>(histogram.
histogram->
getValue(i));
90 const qreal probability = sampleCountForBin / totalNumberOfSamples;
92 accumulator += probability;
93 if (accumulator > highlightsClipping) {
99 if (whitePoint <= blackPoint) {
100 if (blackPoint + 1 == numberOfBins) {
101 whitePoint = blackPoint;
104 whitePoint = blackPoint + 1;
110 static_cast<qreal
>(blackPoint) /
static_cast<qreal
>(numberOfBins),
111 static_cast<qreal
>(whitePoint) /
static_cast<qreal
>(numberOfBins)
116 qreal shadowsClipping,
117 qreal highlightsClipping);
119qreal
getGamma(qreal blackPoint, qreal whitePoint, qreal inputIntensity, qreal outputIntensity)
121 Q_ASSERT(blackPoint < whitePoint);
122 Q_ASSERT(inputIntensity >= blackPoint && inputIntensity <= whitePoint);
131 const qreal inputIntensityAfterLinearMapping =
132 (inputIntensity - blackPoint) / (whitePoint - blackPoint);
134 return qBound(0.01, log(inputIntensityAfterLinearMapping) / log(outputIntensity), 10.0);
140 qreal shadowsClipping,
141 qreal highlightsClipping,
142 qreal maximumInputBlackAndWhiteOffset,
144 qreal midtonesAdjustmentAmount,
150 Q_ASSERT(lightnessHistogram.
channel >= 0);
152 Q_ASSERT(outputBlackPoints.size() == channelsHistograms.size());
153 Q_ASSERT(outputWhitePoints.size() == channelsHistograms.size());
154 Q_ASSERT(outputMidtones.size() == channelsHistograms.size());
158 const QPair<qreal, qreal> inputBlackAndWhitePoints =
160 const qreal inputBlackPoint = qMin(maximumInputBlackAndWhiteOffset, inputBlackAndWhitePoints.first);
161 const qreal inputWhitePoint = qMax(1.0 - maximumInputBlackAndWhiteOffset, inputBlackAndWhitePoints.second);
162 const qreal linearMappingMidPoint = (inputBlackPoint + inputWhitePoint) / 2.0;
164 for (
int i = 0; i < channelsHistograms.size(); ++i) {
170 channelHistogram.
channel >= 0 &&
173 qreal inputIntensity;
174 QPair<qreal, qreal> meanAndMedian =
getMeanAndMedian(channelHistogram, inputBlackPoint, inputWhitePoint);
177 inputIntensity = meanAndMedian.first;
179 inputIntensity = meanAndMedian.second;
182 inputIntensity = linearMappingMidPoint + (inputIntensity - linearMappingMidPoint) * midtonesAdjustmentAmount;
183 gamma =
getGamma(inputBlackPoint, inputWhitePoint, inputIntensity, outputMidtones[i]);
191 outputBlackPoints[i],
201 qreal shadowsClipping,
202 qreal highlightsClipping,
203 qreal maximumInputBlackAndWhiteOffset,
205 qreal midtonesAdjustmentAmount,
212 for (
int i = 0; i < channelsHistograms.size(); ++i) {
220 maximumInputBlackAndWhiteOffset,
221 midtonesAdjustmentMethod,
222 midtonesAdjustmentAmount,
223 {outputBlackPoints[i]},
224 {outputWhitePoints[i]},
void setChannel(qint32 channel)
quint32 getValue(quint8 i)
KoHistogramProducer * producer()
This class holds the parameters for a levels adjustment. It is modeled after KisCubicCurve and has si...
virtual qint32 numberOfBins()=0
virtual QList< KoChannelInfo * > channels()=0
static bool qFuzzyCompare(half p1, half p2)
static bool qFuzzyIsNull(half h)
This namespace contains functions to compute the levels adjustment parameters automatically from a hi...
QPair< qreal, qreal > getMeanAndMedian(ChannelHistogram histogram, qreal begin, qreal end)
QPair< KoColor, KoColor > getDarkestAndWhitestColors(const KisPaintDeviceSP device, qreal shadowsClipping, qreal highlightsClipping)
Finds the darkest and whitest colors in the device having into account the clipping.
QVector< KisLevelsCurve > adjustMonochromaticContrast(ChannelHistogram lightnessHistogram, QVector< ChannelHistogram > &channelsHistograms, qreal shadowsClipping, qreal highlightsClipping, qreal maximumInputBlackAndWhiteOffset, MidtonesAdjustmentMethod midtonesAdjustmentMethod, qreal midtonesAdjustmentAmount, const QVector< qreal > &outputBlackPoints, const QVector< qreal > &outputWhitePoints, const QVector< qreal > &outputMidtones)
Creates a KisLevelsCurve for every channel in "channelsHistograms". Computes the input black and whit...
QVector< KisLevelsCurve > adjustPerChannelContrast(QVector< ChannelHistogram > &channelsHistograms, qreal shadowsClipping, qreal highlightsClipping, qreal maximumInputBlackAndWhiteOffset, MidtonesAdjustmentMethod midtonesAdjustmentMethod, qreal midtonesAdjustmentAmount, const QVector< qreal > &outputBlackPoints, const QVector< qreal > &outputWhitePoints, const QVector< qreal > &outputMidtones)
Creates a KisLevelsCurve for every channel in "channelsHistograms". Computes the input black and whit...
MidtonesAdjustmentMethod
The different methods to enhance the mid tones.
@ MidtonesAdjustmentMethod_None
@ MidtonesAdjustmentMethod_UseMean
qreal getGamma(qreal blackPoint, qreal whitePoint, qreal inputIntensity, qreal outputIntensity)
Computes a gamma value that "moves" the input midpoint towards the output midpoint.
QPair< qreal, qreal > getInputBlackAndWhitePoints(ChannelHistogram histogram, qreal shadowsClipping, qreal highlightsClipping)
Takes a reference histogram (luma, lightness) and computes the black and white points to maximize the...
Convenience class that associates a KisHistogram and a channel index. This is useful because setting ...