ACME-1236 : WIP : Added the vignette mode. Can be applied to colorCorrect and color Transform. Added new -v argument to llimage_libtest
parent
d28b92744e
commit
1b5fb66292
|
|
@ -97,6 +97,10 @@ static const char USAGE[] = "\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"
|
||||
" -v, --vignette <name> [<feather>]\n"
|
||||
" Apply a circular central vignette <name> to the filter using the optional <feather> value. Admissible names:\n"
|
||||
" - 'blend' : the filter is applied with full intensity in the center and blends with the image to the periphery.\n"
|
||||
" - 'fade' : the filter is applied with full intensity in the center and fades to black to the periphery.\n"
|
||||
" -log, --logmetrics <metric>\n"
|
||||
" Log performance data for <metric>. Results in <metric>.slp\n"
|
||||
" Note: so far, only ImageCompressionTester has been tested.\n"
|
||||
|
|
@ -366,6 +370,8 @@ int main(int argc, char** argv)
|
|||
bool reversible = false;
|
||||
std::string filter_name = "";
|
||||
double filter_param = 0.0;
|
||||
std::string vignette_name = "";
|
||||
double vignette_param = 1.0;
|
||||
|
||||
// Init whatever is necessary
|
||||
ll_init_apr();
|
||||
|
|
@ -568,7 +574,36 @@ int main(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
|
||||
else if (!strcmp(argv[arg], "--vignette") || !strcmp(argv[arg], "-v"))
|
||||
{
|
||||
// '--vignette' needs to be specified with a named vignette argument
|
||||
if ((arg + 1) < argc)
|
||||
{
|
||||
vignette_name = argv[arg+1];
|
||||
}
|
||||
if (((arg + 1) >= argc) || (vignette_name[0] == '-'))
|
||||
{
|
||||
// We don't have an argument left in the arg list or the next argument is another option
|
||||
std::cout << "No --vignette argument given, no vignette will be applied to filters" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg += 1; // Skip that arg now we know it's a valid vignette name
|
||||
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
|
||||
break;
|
||||
// --vignette can also have an optional parameter
|
||||
std::string value_str;
|
||||
value_str = argv[arg+1]; // Check the next arg
|
||||
if (value_str[0] != '-') // If it's not another argument, it's a vignette parameter value
|
||||
{
|
||||
vignette_param = atof(value_str.c_str());
|
||||
arg += 1; // Skip that arg now we used it as a valid vignette param
|
||||
if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
|
||||
{
|
||||
analyze_performance = true;
|
||||
}
|
||||
|
|
@ -614,6 +649,16 @@ int main(int argc, char** argv)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Set the vignette if any
|
||||
if (vignette_name == "blend")
|
||||
{
|
||||
raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(vignette_param));
|
||||
}
|
||||
else if (vignette_name == "fade")
|
||||
{
|
||||
raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(vignette_param));
|
||||
}
|
||||
|
||||
// Apply filter if any
|
||||
if (filter_name == "sepia")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -101,7 +101,9 @@ LLImageBase::LLImageBase()
|
|||
mHistoRed(NULL),
|
||||
mHistoGreen(NULL),
|
||||
mHistoBlue(NULL),
|
||||
mHistoBrightness(NULL)
|
||||
mHistoBrightness(NULL),
|
||||
mVignetteMode(VIGNETTE_MODE_NONE),
|
||||
mVignetteGamma(1.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1194,17 +1196,44 @@ void LLImageRaw::colorTransform(const LLMatrix3 &transform)
|
|||
const S32 components = getComponents();
|
||||
llassert( components >= 1 && components <= 4 );
|
||||
|
||||
S32 pixels = getWidth() * getHeight();
|
||||
S32 width = getWidth();
|
||||
S32 height = getHeight();
|
||||
|
||||
U8* dst_data = getData();
|
||||
for (S32 i = 0; i < pixels; i++)
|
||||
for (S32 j = 0; j < height; j++)
|
||||
{
|
||||
LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE]));
|
||||
LLVector3 dst = src * transform;
|
||||
dst.clamp(0.0f,255.0f);
|
||||
dst_data[VRED] = dst.mV[VRED];
|
||||
dst_data[VGREEN] = dst.mV[VGREEN];
|
||||
dst_data[VBLUE] = dst.mV[VBLUE];
|
||||
dst_data += components;
|
||||
for (S32 i = 0; i < width; i++)
|
||||
{
|
||||
LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE]));
|
||||
LLVector3 dst = src * transform;
|
||||
dst.clamp(0.0f,255.0f);
|
||||
if (mVignetteMode == VIGNETTE_MODE_NONE)
|
||||
{
|
||||
dst_data[VRED] = dst.mV[VRED];
|
||||
dst_data[VGREEN] = dst.mV[VGREEN];
|
||||
dst_data[VBLUE] = dst.mV[VBLUE];
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 alpha = getVignetteAlpha(i,j);
|
||||
if (mVignetteMode == VIGNETTE_MODE_BLEND)
|
||||
{
|
||||
// Blends with the source image on the edges
|
||||
F32 inv_alpha = 1.0 - alpha;
|
||||
dst_data[VRED] = inv_alpha * src.mV[VRED] + alpha * dst.mV[VRED];
|
||||
dst_data[VGREEN] = inv_alpha * src.mV[VGREEN] + alpha * dst.mV[VGREEN];
|
||||
dst_data[VBLUE] = inv_alpha * src.mV[VBLUE] + alpha * dst.mV[VBLUE];
|
||||
}
|
||||
else // VIGNETTE_MODE_FADE
|
||||
{
|
||||
// Fade to black on the edges
|
||||
dst_data[VRED] = alpha * dst.mV[VRED];
|
||||
dst_data[VGREEN] = alpha * dst.mV[VGREEN];
|
||||
dst_data[VBLUE] = alpha * dst.mV[VBLUE];
|
||||
}
|
||||
}
|
||||
dst_data += components;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1213,17 +1242,62 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8*
|
|||
const S32 components = getComponents();
|
||||
llassert( components >= 1 && components <= 4 );
|
||||
|
||||
S32 pixels = getWidth() * getHeight();
|
||||
S32 width = getWidth();
|
||||
S32 height = getHeight();
|
||||
|
||||
U8* dst_data = getData();
|
||||
for (S32 i = 0; i < pixels; i++)
|
||||
for (S32 j = 0; j < height; j++)
|
||||
{
|
||||
dst_data[VRED] = lut_red[dst_data[VRED]];
|
||||
dst_data[VGREEN] = lut_green[dst_data[VGREEN]];
|
||||
dst_data[VBLUE] = lut_blue[dst_data[VBLUE]];
|
||||
dst_data += components;
|
||||
for (S32 i = 0; i < width; i++)
|
||||
{
|
||||
if (mVignetteMode == VIGNETTE_MODE_NONE)
|
||||
{
|
||||
dst_data[VRED] = lut_red[dst_data[VRED]];
|
||||
dst_data[VGREEN] = lut_green[dst_data[VGREEN]];
|
||||
dst_data[VBLUE] = lut_blue[dst_data[VBLUE]];
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 alpha = getVignetteAlpha(i,j);
|
||||
if (mVignetteMode == VIGNETTE_MODE_BLEND)
|
||||
{
|
||||
// Blends with the source image on the edges
|
||||
F32 inv_alpha = 1.0 - alpha;
|
||||
dst_data[VRED] = inv_alpha * dst_data[VRED] + alpha * lut_red[dst_data[VRED]];
|
||||
dst_data[VGREEN] = inv_alpha * dst_data[VGREEN] + alpha * lut_green[dst_data[VGREEN]];
|
||||
dst_data[VBLUE] = inv_alpha * dst_data[VBLUE] + alpha * lut_blue[dst_data[VBLUE]];
|
||||
}
|
||||
else // VIGNETTE_MODE_FADE
|
||||
{
|
||||
// Fade to black on the edges
|
||||
dst_data[VRED] = alpha * lut_red[dst_data[VRED]];
|
||||
dst_data[VGREEN] = alpha * lut_green[dst_data[VGREEN]];
|
||||
dst_data[VBLUE] = alpha * lut_blue[dst_data[VBLUE]];
|
||||
}
|
||||
}
|
||||
dst_data += components;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma)
|
||||
{
|
||||
mVignetteMode = mode;
|
||||
mVignetteGamma = gamma;
|
||||
// We always center the vignette on the image and fits it in the image smallest dimension
|
||||
mVignetteCenterX = getWidth()/2;
|
||||
mVignetteCenterY = getHeight()/2;
|
||||
mVignetteWidth = llmin(getWidth()/2,getHeight()/2);
|
||||
}
|
||||
|
||||
F32 LLImageRaw::getVignetteAlpha(S32 i, S32 j)
|
||||
{
|
||||
// alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges
|
||||
// the gamma parameter controls the intensity of the drop down from alpha 1.0 to 0.0
|
||||
F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY);
|
||||
return powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f));
|
||||
}
|
||||
|
||||
U32* LLImageRaw::getBrightnessHistogram()
|
||||
{
|
||||
if (!mHistoBrightness)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,13 @@ typedef enum e_image_codec
|
|||
IMG_CODEC_EOF = 8
|
||||
} EImageCodec;
|
||||
|
||||
typedef enum e_vignette_mode
|
||||
{
|
||||
VIGNETTE_MODE_NONE = 0,
|
||||
VIGNETTE_MODE_BLEND = 1,
|
||||
VIGNETTE_MODE_FADE = 2
|
||||
} EVignetteMode;
|
||||
|
||||
//============================================================================
|
||||
// library initialization class
|
||||
|
||||
|
|
@ -157,6 +164,13 @@ protected:
|
|||
U32 *mHistoBlue;
|
||||
U32 *mHistoBrightness;
|
||||
|
||||
// Vignette filtering
|
||||
EVignetteMode mVignetteMode;
|
||||
S32 mVignetteCenterX;
|
||||
S32 mVignetteCenterY;
|
||||
S32 mVignetteWidth;
|
||||
F32 mVignetteGamma;
|
||||
|
||||
public:
|
||||
static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
|
||||
|
||||
|
|
@ -278,6 +292,7 @@ public:
|
|||
// Filter Primitives
|
||||
void colorTransform(const LLMatrix3 &transform);
|
||||
void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue);
|
||||
void setVignette(EVignetteMode mode, F32 gamma);
|
||||
U32* getBrightnessHistogram();
|
||||
|
||||
protected:
|
||||
|
|
@ -292,6 +307,7 @@ protected:
|
|||
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
||||
|
||||
void computeHistograms();
|
||||
F32 getVignetteAlpha(S32 i, S32 j);
|
||||
|
||||
public:
|
||||
static S32 sGlobalRawMemory;
|
||||
|
|
|
|||
Loading…
Reference in New Issue