ACME-1236 : WIP : Make each color correct filter use a per channel alpha argument, tweak Instagram-like test filters for discussion
parent
90cbda6db0
commit
3cbd0dfd84
|
|
@ -687,72 +687,84 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else if (filter_name == "gamma")
|
||||
{
|
||||
raw_image->filterGamma((float)(filter_param));
|
||||
raw_image->filterGamma((float)(filter_param),LLColor3::white);
|
||||
}
|
||||
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);
|
||||
// For testing, we just colorize in the red channel, modulate by the alpha passed as a parameter
|
||||
LLColor3 color(1.0,0.0,0.0);
|
||||
LLColor3 alpha((F32)(filter_param),0.0,0.0);
|
||||
raw_image->filterColorize(color,alpha);
|
||||
}
|
||||
else if (filter_name == "contrast")
|
||||
{
|
||||
raw_image->filterContrast((float)(filter_param));
|
||||
raw_image->filterContrast((float)(filter_param),LLColor3::white);
|
||||
}
|
||||
else if (filter_name == "brighten")
|
||||
{
|
||||
raw_image->filterBrightness((S32)(filter_param));
|
||||
raw_image->filterBrightness((S32)(filter_param),LLColor3::white);
|
||||
}
|
||||
else if (filter_name == "darken")
|
||||
{
|
||||
raw_image->filterBrightness((S32)(-filter_param));
|
||||
raw_image->filterBrightness((S32)(-filter_param),LLColor3::white);
|
||||
}
|
||||
else if (filter_name == "linearize")
|
||||
{
|
||||
raw_image->filterLinearize((float)(filter_param));
|
||||
raw_image->filterLinearize((float)(filter_param),LLColor3::white);
|
||||
}
|
||||
else if (filter_name == "posterize")
|
||||
{
|
||||
raw_image->filterEqualize((S32)(filter_param));
|
||||
raw_image->filterEqualize((S32)(filter_param),LLColor3::white);
|
||||
}
|
||||
// Test for some "a la Instagram" filters
|
||||
else if (filter_name == "Lomofi")
|
||||
{
|
||||
raw_image->setVignette(VIGNETTE_MODE_BLEND,4.0,0.0);
|
||||
raw_image->filterLinearize(0.2);
|
||||
}
|
||||
else if (filter_name == "Sutro")
|
||||
{
|
||||
raw_image->filterLinearize(0.2);
|
||||
raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5);
|
||||
raw_image->filterSepia();
|
||||
}
|
||||
else if (filter_name == "Inkwell")
|
||||
{
|
||||
raw_image->filterLinearize(0.0);
|
||||
raw_image->filterGrayScale();
|
||||
raw_image->filterLinearize(0.2,LLColor3::white);
|
||||
raw_image->filterBrightness(20,LLColor3::white);
|
||||
}
|
||||
else if (filter_name == "Poprocket")
|
||||
{
|
||||
LLColor4U color = LLColor4U::red;
|
||||
color.setAlpha((U8)(0.2 * 255.0));
|
||||
raw_image->filterLinearize(0.0);
|
||||
LLColor3 color(1.0,0.0,0.0);
|
||||
LLColor3 alpha(0.5,0.0,0.0);
|
||||
raw_image->filterLinearize(0.0,LLColor3::white);
|
||||
raw_image->filterContrast(0.5,LLColor3::white);
|
||||
raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5);
|
||||
raw_image->filterColorize(color);
|
||||
raw_image->filterColorize(color,alpha);
|
||||
}
|
||||
else if (filter_name == "Gotham")
|
||||
else if (filter_name == "Sutro")
|
||||
{
|
||||
raw_image->filterLinearize(0.0);
|
||||
raw_image->filterColorBalance(1.0,1.0,20.0);
|
||||
raw_image->filterGrayScale();
|
||||
raw_image->filterLinearize(0.2,LLColor3::white);
|
||||
raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5);
|
||||
raw_image->filterSepia();
|
||||
}
|
||||
else if (filter_name == "Toaster")
|
||||
{
|
||||
raw_image->filterContrast(0.8);
|
||||
raw_image->filterContrast(0.8,LLColor3::white);
|
||||
raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5);
|
||||
raw_image->filterBrightness(10);
|
||||
raw_image->filterColorBalance(0.5,1.0,1.0);
|
||||
raw_image->filterBrightness(10,LLColor3::white);
|
||||
//raw_image->filterColorBalance(0.5,1.0,1.0);
|
||||
}
|
||||
else if (filter_name == "Inkwell")
|
||||
{
|
||||
raw_image->filterLinearize(0.0,LLColor3::white);
|
||||
raw_image->filterGrayScale();
|
||||
}
|
||||
else if (filter_name == "Hefe")
|
||||
{
|
||||
raw_image->filterLinearize(0.0,LLColor3::white);
|
||||
raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5);
|
||||
raw_image->filterContrast(1.5,LLColor3::white);
|
||||
}
|
||||
else if (filter_name == "Gotham")
|
||||
{
|
||||
raw_image->filterLinearize(0.0,LLColor3::white);
|
||||
// Blow out the Blue
|
||||
LLColor3 color(0.0,0.0,0.0);
|
||||
LLColor3 alpha(0.0,0.0,1.0);
|
||||
raw_image->filterColorize(color,alpha);
|
||||
// Convert to Grayscale
|
||||
raw_image->filterGrayScale();
|
||||
}
|
||||
|
||||
// Save file
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "llimage.h"
|
||||
|
||||
#include "llmath.h"
|
||||
#include "v3color.h"
|
||||
#include "v4coloru.h"
|
||||
#include "m3math.h"
|
||||
#include "v3math.h"
|
||||
|
|
@ -1033,19 +1034,7 @@ void LLImageRaw::filterRotate(F32 alpha)
|
|||
colorTransform(transfo);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterGamma(F32 gamma)
|
||||
{
|
||||
U8 gamma_lut[256];
|
||||
|
||||
for (S32 i = 0; i < 256; i++)
|
||||
{
|
||||
gamma_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma)))));
|
||||
}
|
||||
|
||||
colorCorrect(gamma_lut,gamma_lut,gamma_lut);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterColorBalance(F32 gamma_red, F32 gamma_green, F32 gamma_blue)
|
||||
void LLImageRaw::filterGamma(F32 gamma, const LLColor3& alpha)
|
||||
{
|
||||
U8 gamma_red_lut[256];
|
||||
U8 gamma_green_lut[256];
|
||||
|
|
@ -1053,15 +1042,17 @@ void LLImageRaw::filterColorBalance(F32 gamma_red, F32 gamma_green, F32 gamma_bl
|
|||
|
||||
for (S32 i = 0; i < 256; i++)
|
||||
{
|
||||
gamma_red_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_red)))));
|
||||
gamma_green_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_green)))));
|
||||
gamma_blue_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_blue)))));
|
||||
F32 gamma_i = llclampf((float)(pow((float)(i)/255.0,gamma)));
|
||||
// Blend in with alpha values
|
||||
gamma_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0 * gamma_i);
|
||||
gamma_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0 * gamma_i);
|
||||
gamma_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * 255.0 * gamma_i);
|
||||
}
|
||||
|
||||
colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterLinearize(F32 tail)
|
||||
void LLImageRaw::filterLinearize(F32 tail, const LLColor3& alpha)
|
||||
{
|
||||
// Get the histogram
|
||||
U32* histo = getBrightnessHistogram();
|
||||
|
|
@ -1093,13 +1084,19 @@ void LLImageRaw::filterLinearize(F32 tail)
|
|||
}
|
||||
|
||||
// Compute linear lookup table
|
||||
U8 linear_lut[256];
|
||||
U8 linear_red_lut[256];
|
||||
U8 linear_green_lut[256];
|
||||
U8 linear_blue_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);
|
||||
U8 value_i = (i < min_v ? 0 : 255);
|
||||
// Blend in with alpha values
|
||||
linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
|
||||
linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
|
||||
linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1109,15 +1106,19 @@ void LLImageRaw::filterLinearize(F32 tail)
|
|||
F32 translate = -min_v * slope;
|
||||
for (S32 i = 0; i < 256; i++)
|
||||
{
|
||||
linear_lut[i] = (U8)(llclampb((S32)(slope*i + translate)));
|
||||
U8 value_i = (U8)(llclampb((S32)(slope*i + translate)));
|
||||
// Blend in with alpha values
|
||||
linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
|
||||
linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
|
||||
linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply lookup table
|
||||
colorCorrect(linear_lut,linear_lut,linear_lut);
|
||||
colorCorrect(linear_red_lut,linear_green_lut,linear_blue_lut);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterEqualize(S32 nb_classes)
|
||||
void LLImageRaw::filterEqualize(S32 nb_classes, const LLColor3& alpha)
|
||||
{
|
||||
// Regularize the parameter: must be between 2 and 255
|
||||
nb_classes = llmax(nb_classes,2);
|
||||
|
|
@ -1142,10 +1143,15 @@ void LLImageRaw::filterEqualize(S32 nb_classes)
|
|||
S32 current_value = 0;
|
||||
|
||||
// Compute equalized lookup table
|
||||
U8 equalize_lut[256];
|
||||
U8 equalize_red_lut[256];
|
||||
U8 equalize_green_lut[256];
|
||||
U8 equalize_blue_lut[256];
|
||||
for (S32 i = 0; i < 256; i++)
|
||||
{
|
||||
equalize_lut[i] = (U8)(current_value);
|
||||
// Blend in current_value with alpha values
|
||||
equalize_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * current_value);
|
||||
equalize_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * current_value);
|
||||
equalize_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * current_value);
|
||||
if (cumulated_histo[i] >= current_count)
|
||||
{
|
||||
current_count += delta_count;
|
||||
|
|
@ -1155,73 +1161,65 @@ void LLImageRaw::filterEqualize(S32 nb_classes)
|
|||
}
|
||||
|
||||
// Apply lookup table
|
||||
colorCorrect(equalize_lut,equalize_lut,equalize_lut);
|
||||
colorCorrect(equalize_red_lut,equalize_green_lut,equalize_blue_lut);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterColorize(const LLColor4U& color)
|
||||
void LLImageRaw::filterColorize(const LLColor3& color, const LLColor3& alpha)
|
||||
{
|
||||
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]);
|
||||
F32 red_composite = 255.0 * alpha.mV[0] * color.mV[0];
|
||||
F32 green_composite = 255.0 * alpha.mV[1] * color.mV[1];
|
||||
F32 blue_composite = 255.0 * alpha.mV[2] * 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)));
|
||||
red_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[0]) * (F32)(i) + red_composite)));
|
||||
green_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[1]) * (F32)(i) + green_composite)));
|
||||
blue_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[2]) * (F32)(i) + blue_composite)));
|
||||
}
|
||||
|
||||
colorCorrect(red_lut,green_lut,blue_lut);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterContrast(F32 slope)
|
||||
void LLImageRaw::filterContrast(F32 slope, const LLColor3& alpha)
|
||||
{
|
||||
U8 contrast_lut[256];
|
||||
U8 contrast_red_lut[256];
|
||||
U8 contrast_green_lut[256];
|
||||
U8 contrast_blue_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)));
|
||||
U8 value_i = (U8)(llclampb((S32)(slope*i + translate)));
|
||||
// Blend in with alpha values
|
||||
contrast_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
|
||||
contrast_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
|
||||
contrast_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
|
||||
}
|
||||
|
||||
colorCorrect(contrast_lut,contrast_lut,contrast_lut);
|
||||
colorCorrect(contrast_red_lut,contrast_green_lut,contrast_blue_lut);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterBrightness(S32 add)
|
||||
void LLImageRaw::filterBrightness(S32 add, const LLColor3& alpha)
|
||||
{
|
||||
U8 brightness_lut[256];
|
||||
U8 brightness_red_lut[256];
|
||||
U8 brightness_green_lut[256];
|
||||
U8 brightness_blue_lut[256];
|
||||
|
||||
for (S32 i = 0; i < 256; i++)
|
||||
{
|
||||
brightness_lut[i] = (U8)(llclampb((S32)((S32)(i) + add)));
|
||||
U8 value_i = (U8)(llclampb((S32)((S32)(i) + add)));
|
||||
// Blend in with alpha values
|
||||
brightness_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
|
||||
brightness_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
|
||||
brightness_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
|
||||
}
|
||||
|
||||
colorCorrect(brightness_lut,brightness_lut,brightness_lut);
|
||||
}
|
||||
|
||||
void LLImageRaw::filterMinMax(S32 min, S32 max)
|
||||
{
|
||||
U8 contrast_lut[256];
|
||||
min = llclampb(min);
|
||||
max = llclampb(max);
|
||||
|
||||
F32 slope = 255.0/(F32)(max - min);
|
||||
F32 translate = -slope*min;
|
||||
|
||||
for (S32 i = 0; i < 256; i++)
|
||||
{
|
||||
contrast_lut[i] = (U8)(llclampb((S32)(slope*i + translate)));
|
||||
}
|
||||
|
||||
colorCorrect(contrast_lut,contrast_lut,contrast_lut);
|
||||
colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut);
|
||||
}
|
||||
|
||||
// Filter Primitives
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ const S32 HTTP_PACKET_SIZE = 1496;
|
|||
class LLImageFormatted;
|
||||
class LLImageRaw;
|
||||
class LLColor4U;
|
||||
class LLColor3;
|
||||
class LLMatrix3;
|
||||
class LLPrivateMemoryPool;
|
||||
|
||||
|
|
@ -278,19 +279,22 @@ public:
|
|||
// Src and dst are same size. Src has 4 components. Dst has 3 components.
|
||||
void compositeUnscaled4onto3( LLImageRaw* src );
|
||||
|
||||
// Filter Operations
|
||||
// Filter Operations : Transforms
|
||||
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
|
||||
void filterColorBalance(F32 gamma_red, F32 gamma_green, F32 gamma_blue); // Change the color balance applying gammas to each channel
|
||||
void filterMinMax(S32 min, S32 max); // Redistribute contrast / brightness between min and max in a linear way
|
||||
void filterRotate(F32 alpha); // Rotates hue according to alpha, alpha is an angle in degrees
|
||||
|
||||
// Filter Operations : Color Corrections
|
||||
// When specified, the LLColor3 alpha parameter indicates the intensity of the effect for each color channel
|
||||
// acting in effect as an alpha blending factor different for each channel. For instance (1.0,0.0,0.0) will apply
|
||||
// the effect only to the Red channel. Intermediate values blends the effect with the source color.
|
||||
void filterGamma(F32 gamma, const LLColor3& alpha); // Apply gamma to each channel
|
||||
void filterLinearize(F32 tail, const LLColor3& alpha); // Use histogram to linearize constrast between min and max values minus tail
|
||||
void filterEqualize(S32 nb_classes, const LLColor3& alpha); // Use histogram to equalize constrast between nb_classes throughout the image
|
||||
void filterColorize(const LLColor3& color, const LLColor3& alpha); // Colorize with color and alpha per channel
|
||||
void filterContrast(F32 slope, const LLColor3& alpha); // Change contrast according to slope: > 1.0 more contrast, < 1.0 less contrast
|
||||
void filterBrightness(S32 add, const LLColor3& alpha); // Change brightness according to add: > 0 brighter, < 0 darker
|
||||
|
||||
// Filter Primitives
|
||||
void colorTransform(const LLMatrix3 &transform);
|
||||
|
|
|
|||
Loading…
Reference in New Issue