diff options
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) | 
