105 lines
2.9 KiB
C++
105 lines
2.9 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <cmath>
|
|
#include "ColorScale.h"
|
|
#include "JFJochException.h"
|
|
|
|
float luminance(rgb input) {
|
|
return 0.2126f * input.r + 0.7152f * input.g + 0.0722f * input.b;
|
|
}
|
|
|
|
ColorScale::ColorScale() : lut_(kLutSize) {
|
|
CalcLUT();
|
|
}
|
|
|
|
void ColorScale::Select(ColorScaleEnum val) {
|
|
current = val;
|
|
CalcLUT();
|
|
}
|
|
|
|
const std::vector<rgb> &ColorScale::LUTData() const {
|
|
return lut_;
|
|
}
|
|
|
|
void ColorScale::CalcLUT() const {
|
|
const std::vector<rgb>* map = nullptr;
|
|
switch (current) {
|
|
case ColorScaleEnum::Viridis: map = &viridis_colormap; break;
|
|
case ColorScaleEnum::Heat: map = &heat_colormap; break;
|
|
case ColorScaleEnum::Indigo: map = &white_to_indigo_colormap; break;
|
|
case ColorScaleEnum::BW: map = &white_to_black_colormap; break;
|
|
default:
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Color scale unknown");
|
|
}
|
|
|
|
for (size_t i = 0; i < kLutSize; ++i) {
|
|
const float f = static_cast<float>(i) / static_cast<float>(kLutSize - 1);
|
|
lut_[i] = Apply(f, *map);
|
|
}
|
|
}
|
|
|
|
rgb ColorScale::Apply(float input, const std::vector<rgb> &map) {
|
|
size_t num_colors = map.size();
|
|
if (num_colors < 2) {
|
|
throw std::invalid_argument("Colormap must have at least two colors.");
|
|
}
|
|
|
|
float scaled_value = input * (num_colors - 1);
|
|
size_t lower_idx = static_cast<size_t>(scaled_value);
|
|
size_t upper_idx = std::min(lower_idx + 1, num_colors - 1);
|
|
float t = scaled_value - lower_idx; // Fraction for interpolation
|
|
|
|
rgb lower = map[lower_idx];
|
|
rgb upper = map[upper_idx];
|
|
|
|
return {
|
|
.r = static_cast<uint8_t>(lower.r + t * (upper.r - lower.r)),
|
|
.g = static_cast<uint8_t>(lower.g + t * (upper.g - lower.g)),
|
|
.b = static_cast<uint8_t>(lower.b + t * (upper.b - lower.b))
|
|
};
|
|
}
|
|
|
|
rgb ColorScale::Apply(ColorScaleSpecial input) const {
|
|
switch (input) {
|
|
case ColorScaleSpecial::Gap:
|
|
return gap;
|
|
default:
|
|
case ColorScaleSpecial::BadPixel:
|
|
return bad;
|
|
}
|
|
}
|
|
|
|
rgb ColorScale::Apply(float input, float min, float max) const {
|
|
if (!std::isfinite(input))
|
|
return gap;
|
|
|
|
float f;
|
|
if (input <= min)
|
|
f = 0.0f;
|
|
else if (input >= max)
|
|
f = 1.0f;
|
|
else
|
|
f = (input - min) / (max - min);
|
|
|
|
const size_t idx = static_cast<size_t>(f * static_cast<float>(kLutSize - 1));
|
|
return lut_[idx];
|
|
}
|
|
|
|
rgb ColorScale::ApplyLUTIndex(size_t idx) const {
|
|
if (idx >= kLutSize)
|
|
return lut_[kLutSize-1];
|
|
return lut_[idx];
|
|
}
|
|
|
|
ColorScale &ColorScale::Gap(rgb input) {
|
|
gap = input;
|
|
return *this;
|
|
}
|
|
|
|
ColorScale &ColorScale::BadPixel(rgb input) {
|
|
bad = input;
|
|
return *this;
|
|
}
|