Skip to content
Snippets Groups Projects
Commit 1b5fb662 authored by Merov Linden's avatar Merov Linden
Browse files

ACME-1236 : WIP : Added the vignette mode. Can be applied to colorCorrect and...

ACME-1236 : WIP : Added the vignette mode. Can be applied to colorCorrect and color Transform. Added new -v argument to llimage_libtest
parent d28b9274
No related branches found
No related tags found
No related merge requests found
...@@ -97,6 +97,10 @@ static const char USAGE[] = "\n" ...@@ -97,6 +97,10 @@ static const char USAGE[] = "\n"
" - 'darken' substracts <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" " - '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" " - '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, --logmetrics <metric>\n"
" Log performance data for <metric>. Results in <metric>.slp\n" " Log performance data for <metric>. Results in <metric>.slp\n"
" Note: so far, only ImageCompressionTester has been tested.\n" " Note: so far, only ImageCompressionTester has been tested.\n"
...@@ -366,6 +370,8 @@ int main(int argc, char** argv) ...@@ -366,6 +370,8 @@ int main(int argc, char** argv)
bool reversible = false; bool reversible = false;
std::string filter_name = ""; std::string filter_name = "";
double filter_param = 0.0; double filter_param = 0.0;
std::string vignette_name = "";
double vignette_param = 1.0;
// Init whatever is necessary // Init whatever is necessary
ll_init_apr(); ll_init_apr();
...@@ -568,7 +574,36 @@ int main(int argc, char** argv) ...@@ -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; analyze_performance = true;
} }
...@@ -614,6 +649,16 @@ int main(int argc, char** argv) ...@@ -614,6 +649,16 @@ int main(int argc, char** argv)
continue; 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 // Apply filter if any
if (filter_name == "sepia") if (filter_name == "sepia")
{ {
......
...@@ -101,7 +101,9 @@ LLImageBase::LLImageBase() ...@@ -101,7 +101,9 @@ LLImageBase::LLImageBase()
mHistoRed(NULL), mHistoRed(NULL),
mHistoGreen(NULL), mHistoGreen(NULL),
mHistoBlue(NULL), mHistoBlue(NULL),
mHistoBrightness(NULL) mHistoBrightness(NULL),
mVignetteMode(VIGNETTE_MODE_NONE),
mVignetteGamma(1.0)
{ {
} }
...@@ -1194,17 +1196,44 @@ void LLImageRaw::colorTransform(const LLMatrix3 &transform) ...@@ -1194,17 +1196,44 @@ void LLImageRaw::colorTransform(const LLMatrix3 &transform)
const S32 components = getComponents(); const S32 components = getComponents();
llassert( components >= 1 && components <= 4 ); llassert( components >= 1 && components <= 4 );
S32 pixels = getWidth() * getHeight(); S32 width = getWidth();
S32 height = getHeight();
U8* dst_data = getData(); 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])); for (S32 i = 0; i < width; i++)
LLVector3 dst = src * transform; {
dst.clamp(0.0f,255.0f); LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE]));
dst_data[VRED] = dst.mV[VRED]; LLVector3 dst = src * transform;
dst_data[VGREEN] = dst.mV[VGREEN]; dst.clamp(0.0f,255.0f);
dst_data[VBLUE] = dst.mV[VBLUE]; if (mVignetteMode == VIGNETTE_MODE_NONE)
dst_data += components; {
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* ...@@ -1213,17 +1242,62 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8*
const S32 components = getComponents(); const S32 components = getComponents();
llassert( components >= 1 && components <= 4 ); llassert( components >= 1 && components <= 4 );
S32 pixels = getWidth() * getHeight(); S32 width = getWidth();
S32 height = getHeight();
U8* dst_data = getData(); 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]]; for (S32 i = 0; i < width; i++)
dst_data[VGREEN] = lut_green[dst_data[VGREEN]]; {
dst_data[VBLUE] = lut_blue[dst_data[VBLUE]]; if (mVignetteMode == VIGNETTE_MODE_NONE)
dst_data += components; {
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() U32* LLImageRaw::getBrightnessHistogram()
{ {
if (!mHistoBrightness) if (!mHistoBrightness)
......
...@@ -87,6 +87,13 @@ typedef enum e_image_codec ...@@ -87,6 +87,13 @@ typedef enum e_image_codec
IMG_CODEC_EOF = 8 IMG_CODEC_EOF = 8
} EImageCodec; } EImageCodec;
typedef enum e_vignette_mode
{
VIGNETTE_MODE_NONE = 0,
VIGNETTE_MODE_BLEND = 1,
VIGNETTE_MODE_FADE = 2
} EVignetteMode;
//============================================================================ //============================================================================
// library initialization class // library initialization class
...@@ -157,6 +164,13 @@ class LLImageBase : public LLThreadSafeRefCount ...@@ -157,6 +164,13 @@ class LLImageBase : public LLThreadSafeRefCount
U32 *mHistoBlue; U32 *mHistoBlue;
U32 *mHistoBrightness; U32 *mHistoBrightness;
// Vignette filtering
EVignetteMode mVignetteMode;
S32 mVignetteCenterX;
S32 mVignetteCenterY;
S32 mVignetteWidth;
F32 mVignetteGamma;
public: public:
static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
...@@ -278,6 +292,7 @@ class LLImageRaw : public LLImageBase ...@@ -278,6 +292,7 @@ class LLImageRaw : public LLImageBase
// Filter Primitives // Filter Primitives
void colorTransform(const LLMatrix3 &transform); void colorTransform(const LLMatrix3 &transform);
void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue); void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue);
void setVignette(EVignetteMode mode, F32 gamma);
U32* getBrightnessHistogram(); U32* getBrightnessHistogram();
protected: protected:
...@@ -292,6 +307,7 @@ class LLImageRaw : public LLImageBase ...@@ -292,6 +307,7 @@ class LLImageRaw : public LLImageBase
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
void computeHistograms(); void computeHistograms();
F32 getVignetteAlpha(S32 i, S32 j);
public: public:
static S32 sGlobalRawMemory; static S32 sGlobalRawMemory;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment