diff options
author | Merov Linden <merov@lindenlab.com> | 2014-01-02 16:14:38 -0800 |
---|---|---|
committer | Merov Linden <merov@lindenlab.com> | 2014-01-02 16:14:38 -0800 |
commit | d28b92744ee0d4a19a5587585998e5c351f6d300 (patch) | |
tree | 21281b842216cfd32e7eae7ee72953dc15f8e5be /indra/llimage | |
parent | 205a4e3dc63c338c05e27a4806cdfd6f50bac2b6 (diff) |
ACME-1236 : WIP : added all the color correction filters: colorize, linarize, equalize, contrast, brightness
Diffstat (limited to 'indra/llimage')
-rwxr-xr-x | indra/llimage/llimage.cpp | 155 | ||||
-rwxr-xr-x | indra/llimage/llimage.h | 16 |
2 files changed, 166 insertions, 5 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index d406995f3a..5dc9c24f6c 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1042,6 +1042,152 @@ void LLImageRaw::filterGamma(F32 gamma) colorCorrect(gamma_lut,gamma_lut,gamma_lut); } +void LLImageRaw::filterLinearize(F32 tail) +{ + // Get the histogram + U32* histo = getBrightnessHistogram(); + + // Compute cumulated histogram + U32 cumulated_histo[256]; + cumulated_histo[0] = histo[0]; + for (S32 i = 1; i < 256; i++) + { + cumulated_histo[i] = cumulated_histo[i-1] + histo[i]; + } + + // Compute min and max counts minus tail + tail = llclampf(tail); + S32 total = cumulated_histo[255]; + S32 min_c = (S32)((F32)(total) * tail); + S32 max_c = (S32)((F32)(total) * (1.0 - tail)); + + // Find min and max values + S32 min_v = 0; + while (cumulated_histo[min_v] < min_c) + { + min_v++; + } + S32 max_v = 255; + while (cumulated_histo[max_v] > max_c) + { + max_v--; + } + + // Compute linear lookup table + U8 linear_lut[256]; + if (max_v == min_v) + { + // Degenerated binary split case + for (S32 i = 0; i < 256; i++) + { + linear_lut[i] = (i < min_v ? 0 : 255); + } + } + else + { + // Linearize between min and max + F32 slope = 255.0 / (F32)(max_v - min_v); + F32 translate = -min_v * slope; + for (S32 i = 0; i < 256; i++) + { + linear_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + } + } + + // Apply lookup table + colorCorrect(linear_lut,linear_lut,linear_lut); +} + +void LLImageRaw::filterEqualize(S32 nb_classes) +{ + // Regularize the parameter: must be between 2 and 255 + nb_classes = llmax(nb_classes,2); + nb_classes = llclampb(nb_classes); + + // Get the histogram + U32* histo = getBrightnessHistogram(); + + // Compute cumulated histogram + U32 cumulated_histo[256]; + cumulated_histo[0] = histo[0]; + for (S32 i = 1; i < 256; i++) + { + cumulated_histo[i] = cumulated_histo[i-1] + histo[i]; + } + + // Compute deltas + S32 total = cumulated_histo[255]; + S32 delta_count = total / nb_classes; + S32 current_count = delta_count; + S32 delta_value = 256 / (nb_classes - 1); + S32 current_value = 0; + + // Compute equalized lookup table + U8 equalize_lut[256]; + for (S32 i = 0; i < 256; i++) + { + equalize_lut[i] = (U8)(current_value); + if (cumulated_histo[i] >= current_count) + { + current_count += delta_count; + current_value += delta_value; + current_value = llclampb(current_value); + } + } + + // Apply lookup table + colorCorrect(equalize_lut,equalize_lut,equalize_lut); +} + +void LLImageRaw::filterColorize(const LLColor4U& color) +{ + U8 red_lut[256]; + U8 green_lut[256]; + U8 blue_lut[256]; + + F32 alpha = (F32)(color.mV[3])/255.0; + F32 inv_alpha = 1.0 - alpha; + + F32 red_composite = alpha * (F32)(color.mV[0]); + F32 green_composite = alpha * (F32)(color.mV[1]); + F32 blue_composite = alpha * (F32)(color.mV[2]); + + for (S32 i = 0; i < 256; i++) + { + red_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + red_composite))); + green_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + green_composite))); + blue_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + blue_composite))); + } + + colorCorrect(red_lut,green_lut,blue_lut); +} + +void LLImageRaw::filterContrast(F32 slope) +{ + U8 contrast_lut[256]; + + F32 translate = 128.0 * (1.0 - slope); + + for (S32 i = 0; i < 256; i++) + { + contrast_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + } + + colorCorrect(contrast_lut,contrast_lut,contrast_lut); +} + +void LLImageRaw::filterBrightness(S32 add) +{ + U8 brightness_lut[256]; + + for (S32 i = 0; i < 256; i++) + { + brightness_lut[i] = (U8)(llclampb((S32)((S32)(i) + add))); + } + + colorCorrect(brightness_lut,brightness_lut,brightness_lut); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { @@ -1078,6 +1224,15 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } +U32* LLImageRaw::getBrightnessHistogram() +{ + if (!mHistoBrightness) + { + computeHistograms(); + } + return mHistoBrightness; +} + void LLImageRaw::computeHistograms() { const S32 components = getComponents(); diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 89734693cc..b62deadee0 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -264,15 +264,21 @@ public: void compositeUnscaled4onto3( LLImageRaw* src ); // Filter Operations - void filterGrayScale(); - void filterSepia(); - void filterSaturate(F32 saturation); // < 1.0 desaturates, > 1.0 saturates - void filterRotate(F32 alpha); // rotates hue, alpha in degrees - void filterGamma(F32 gamma); // Apply a gamma lookup to all channels + void filterGrayScale(); // Convert to grayscale + void filterSepia(); // Convert to sepia + void filterSaturate(F32 saturation); // < 1.0 desaturates, > 1.0 saturates + void filterRotate(F32 alpha); // Rotates hue according to alpha, alpha in degrees + void filterGamma(F32 gamma); // Apply gamma to all channels + void filterLinearize(F32 tail); // Use histogram to linearize constrast between min and max values minus tail + void filterEqualize(S32 nb_classes); // Use histogram to equalize constrast throughout the image + void filterColorize(const LLColor4U& color); // Colorize with color. Alpha will be taken into account for colorization intensity. + void filterContrast(F32 slope); // Change contrast according to slope: > 1.0 more contrast, < 1.0 less contrast + void filterBrightness(S32 add); // Change brightness according to add: > 0 brighter, < 0 darker // Filter Primitives void colorTransform(const LLMatrix3 &transform); void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue); + U32* getBrightnessHistogram(); protected: // Create an image from a local file (generally used in tools) |