Skip to content
Snippets Groups Projects
Commit 447d973f authored by Micah Elizabeth Scott's avatar Micah Elizabeth Scott
Browse files

More accurate iterative brightness scaling algorithm

parent f444fb65
No related branches found
No related tags found
No related merge requests found
......@@ -59,7 +59,7 @@ private:
inline Brightness::Brightness(Effect &next)
: next(next),
lowerLimit(0), upperLimit(1),
currentScale(0)
currentScale(1)
{
// Fadecandy default
setAssumedGamma(2.5);
......@@ -86,33 +86,71 @@ inline void Brightness::beginFrame(const FrameInfo& f)
next.beginFrame(f);
colors.resize(f.pixels.size());
PixelInfoIter pi = f.pixels.begin();
PixelInfoIter pe = f.pixels.end();
std::vector<Vec3>::iterator ci = colors.begin();
float avg = 0;
unsigned count = 0;
for (;pi != pe; ++pi, ++ci) {
Vec3 &rgb = *ci;
// Calculate the next effect's pixels, storing them all. Also count the total number
// of mapped pixels, ignoring any unmapped ones.
if (pi->isMapped()) {
next.calculatePixel(rgb, *pi);
{
PixelInfoIter pi = f.pixels.begin();
PixelInfoIter pe = f.pixels.end();
std::vector<Vec3>::iterator ci = colors.begin();
avg += powf(rgb[0], gamma) + powf(rgb[1], gamma) + powf(rgb[2], gamma);
count++;
for (;pi != pe; ++pi, ++ci) {
if (pi->isMapped()) {
next.calculatePixel(*ci, *pi);
count++;
}
}
}
if (count && avg > 0) {
if (count == 0) {
// No LEDs mapped
return;
}
// Iterative algorithm to adjust brightness scaling. I'm not sure a closed-form
// solution exists- this is complicated for multiple reasons. We want to scale the
// entire image in a perceptually linear way, but the final brightness we're interested
// in is related to the total linear intensity of all LEDs. Additionally, the brightness
// is clamped at each LED, so we may need to increase the brightness of other LEDs to
// compensate for individual LEDs that can't get any brighter. Usually this only takes
// a few iterations to converge.
const unsigned maxIters = 50;
const float epsilon = 1e-3;
for (unsigned iter = 0; iter < maxIters; iter++) {
std::vector<Vec3>::iterator ci = colors.begin();
std::vector<Vec3>::iterator ce = colors.end();
float avg = 0;
for (;ci != ce; ++ci) {
Vec3& rgb = *ci;
// Simulated linear brightness, using current scale
for (unsigned i = 0; i < 3; i++) {
avg += powf(std::max(0.0f, std::min(1.0f, rgb[i] * currentScale)), gamma);
}
}
avg /= count;
// Make the best estimate we can for this iteration
float adjustment;
if (avg < lowerLimit) {
currentScale = powf(lowerLimit / avg, 1.0f / gamma);
adjustment = powf(lowerLimit / avg, 1.0f / gamma);
} else if (avg > upperLimit) {
currentScale = powf(upperLimit / avg, 1.0f / gamma);
adjustment = powf(upperLimit / avg, 1.0f / gamma);
} else {
currentScale = 1.0f;
adjustment = 1.0f;
}
currentScale *= adjustment;
// Was this adjustment negligible? We can quit early.
if (fabsf(adjustment - 1.0f) < epsilon) {
break;
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment