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 | |
parent | 205a4e3dc63c338c05e27a4806cdfd6f50bac2b6 (diff) |
ACME-1236 : WIP : added all the color correction filters: colorize, linarize, equalize, contrast, brightness
Diffstat (limited to 'indra')
-rwxr-xr-x | indra/integration_tests/llimage_libtest/CMakeLists.txt | 3 | ||||
-rwxr-xr-x | indra/integration_tests/llimage_libtest/llimage_libtest.cpp | 44 | ||||
-rwxr-xr-x | indra/llimage/llimage.cpp | 155 | ||||
-rwxr-xr-x | indra/llimage/llimage.h | 16 |
4 files changed, 209 insertions, 9 deletions
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt index 36a7d38bb7..8a83ac498f 100755 --- a/indra/integration_tests/llimage_libtest/CMakeLists.txt +++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt @@ -7,6 +7,7 @@ project (llimage_libtest) include(00-Common) include(LLCommon) include(LLImage) +include(LLMath) include(LLImageJ2COJ) include(LLKDU) include(LLVFS) @@ -15,6 +16,7 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} ) include_directories(SYSTEM ${LLCOMMON_SYSTEM_INCLUDE_DIRS} @@ -64,6 +66,7 @@ endif (DARWIN) target_link_libraries(llimage_libtest ${LLCOMMON_LIBRARIES} ${LLVFS_LIBRARIES} + ${LLMATH_LIBRARIES} ${LLIMAGE_LIBRARIES} ${LLKDU_LIBRARIES} ${KDU_LIBRARY} diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index afd5e2ce98..4d32282a0d 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -39,6 +39,7 @@ #include "llimagej2c.h" #include "lldir.h" #include "lldiriterator.h" +#include "v4coloru.h" // system libraries #include <iostream> @@ -84,10 +85,18 @@ static const char USAGE[] = "\n" " Set the compression to be lossless (reversible in j2c parlance).\n" " Only valid for output j2c images.\n" " -f, --filter <name> [<param>]\n" -" Apply the filter <name> to the input images using the optional param (float) value:\n" -" - 'grayscale' and 'sepia' just do that (no param).\n" -" - 'saturate' changes color saturation according to param: param < 1.0 will desaturate, param > 1.0 will saturate.\n" -" - 'rotate' rotates the color hue according to param (in degree, positive value only).\n" +" Apply the filter <name> to the input images using the optional <param> value. Admissible names:\n" +" - 'grayscale' converts to grayscale (no param).\n" +" - 'sepia' converts to sepia (no param).\n" +" - 'saturate' changes color saturation according to <param>: < 1.0 will desaturate, > 1.0 will saturate.\n" +" - 'rotate' rotates the color hue according to <param> (in degree, positive value only).\n" +" - 'gamma' applies gamma curve <param> to all channels: > 1.0 will darken, < 1.0 will lighten.\n" +" - 'colorize' applies a red tint to the image using <param> as an alpha (transparency between 0.0 and 1.0) value.\n" +" - 'contrast' modifies the contrast according to <param> : > 1.0 will enhance the contrast, <1.0 will flatten it.\n" +" - 'brighten' adds <param> light to the image (<param> between 0 and 255).\n" +" - 'darken' substracts <param> light to the image (<param> between 0 and 255).\n" +" - 'linearize' optimizes the contrast using the brightness histogram. <param> is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" +" - 'posterize' redistributes the colors between <param> classes per channel (<param> between 2 and 255).\n" " -log, --logmetrics <metric>\n" " Log performance data for <metric>. Results in <metric>.slp\n" " Note: so far, only ImageCompressionTester has been tested.\n" @@ -626,6 +635,33 @@ int main(int argc, char** argv) { raw_image->filterGamma((float)(filter_param)); } + else if (filter_name == "colorize") + { + // For testing, we just colorize in red, modulate by the alpha passed as a parameter + LLColor4U color = LLColor4U::red; + color.setAlpha((U8)(filter_param * 255.0)); + raw_image->filterColorize(color); + } + else if (filter_name == "contrast") + { + raw_image->filterContrast((float)(filter_param)); + } + else if (filter_name == "brighten") + { + raw_image->filterBrightness((S32)(filter_param)); + } + else if (filter_name == "darken") + { + raw_image->filterBrightness((S32)(-filter_param)); + } + else if (filter_name == "linearize") + { + raw_image->filterLinearize((float)(filter_param)); + } + else if (filter_name == "posterize") + { + raw_image->filterEqualize((S32)(filter_param)); + } // Save file if (out_file != out_end) 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) |