From 7372afaae4aa7097ffad1e9c070b8b9d9a611f62 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 20 Dec 2013 13:49:20 -0800 Subject: ACME-1236 : WIP : Implement colorTransform filter, grayscale and sepia using it, add parameter to llimage_libtest to use filters --- .../llimage_libtest/llimage_libtest.cpp | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 034c816742..e485136f58 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -83,6 +83,9 @@ static const char USAGE[] = "\n" " -rev, --reversible\n" " Set the compression to be lossless (reversible in j2c parlance).\n" " Only valid for output j2c images.\n" +" -f, --filter \n" +" Apply the filter to the input images.\n" +" Note: so far, only grayscale and sepia are supported.\n" " -log, --logmetrics \n" " Log performance data for . Results in .slp\n" " Note: so far, only ImageCompressionTester has been tested.\n" @@ -350,6 +353,7 @@ int main(int argc, char** argv) int blocks_size = -1; int levels = 0; bool reversible = false; + std::string filter_name = ""; // Init whatever is necessary ll_init_apr(); @@ -523,6 +527,26 @@ int main(int argc, char** argv) break; } } + else if (!strcmp(argv[arg], "--filter") || !strcmp(argv[arg], "-f")) + { + // '--filter' needs to be specified with a named filter argument + // Note: for the moment, only sepia and grayscale are supported + if ((arg + 1) < argc) + { + filter_name = argv[arg+1]; + } + if (((arg + 1) >= argc) || (filter_name[0] == '-')) + { + // We don't have an argument left in the arg list or the next argument is another option + std::cout << "No --filter argument given, no filter will be applied" << std::endl; + } + else + { + arg += 1; // Skip that arg now we know it's a valid test name + 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; @@ -568,6 +592,16 @@ int main(int argc, char** argv) std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl; continue; } + + // Apply filter if any + if (filter_name == "sepia") + { + raw_image->filterSepia(); + } + else if (filter_name == "grayscale") + { + raw_image->filterGrayScale(); + } // Save file if (out_file != out_end) -- cgit v1.3 From 08a798bb1d88708765041adf21a784911842f101 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 30 Dec 2013 20:33:33 -0800 Subject: ACME-1236 : WIP : Implement saturation/desaturation transform filter, add it to llimage_libtest for testing --- .../llimage_libtest/llimage_libtest.cpp | 4 +++ indra/llimage/llimage.cpp | 31 ++++++++++++++++++++++ indra/llimage/llimage.h | 1 + 3 files changed, 36 insertions(+) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index e485136f58..cbd6ccebbf 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -602,6 +602,10 @@ int main(int argc, char** argv) { raw_image->filterGrayScale(); } + else if (filter_name == "saturate") + { + raw_image->filterSaturate(2.0f); + } // Save file if (out_file != out_end) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 73e6f48a8d..4028514898 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -955,6 +955,37 @@ void LLImageRaw::filterSepia() colorTransform(sepia); } +void LLImageRaw::filterSaturate(F32 saturation) +{ + // Matrix to Lij + LLMatrix3 r_a; + LLMatrix3 r_b; + + // 45 degre rotation around z + r_a.setRows(LLVector3(0.7071, 0.7071, 0.0), + LLVector3(-0.7071, 0.7071, 0.0), + LLVector3(0.0, 0.0, 1.0)); + // 54.73 degre rotation around y + r_b.setRows(LLVector3(0.5773, 0.0, -0.8165), + LLVector3(0.0, 1.0, 0.0), + LLVector3(0.8165, 0.0, 0.5773)); + + // Coordinate conversion + LLMatrix3 Lij = r_b * r_a; + LLMatrix3 Lij_inv = Lij; + Lij_inv.transpose(); + + // Local saturation transform + LLMatrix3 s; + s.setRows(LLVector3(saturation, 0.0, 0.0), + LLVector3(0.0, saturation, 0.0), + LLVector3(0.0, 0.0, 1.0)); + + // Global saturation transform + LLMatrix3 transfo = Lij_inv * s * Lij; + colorTransform(transfo); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index d6b7e65c76..1742cf8a71 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -260,6 +260,7 @@ public: // Filter Operations void filterGrayScale(); void filterSepia(); + void filterSaturate(F32 s); // Filter Primitives void colorTransform(const LLMatrix3 &transform); -- cgit v1.3 From 218d305c443d4e5ddba03c6f4a988924939d805d Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 1 Jan 2014 17:13:06 -0800 Subject: ACME-1236 : WIP : add an optional filter parameter to llimage_libtest --- .../llimage_libtest/llimage_libtest.cpp | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index cbd6ccebbf..d1535bf3cf 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -83,9 +83,10 @@ static const char USAGE[] = "\n" " -rev, --reversible\n" " Set the compression to be lossless (reversible in j2c parlance).\n" " Only valid for output j2c images.\n" -" -f, --filter \n" -" Apply the filter to the input images.\n" -" Note: so far, only grayscale and sepia are supported.\n" +" -f, --filter []\n" +" Apply the filter to the input images using the optional param (float) value.\n" +" Notes: - 'grayscale' and 'sepia' are supported (no param).\n" +" - 'saturate' uses the param: param < 1.0 will desaturate the colors, param > 1.0 will saturate them.\n" " -log, --logmetrics \n" " Log performance data for . Results in .slp\n" " Note: so far, only ImageCompressionTester has been tested.\n" @@ -354,6 +355,7 @@ int main(int argc, char** argv) int levels = 0; bool reversible = false; std::string filter_name = ""; + double filter_param = 0.0; // Init whatever is necessary ll_init_apr(); @@ -530,7 +532,6 @@ int main(int argc, char** argv) else if (!strcmp(argv[arg], "--filter") || !strcmp(argv[arg], "-f")) { // '--filter' needs to be specified with a named filter argument - // Note: for the moment, only sepia and grayscale are supported if ((arg + 1) < argc) { filter_name = argv[arg+1]; @@ -545,7 +546,17 @@ int main(int argc, char** argv) arg += 1; // Skip that arg now we know it's a valid test name if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list break; - } + // --filter 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 filter parameter value + { + filter_param = atof(value_str.c_str()); + arg += 1; // Skip that arg now we used it as a valid filter 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")) { @@ -604,7 +615,7 @@ int main(int argc, char** argv) } else if (filter_name == "saturate") { - raw_image->filterSaturate(2.0f); + raw_image->filterSaturate((float)(filter_param)); } // Save file -- cgit v1.3 From 9dca514c0b416c1b15e9a63e6f5af1b52df70b7e Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 1 Jan 2014 17:58:52 -0800 Subject: ACME-1236 : WIP : add filterRotate to rotate hue, add rotate as a valid argument to --filter in llimage_libtest --- .../llimage_libtest/llimage_libtest.cpp | 11 +++-- indra/llimage/llimage.cpp | 48 +++++++++++++++++++--- indra/llimage/llimage.h | 3 +- 3 files changed, 52 insertions(+), 10 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index d1535bf3cf..1f9a5f0e18 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -84,9 +84,10 @@ 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 []\n" -" Apply the filter to the input images using the optional param (float) value.\n" -" Notes: - 'grayscale' and 'sepia' are supported (no param).\n" -" - 'saturate' uses the param: param < 1.0 will desaturate the colors, param > 1.0 will saturate them.\n" +" Apply the filter 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" " -log, --logmetrics \n" " Log performance data for . Results in .slp\n" " Note: so far, only ImageCompressionTester has been tested.\n" @@ -617,6 +618,10 @@ int main(int argc, char** argv) { raw_image->filterSaturate((float)(filter_param)); } + else if (filter_name == "rotate") + { + raw_image->filterRotate((float)(filter_param)); + } // Save file if (out_file != out_end) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 4028514898..8b7c352437 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -962,13 +962,15 @@ void LLImageRaw::filterSaturate(F32 saturation) LLMatrix3 r_b; // 45 degre rotation around z - r_a.setRows(LLVector3(0.7071, 0.7071, 0.0), - LLVector3(-0.7071, 0.7071, 0.0), - LLVector3(0.0, 0.0, 1.0)); + r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0), + LLVector3(-OO_SQRT2, OO_SQRT2, 0.0), + LLVector3( 0.0, 0.0, 1.0)); // 54.73 degre rotation around y - r_b.setRows(LLVector3(0.5773, 0.0, -0.8165), - LLVector3(0.0, 1.0, 0.0), - LLVector3(0.8165, 0.0, 0.5773)); + float oo_sqrt3 = 1.0f / F_SQRT3; + float sin_54 = F_SQRT2 * oo_sqrt3; + r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54), + LLVector3(0.0, 1.0, 0.0), + LLVector3(sin_54, 0.0, oo_sqrt3)); // Coordinate conversion LLMatrix3 Lij = r_b * r_a; @@ -986,6 +988,40 @@ void LLImageRaw::filterSaturate(F32 saturation) colorTransform(transfo); } +void LLImageRaw::filterRotate(F32 alpha) +{ + // Matrix to Lij + LLMatrix3 r_a; + LLMatrix3 r_b; + + // 45 degre rotation around z + r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0), + LLVector3(-OO_SQRT2, OO_SQRT2, 0.0), + LLVector3( 0.0, 0.0, 1.0)); + // 54.73 degre rotation around y + float oo_sqrt3 = 1.0f / F_SQRT3; + float sin_54 = F_SQRT2 * oo_sqrt3; + r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54), + LLVector3(0.0, 1.0, 0.0), + LLVector3(sin_54, 0.0, oo_sqrt3)); + + // Coordinate conversion + LLMatrix3 Lij = r_b * r_a; + LLMatrix3 Lij_inv = Lij; + Lij_inv.transpose(); + + // Local color rotation transform + LLMatrix3 r; + alpha *= DEG_TO_RAD; + r.setRows(LLVector3( cosf(alpha), sinf(alpha), 0.0), + LLVector3(-sinf(alpha), cosf(alpha), 0.0), + LLVector3( 0.0, 0.0, 1.0)); + + // Global color rotation transform + LLMatrix3 transfo = Lij_inv * r * Lij; + colorTransform(transfo); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 1742cf8a71..3a9c088dbd 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -260,7 +260,8 @@ public: // Filter Operations void filterGrayScale(); void filterSepia(); - void filterSaturate(F32 s); + void filterSaturate(F32 saturation); // < 1.0 desaturates, > 1.0 saturates + void filterRotate(F32 alpha); // rotates hue, alpha in degrees // Filter Primitives void colorTransform(const LLMatrix3 &transform); -- cgit v1.3 From 205a4e3dc63c338c05e27a4806cdfd6f50bac2b6 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 1 Jan 2014 19:42:10 -0800 Subject: ACME-1236 : WIP : add filterGamma, computeHistograms, colorCorrect, implemented filter gamma to llimage_libtest for testing --- .../llimage_libtest/llimage_libtest.cpp | 4 + indra/llimage/llimage.cpp | 92 +++++++++++++++++++++- indra/llimage/llimage.h | 11 +++ 3 files changed, 103 insertions(+), 4 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 1f9a5f0e18..afd5e2ce98 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -622,6 +622,10 @@ int main(int argc, char** argv) { raw_image->filterRotate((float)(filter_param)); } + else if (filter_name == "gamma") + { + raw_image->filterGamma((float)(filter_param)); + } // Save file if (out_file != out_end) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 8b7c352437..d406995f3a 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -97,7 +97,11 @@ LLImageBase::LLImageBase() mHeight(0), mComponents(0), mBadBufferAllocation(false), - mAllowOverSize(false) + mAllowOverSize(false), + mHistoRed(NULL), + mHistoGreen(NULL), + mHistoBlue(NULL), + mHistoBrightness(NULL) { } @@ -105,10 +109,14 @@ LLImageBase::LLImageBase() LLImageBase::~LLImageBase() { deleteData(); // virtual + ll_aligned_free_16(mHistoRed); + ll_aligned_free_16(mHistoGreen); + ll_aligned_free_16(mHistoBlue); + ll_aligned_free_16(mHistoBrightness); } -//static -void LLImageBase::createPrivatePool() +//static +void LLImageBase::createPrivatePool() { if(!sPrivatePoolp) { @@ -1022,6 +1030,18 @@ 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); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { @@ -1030,7 +1050,7 @@ void LLImageRaw::colorTransform(const LLMatrix3 &transform) S32 pixels = getWidth() * getHeight(); U8* dst_data = getData(); - for( S32 i=0; i= 1 && components <= 4 ); + + S32 pixels = getWidth() * getHeight(); + U8* dst_data = getData(); + for (S32 i = 0; i < pixels; i++) + { + 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; + } +} + +void LLImageRaw::computeHistograms() +{ + const S32 components = getComponents(); + llassert( components >= 1 && components <= 4 ); + + // Allocate memory for the histograms + if (!mHistoRed) + { + mHistoRed = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + if (!mHistoGreen) + { + mHistoGreen = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + if (!mHistoBlue) + { + mHistoBlue = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + if (!mHistoBrightness) + { + mHistoBrightness = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + + // Initialize them + for (S32 i = 0; i < 256; i++) + { + mHistoRed[i] = 0; + mHistoGreen[i] = 0; + mHistoBlue[i] = 0; + mHistoBrightness[i] = 0; + } + + // Compute them + S32 pixels = getWidth() * getHeight(); + U8* dst_data = getData(); + for (S32 i = 0; i < pixels; i++) + { + mHistoRed[dst_data[VRED]]++; + mHistoGreen[dst_data[VGREEN]]++; + mHistoBlue[dst_data[VBLUE]]++; + // Note: this is a very simple shorthand for brightness but it's OK for our use + S32 brightness = ((S32)(dst_data[VRED]) + (S32)(dst_data[VGREEN]) + (S32)(dst_data[VBLUE])) / 3; + mHistoBrightness[brightness]++; + // next pixel... + dst_data += components; + } +} + void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) { const S32 components = getComponents(); diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 3a9c088dbd..89734693cc 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -151,6 +151,12 @@ protected: // special accessor to allow direct setting of mData and mDataSize by LLImageFormatted void setDataAndSize(U8 *data, S32 size); + // Histograms (if we ever happen to need them) + U32 *mHistoRed; + U32 *mHistoGreen; + U32 *mHistoBlue; + U32 *mHistoBrightness; + public: static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); @@ -262,8 +268,11 @@ public: 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 + // Filter Primitives void colorTransform(const LLMatrix3 &transform); + void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue); protected: // Create an image from a local file (generally used in tools) @@ -276,6 +285,8 @@ protected: void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; + void computeHistograms(); + public: static S32 sGlobalRawMemory; static S32 sRawImageCount; -- cgit v1.3 From d28b92744ee0d4a19a5587585998e5c351f6d300 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 2 Jan 2014 16:14:38 -0800 Subject: ACME-1236 : WIP : added all the color correction filters: colorize, linarize, equalize, contrast, brightness --- .../llimage_libtest/CMakeLists.txt | 3 + .../llimage_libtest/llimage_libtest.cpp | 44 +++++- indra/llimage/llimage.cpp | 155 +++++++++++++++++++++ indra/llimage/llimage.h | 16 ++- 4 files changed, 209 insertions(+), 9 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') 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 @@ -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 []\n" -" Apply the filter 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 to the input images using the optional value. Admissible names:\n" +" - 'grayscale' converts to grayscale (no param).\n" +" - 'sepia' converts to sepia (no param).\n" +" - 'saturate' changes color saturation according to : < 1.0 will desaturate, > 1.0 will saturate.\n" +" - 'rotate' rotates the color hue according to (in degree, positive value only).\n" +" - 'gamma' applies gamma curve to all channels: > 1.0 will darken, < 1.0 will lighten.\n" +" - 'colorize' applies a red tint to the image using as an alpha (transparency between 0.0 and 1.0) value.\n" +" - 'contrast' modifies the contrast according to : > 1.0 will enhance the contrast, <1.0 will flatten it.\n" +" - 'brighten' adds light to the image ( between 0 and 255).\n" +" - 'darken' substracts light to the image ( between 0 and 255).\n" +" - 'linearize' optimizes the contrast using the brightness histogram. is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" +" - 'posterize' redistributes the colors between classes per channel ( between 2 and 255).\n" " -log, --logmetrics \n" " Log performance data for . Results in .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) -- cgit v1.3 From 1b5fb662927ac84606cf767c8c9ec350e82b656f Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 3 Jan 2014 14:19:29 -0800 Subject: ACME-1236 : WIP : Added the vignette mode. Can be applied to colorCorrect and color Transform. Added new -v argument to llimage_libtest --- .../llimage_libtest/llimage_libtest.cpp | 47 ++++++++- indra/llimage/llimage.cpp | 106 +++++++++++++++++---- indra/llimage/llimage.h | 16 ++++ 3 files changed, 152 insertions(+), 17 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 4d32282a0d..45e60f64e6 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -97,6 +97,10 @@ static const char USAGE[] = "\n" " - 'darken' substracts light to the image ( between 0 and 255).\n" " - 'linearize' optimizes the contrast using the brightness histogram. is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" " - 'posterize' redistributes the colors between classes per channel ( between 2 and 255).\n" +" -v, --vignette []\n" +" Apply a circular central vignette to the filter using the optional 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 \n" " Log performance data for . Results in .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") { diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 5dc9c24f6c..da22ed5e5b 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -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) diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index b62deadee0..b9f6a12bdd 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -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; -- cgit v1.3 From 35e30759c82e0fa425e2ee5ba235868a25b44169 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 3 Jan 2014 15:44:29 -0800 Subject: ACME-1236 : WIP : Added a min value to vignette --- .../llimage_libtest/llimage_libtest.cpp | 23 +++++++++++++++------- indra/llimage/llimage.cpp | 12 +++++++---- indra/llimage/llimage.h | 3 ++- 3 files changed, 26 insertions(+), 12 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 45e60f64e6..6c23a6a866 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -97,8 +97,8 @@ static const char USAGE[] = "\n" " - 'darken' substracts light to the image ( between 0 and 255).\n" " - 'linearize' optimizes the contrast using the brightness histogram. is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" " - 'posterize' redistributes the colors between classes per channel ( between 2 and 255).\n" -" -v, --vignette []\n" -" Apply a circular central vignette to the filter using the optional value. Admissible names:\n" +" -v, --vignette [ ]\n" +" Apply a circular central vignette to the filter using the optional and values. 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 \n" @@ -371,7 +371,8 @@ int main(int argc, char** argv) std::string filter_name = ""; double filter_param = 0.0; std::string vignette_name = ""; - double vignette_param = 1.0; + double vignette_param_1 = 1.0; + double vignette_param_2 = 0.0; // Init whatever is necessary ll_init_apr(); @@ -591,15 +592,23 @@ int main(int argc, char** argv) 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 + // --vignette can also have optional parameters 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()); + vignette_param_1 = 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; + 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_2 = 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; + } } } } @@ -652,11 +661,11 @@ int main(int argc, char** argv) // Set the vignette if any if (vignette_name == "blend") { - raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(vignette_param)); + raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(vignette_param_1),(float)(vignette_param_2)); } else if (vignette_name == "fade") { - raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(vignette_param)); + raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(vignette_param_1),(float)(vignette_param_2)); } // Apply filter if any diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index da22ed5e5b..d84989f9c8 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -103,7 +103,8 @@ LLImageBase::LLImageBase() mHistoBlue(NULL), mHistoBrightness(NULL), mVignetteMode(VIGNETTE_MODE_NONE), - mVignetteGamma(1.0) + mVignetteGamma(1.0), + mVignetteMin(0.0) { } @@ -1280,10 +1281,11 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } -void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma) +void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) { mVignetteMode = mode; mVignetteGamma = gamma; + mVignetteMin = llclampf(min); // We always center the vignette on the image and fits it in the image smallest dimension mVignetteCenterX = getWidth()/2; mVignetteCenterY = getHeight()/2; @@ -1293,9 +1295,11 @@ void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma) 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 + // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) 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)); + F32 alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); + // We rescale alpha between min and 1.0 so to avoid complete fading if so desired. + return (mVignetteMin + alpha * (1.0 - mVignetteMin)); } U32* LLImageRaw::getBrightnessHistogram() diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index b9f6a12bdd..404f1c0769 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -170,6 +170,7 @@ protected: S32 mVignetteCenterY; S32 mVignetteWidth; F32 mVignetteGamma; + F32 mVignetteMin; public: static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); @@ -292,7 +293,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); + void setVignette(EVignetteMode mode, F32 gamma, F32 min); U32* getBrightnessHistogram(); protected: -- cgit v1.3 From 90cbda6db0d075dccc2369a68b02919b40f53cca Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 3 Jan 2014 17:31:04 -0800 Subject: ACME-1236 : WIP : Add 2 new color correction filters. Add a la Instagram composite filters for testing in llimage_libtest --- .../llimage_libtest/llimage_libtest.cpp | 40 +++++++++++++++++++++- indra/llimage/llimage.cpp | 33 ++++++++++++++++++ indra/llimage/llimage.h | 4 ++- 3 files changed, 75 insertions(+), 2 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 6c23a6a866..58d7f53dd1 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -716,7 +716,45 @@ int main(int argc, char** argv) { raw_image->filterEqualize((S32)(filter_param)); } - + // 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(); + } + else if (filter_name == "Poprocket") + { + LLColor4U color = LLColor4U::red; + color.setAlpha((U8)(0.2 * 255.0)); + raw_image->filterLinearize(0.0); + raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5); + raw_image->filterColorize(color); + } + else if (filter_name == "Gotham") + { + raw_image->filterLinearize(0.0); + raw_image->filterColorBalance(1.0,1.0,20.0); + raw_image->filterGrayScale(); + } + else if (filter_name == "Toaster") + { + raw_image->filterContrast(0.8); + raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5); + raw_image->filterBrightness(10); + raw_image->filterColorBalance(0.5,1.0,1.0); + } + // Save file if (out_file != out_end) { diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index d84989f9c8..3d86abb26d 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1045,6 +1045,22 @@ void LLImageRaw::filterGamma(F32 gamma) colorCorrect(gamma_lut,gamma_lut,gamma_lut); } +void LLImageRaw::filterColorBalance(F32 gamma_red, F32 gamma_green, F32 gamma_blue) +{ + U8 gamma_red_lut[256]; + U8 gamma_green_lut[256]; + U8 gamma_blue_lut[256]; + + 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))))); + } + + colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut); +} + void LLImageRaw::filterLinearize(F32 tail) { // Get the histogram @@ -1191,6 +1207,23 @@ void LLImageRaw::filterBrightness(S32 add) 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); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 404f1c0769..6e58453da5 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -289,7 +289,9 @@ public: 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 + // Filter Primitives void colorTransform(const LLMatrix3 &transform); void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue); -- cgit v1.3 From 3cbd0dfd849a94a789ae70f4bdc176f85cf2ba34 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 6 Jan 2014 14:46:52 -0800 Subject: ACME-1236 : WIP : Make each color correct filter use a per channel alpha argument, tweak Instagram-like test filters for discussion --- .../llimage_libtest/llimage_libtest.cpp | 66 +++++++----- indra/llimage/llimage.cpp | 118 ++++++++++----------- indra/llimage/llimage.h | 24 +++-- 3 files changed, 111 insertions(+), 97 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 58d7f53dd1..6045ed321d 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -687,73 +687,85 @@ 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); + raw_image->filterLinearize(0.2,LLColor3::white); + raw_image->filterBrightness(20,LLColor3::white); + } + else if (filter_name == "Poprocket") + { + 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,alpha); } else if (filter_name == "Sutro") { - raw_image->filterLinearize(0.2); + 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,LLColor3::white); + raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5); + 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); + raw_image->filterLinearize(0.0,LLColor3::white); raw_image->filterGrayScale(); } - else if (filter_name == "Poprocket") + else if (filter_name == "Hefe") { - LLColor4U color = LLColor4U::red; - color.setAlpha((U8)(0.2 * 255.0)); - raw_image->filterLinearize(0.0); + raw_image->filterLinearize(0.0,LLColor3::white); raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5); - raw_image->filterColorize(color); + raw_image->filterContrast(1.5,LLColor3::white); } else if (filter_name == "Gotham") { - raw_image->filterLinearize(0.0); - raw_image->filterColorBalance(1.0,1.0,20.0); + 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(); } - else if (filter_name == "Toaster") - { - raw_image->filterContrast(0.8); - raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5); - raw_image->filterBrightness(10); - raw_image->filterColorBalance(0.5,1.0,1.0); - } // Save file if (out_file != out_end) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 3d86abb26d..977bb09b63 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -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]; - - for (S32 i = 0; i < 256; i++) - { - brightness_lut[i] = (U8)(llclampb((S32)((S32)(i) + add))); - } - - 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; + U8 brightness_red_lut[256]; + U8 brightness_green_lut[256]; + U8 brightness_blue_lut[256]; for (S32 i = 0; i < 256; i++) { - contrast_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + 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(contrast_lut,contrast_lut,contrast_lut); + colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut); } // Filter Primitives diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 6e58453da5..cc91f95624 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -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); -- cgit v1.3 From 5187e709c923429554ab89600a0b27cb9cedd567 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 7 Jan 2014 16:17:25 -0800 Subject: ACME-1236 : WIP : Add filter file loading and execution to llimage_libtest, suppress the a la Instagram tests as a result --- .../llimage_libtest/llimage_libtest.cpp | 156 ++++++++++++++------- 1 file changed, 107 insertions(+), 49 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 6045ed321d..009be0941e 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -40,6 +40,7 @@ #include "lldir.h" #include "lldiriterator.h" #include "v4coloru.h" +#include "llsdserialize.h" // system libraries #include @@ -97,6 +98,7 @@ static const char USAGE[] = "\n" " - 'darken' substracts light to the image ( between 0 and 255).\n" " - 'linearize' optimizes the contrast using the brightness histogram. is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" " - 'posterize' redistributes the colors between classes per channel ( between 2 and 255).\n" +" - Any other value will be interpreted as a file name describing a sequence of filters and parameters to be applied to the input images\n" " -v, --vignette [ ]\n" " Apply a circular central vignette to the filter using the optional and values. Admissible names:\n" " - 'blend' : the filter is applied with full intensity in the center and blends with the image to the periphery.\n" @@ -114,10 +116,110 @@ static const char USAGE[] = "\n" // true when all image loading is done. Used by metric logging thread to know when to stop the thread. static bool sAllDone = false; +// Load filter from file +LLSD load_filter_from_file(const std::string& file_path) +{ + std::cout << "Loading filter settings from : " << file_path << std::endl; + + llifstream filter_xml(file_path); + if (filter_xml.is_open()) + { + // load and parse it + LLSD filter_data(LLSD::emptyArray()); + LLPointer parser = new LLSDXMLParser(); + parser->parse(filter_xml, filter_data, LLSDSerialize::SIZE_UNLIMITED); + filter_xml.close(); + return filter_data; + } + else + { + return LLSD(); + } +} + +// Apply the filter data to the image passed as parameter +void execute_filter(const LLSD& filter_data, LLPointer raw_image) +{ + //std::cout << "Filter : size = " << filter_data.size() << std::endl; + for (S32 i = 0; i < filter_data.size(); ++i) + { + std::string filter_name = filter_data[i][0].asString(); + // Dump out the filter values (for debug) + //std::cout << "Filter : name = " << filter_data[i][0].asString() << ", params = "; + //for (S32 j = 1; j < filter_data[i].size(); ++j) + //{ + // std::cout << filter_data[i][j].asString() << ", "; + //} + //std::cout << std::endl; + + // Execute the filter described on this line + if (filter_name == "blend") + { + raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); + } + else if (filter_name == "fade") + { + raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); + } + else if (filter_name == "sepia") + { + raw_image->filterSepia(); + } + else if (filter_name == "grayscale") + { + raw_image->filterGrayScale(); + } + else if (filter_name == "saturate") + { + raw_image->filterSaturate((float)(filter_data[i][1].asReal())); + } + else if (filter_name == "rotate") + { + raw_image->filterRotate((float)(filter_data[i][1].asReal())); + } + else if (filter_name == "gamma") + { + LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); + raw_image->filterGamma((float)(filter_data[i][1].asReal()),color); + } + else if (filter_name == "colorize") + { + LLColor3 color((float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal())); + LLColor3 alpha((F32)(filter_data[i][4].asReal()),(float)(filter_data[i][5].asReal()),(float)(filter_data[i][6].asReal())); + raw_image->filterColorize(color,alpha); + } + else if (filter_name == "contrast") + { + LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); + raw_image->filterContrast((float)(filter_data[i][1].asReal()),color); + } + else if (filter_name == "brighten") + { + LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); + raw_image->filterBrightness((S32)(filter_data[i][1].asReal()),color); + } + else if (filter_name == "darken") + { + LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); + raw_image->filterBrightness((S32)(-filter_data[i][1].asReal()),color); + } + else if (filter_name == "linearize") + { + LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); + raw_image->filterLinearize((float)(filter_data[i][1].asReal()),color); + } + else if (filter_name == "posterize") + { + LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); + raw_image->filterEqualize((S32)(filter_data[i][1].asReal()),color); + } + } +} + // Create an empty formatted image instance of the correct type from the filename LLPointer create_image(const std::string &filename) { - std::string exten = gDirUtilp->getExtension(filename); + std::string exten = gDirUtilp->getExtension(filename); LLPointer image = LLImageFormatted::createFromExtension(exten); return image; } @@ -716,55 +818,11 @@ int main(int argc, char** argv) { raw_image->filterEqualize((S32)(filter_param),LLColor3::white); } - // Test for some "a la Instagram" filters - else if (filter_name == "Lomofi") + else if (filter_name != "") { - raw_image->setVignette(VIGNETTE_MODE_BLEND,4.0,0.0); - raw_image->filterLinearize(0.2,LLColor3::white); - raw_image->filterBrightness(20,LLColor3::white); - } - else if (filter_name == "Poprocket") - { - 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,alpha); - } - else if (filter_name == "Sutro") - { - 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,LLColor3::white); - raw_image->setVignette(VIGNETTE_MODE_FADE,4.0,0.5); - 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(); + // We're interpreting the filter as a filter file name + LLSD filter_data = load_filter_from_file(filter_name); + execute_filter(filter_data,raw_image); } // Save file -- cgit v1.3 From c2a974f1556906f6ca69afb5942378c8dbf85169 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 7 Jan 2014 22:10:23 -0800 Subject: ACME-1236 : WIP : Introduced screenFilter, simple creative screening filter --- .../llimage_libtest/llimage_libtest.cpp | 11 +++++- indra/llimage/llimage.cpp | 46 ++++++++++++++++++++++ indra/llimage/llimage.h | 1 + 3 files changed, 56 insertions(+), 2 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 009be0941e..69cea33911 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -119,8 +119,7 @@ static bool sAllDone = false; // Load filter from file LLSD load_filter_from_file(const std::string& file_path) { - std::cout << "Loading filter settings from : " << file_path << std::endl; - + //std::cout << "Loading filter settings from : " << file_path << std::endl; llifstream filter_xml(file_path); if (filter_xml.is_open()) { @@ -213,6 +212,10 @@ void execute_filter(const LLSD& filter_data, LLPointer raw_image) LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); raw_image->filterEqualize((S32)(filter_data[i][1].asReal()),color); } + else if (filter_name == "screen") + { + raw_image->screenFilter((S32)(filter_data[i][1].asReal())); + } } } @@ -818,6 +821,10 @@ int main(int argc, char** argv) { raw_image->filterEqualize((S32)(filter_param),LLColor3::white); } + else if (filter_name == "screen") + { + raw_image->screenFilter((S32)(filter_param)); + } else if (filter_name != "") { // We're interpreting the filter as a filter file name diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 977bb09b63..ae3de32788 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1312,6 +1312,52 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } +void LLImageRaw::screenFilter(const S32 wave_length) +{ + const S32 components = getComponents(); + llassert( components >= 1 && components <= 4 ); + + S32 width = getWidth(); + S32 height = getHeight(); + + U8* dst_data = getData(); + for (S32 j = 0; j < height; j++) + { + for (S32 i = 0; i < width; i++) + { + F32 value = (sinf(2*F_PI*i/wave_length)*sinf(2*F_PI*j/wave_length)+1.0)*255.0/2.0; + //F32 value = (sinf(2*F_PI*i/wave_length)+1.0)*255.0/2.0; // will do line + U8 dst_value = (dst_data[VRED] >= (U8)(value) ? 255 : 0); + if (mVignetteMode == VIGNETTE_MODE_NONE) + { + dst_data[VRED] = dst_value; + dst_data[VGREEN] = dst_value; + dst_data[VBLUE] = dst_value; + } + 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 * dst_value; + dst_data[VGREEN] = inv_alpha * dst_data[VGREEN] + alpha * dst_value; + dst_data[VBLUE] = inv_alpha * dst_data[VBLUE] + alpha * dst_value; + } + else // VIGNETTE_MODE_FADE + { + // Fade to black on the edges + dst_data[VRED] = alpha * dst_value; + dst_data[VGREEN] = alpha * dst_value; + dst_data[VBLUE] = alpha * dst_value; + } + } + dst_data += components; + } + } +} + void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) { mVignetteMode = mode; diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index cc91f95624..ed17f1af21 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -299,6 +299,7 @@ public: // Filter Primitives void colorTransform(const LLMatrix3 &transform); void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue); + void screenFilter(const S32 wave_length); void setVignette(EVignetteMode mode, F32 gamma, F32 min); U32* getBrightnessHistogram(); -- cgit v1.3 From 3161d822ab1336a347f1bb34574b5c4b8e747799 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 8 Jan 2014 15:41:42 -0800 Subject: ACME-1236 : WIP : Added mode and angle parameter to filterScreen (renamed for consistency) --- .../llimage_libtest/llimage_libtest.cpp | 34 +++++++++++++++++++--- indra/llimage/llimage.cpp | 28 +++++++++++++----- indra/llimage/llimage.h | 10 +++++-- 3 files changed, 59 insertions(+), 13 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 69cea33911..90a7c09442 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -98,7 +98,11 @@ static const char USAGE[] = "\n" " - 'darken' substracts light to the image ( between 0 and 255).\n" " - 'linearize' optimizes the contrast using the brightness histogram. is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" " - 'posterize' redistributes the colors between classes per channel ( between 2 and 255).\n" -" - Any other value will be interpreted as a file name describing a sequence of filters and parameters to be applied to the input images\n" +" - 'newsscreen' applies a 2D sine screening to the red channel and output to black and white.\n" +" - 'horizontalscreen' applies a horizontal screening to the red channel and output to black and white.\n" +" - 'verticalscreen' applies a vertical screening to the red channel and output to black and white.\n" +" - 'slantedscreen' applies a 45 degrees slanted screening to the red channel and output to black and white.\n" +" - Any other value will be interpreted as a file name describing a sequence of filters and parameters to be applied to the input images.\n" " -v, --vignette [ ]\n" " Apply a circular central vignette to the filter using the optional and values. Admissible names:\n" " - 'blend' : the filter is applied with full intensity in the center and blends with the image to the periphery.\n" @@ -214,7 +218,17 @@ void execute_filter(const LLSD& filter_data, LLPointer raw_image) } else if (filter_name == "screen") { - raw_image->screenFilter((S32)(filter_data[i][1].asReal())); + std::string screen_name = filter_data[i][1].asString(); + EScreenMode mode = SCREEN_MODE_2DSINE; + if (screen_name == "2Dsine") + { + mode = SCREEN_MODE_2DSINE; + } + else if (screen_name == "line") + { + mode = SCREEN_MODE_LINE; + } + raw_image->filterScreen(mode,(S32)(filter_data[i][2].asReal()),(F32)(filter_data[i][3].asReal())); } } } @@ -821,9 +835,21 @@ int main(int argc, char** argv) { raw_image->filterEqualize((S32)(filter_param),LLColor3::white); } - else if (filter_name == "screen") + else if (filter_name == "newsscreen") + { + raw_image->filterScreen(SCREEN_MODE_2DSINE,(S32)(filter_param),0.0); + } + else if (filter_name == "horizontalscreen") + { + raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),0.0); + } + else if (filter_name == "verticalscreen") + { + raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),90.0); + } + else if (filter_name == "slantedscreen") { - raw_image->screenFilter((S32)(filter_param)); + raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),45.0); } else if (filter_name != "") { diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index ae3de32788..a30646d846 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1000,7 +1000,7 @@ void LLImageRaw::filterSaturate(F32 saturation) colorTransform(transfo); } -void LLImageRaw::filterRotate(F32 alpha) +void LLImageRaw::filterRotate(F32 angle) { // Matrix to Lij LLMatrix3 r_a; @@ -1024,9 +1024,9 @@ void LLImageRaw::filterRotate(F32 alpha) // Local color rotation transform LLMatrix3 r; - alpha *= DEG_TO_RAD; - r.setRows(LLVector3( cosf(alpha), sinf(alpha), 0.0), - LLVector3(-sinf(alpha), cosf(alpha), 0.0), + angle *= DEG_TO_RAD; + r.setRows(LLVector3( cosf(angle), sinf(angle), 0.0), + LLVector3(-sinf(angle), cosf(angle), 0.0), LLVector3( 0.0, 0.0, 1.0)); // Global color rotation transform @@ -1312,7 +1312,7 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } -void LLImageRaw::screenFilter(const S32 wave_length) +void LLImageRaw::filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle) { const S32 components = getComponents(); llassert( components >= 1 && components <= 4 ); @@ -1320,14 +1320,28 @@ void LLImageRaw::screenFilter(const S32 wave_length) S32 width = getWidth(); S32 height = getHeight(); + F32 sin = sinf(angle*DEG_TO_RAD); + F32 cos = cosf(angle*DEG_TO_RAD); + U8* dst_data = getData(); for (S32 j = 0; j < height; j++) { for (S32 i = 0; i < width; i++) { - F32 value = (sinf(2*F_PI*i/wave_length)*sinf(2*F_PI*j/wave_length)+1.0)*255.0/2.0; - //F32 value = (sinf(2*F_PI*i/wave_length)+1.0)*255.0/2.0; // will do line + F32 value = 0.0; + F32 d = 0.0; + switch (mode) + { + case SCREEN_MODE_2DSINE: + value = (sinf(2*F_PI*i/wave_length)*sinf(2*F_PI*j/wave_length)+1.0)*255.0/2.0; + break; + case SCREEN_MODE_LINE: + d = sin*i - cos*j; + value = (sinf(2*F_PI*d/wave_length)+1.0)*255.0/2.0; + break; + } U8 dst_value = (dst_data[VRED] >= (U8)(value) ? 255 : 0); + if (mVignetteMode == VIGNETTE_MODE_NONE) { dst_data[VRED] = dst_value; diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index ed17f1af21..f2bb91a329 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -95,6 +95,12 @@ typedef enum e_vignette_mode VIGNETTE_MODE_FADE = 2 } EVignetteMode; +typedef enum e_screen_mode +{ + SCREEN_MODE_2DSINE = 0, + SCREEN_MODE_LINE = 1 +} EScreenMode; + //============================================================================ // library initialization class @@ -283,7 +289,7 @@ public: 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 is an angle in degrees + void filterRotate(F32 angle); // Rotates hue according to angle, angle in degrees // Filter Operations : Color Corrections // When specified, the LLColor3 alpha parameter indicates the intensity of the effect for each color channel @@ -299,7 +305,7 @@ public: // Filter Primitives void colorTransform(const LLMatrix3 &transform); void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue); - void screenFilter(const S32 wave_length); + void filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle); void setVignette(EVignetteMode mode, F32 gamma, F32 min); U32* getBrightnessHistogram(); -- cgit v1.3 From 0c7cab771cb7972ed44eedf0c16133ef082eb9e1 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 9 Jan 2014 21:58:30 -0800 Subject: ACME-1236 : Add lines as a new type of vignette and Brightscan as an example --- .../llimage_libtest/llimage_libtest.cpp | 12 +++++++---- indra/llimage/llimage.cpp | 21 +++++++++++++++----- indra/llimage/llimage.h | 9 ++++++++- indra/newview/app_settings/filters/Brightscan.xml | 23 ++++++++++++++++++++++ 4 files changed, 55 insertions(+), 10 deletions(-) create mode 100755 indra/newview/app_settings/filters/Brightscan.xml (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 90a7c09442..2447e00028 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -158,11 +158,15 @@ void execute_filter(const LLSD& filter_data, LLPointer raw_image) // Execute the filter described on this line if (filter_name == "blend") { - raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); + raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); } else if (filter_name == "fade") { - raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); + raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); + } + else if (filter_name == "lines") + { + raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_LINES,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); } else if (filter_name == "sepia") { @@ -780,11 +784,11 @@ int main(int argc, char** argv) // Set the vignette if any if (vignette_name == "blend") { - raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(vignette_param_1),(float)(vignette_param_2)); + raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2)); } else if (vignette_name == "fade") { - raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(vignette_param_1),(float)(vignette_param_2)); + raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2)); } // Apply filter if any diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 14fa71d828..3105fe3746 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1372,9 +1372,10 @@ void LLImageRaw::filterScreen(EScreenMode mode, const S32 wave_length, const F32 } } -void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) +void LLImageRaw::setVignette(EVignetteMode mode, EVignetteType type, F32 gamma, F32 min) { mVignetteMode = mode; + mVignetteType = type; mVignetteGamma = gamma; mVignetteMin = llclampf(min); // We always center the vignette on the image and fits it in the image smallest dimension @@ -1385,10 +1386,20 @@ void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) 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 (center) to 0.0 - F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY); - F32 alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); + F32 alpha = 1.0; + if (mVignetteType == VIGNETTE_TYPE_CENTER) + { + // 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 (center) to 0.0 + F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY); + alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); + } + else if (mVignetteType == VIGNETTE_TYPE_LINES) + { + // alpha varies according to a squared sine function vertically. + // gamma is interpreted as the wavelength (in pixels) of the sine in that case. + alpha = (sinf(2*F_PI*j/mVignetteGamma) > 0.0 ? 1.0 : 0.0); + } // We rescale alpha between min and 1.0 so to avoid complete fading if so desired. return (mVignetteMin + alpha * (1.0 - mVignetteMin)); } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index f2bb91a329..a600f2e4a6 100755 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -95,6 +95,12 @@ typedef enum e_vignette_mode VIGNETTE_MODE_FADE = 2 } EVignetteMode; +typedef enum e_vignette_type +{ + VIGNETTE_TYPE_CENTER = 0, + VIGNETTE_TYPE_LINES = 1 +} EVignetteType; + typedef enum e_screen_mode { SCREEN_MODE_2DSINE = 0, @@ -173,6 +179,7 @@ protected: // Vignette filtering EVignetteMode mVignetteMode; + EVignetteType mVignetteType; S32 mVignetteCenterX; S32 mVignetteCenterY; S32 mVignetteWidth; @@ -306,7 +313,7 @@ public: void colorTransform(const LLMatrix3 &transform); void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue); void filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle); - void setVignette(EVignetteMode mode, F32 gamma, F32 min); + void setVignette(EVignetteMode mode, EVignetteType type, F32 gamma, F32 min); U32* getBrightnessHistogram(); protected: diff --git a/indra/newview/app_settings/filters/Brightscan.xml b/indra/newview/app_settings/filters/Brightscan.xml new file mode 100755 index 0000000000..8b10687ef5 --- /dev/null +++ b/indra/newview/app_settings/filters/Brightscan.xml @@ -0,0 +1,23 @@ + + + + linearize + 0.01 + 1.0 + 1.0 + 1.0 + + + lines + 10.0 + 0.0 + + + brighten + 100.0 + 1.0 + 1.0 + 1.0 + + + -- cgit v1.3 From 54ad7de61b5be2014c2e061a4964b7d6620a5dd4 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 13 Jan 2014 17:01:44 -0800 Subject: ACME-1244 : Introduced llimage/llimagefilter, refactored the filter execution code, simplified llimage_libtest filter testing --- .../llimage_libtest/llimage_libtest.cpp | 274 +-------------------- indra/llimage/CMakeLists.txt | 2 + indra/llimage/llimagefilter.cpp | 269 ++++++++++++++++++++ indra/llimage/llimagefilter.h | 73 ++++++ 4 files changed, 351 insertions(+), 267 deletions(-) create mode 100755 indra/llimage/llimagefilter.cpp create mode 100755 indra/llimage/llimagefilter.h (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 2447e00028..d3373a61f2 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -32,6 +32,7 @@ // Linden library includes #include "llimage.h" +#include "llimagefilter.h" #include "llimagejpeg.h" #include "llimagepng.h" #include "llimagebmp.h" @@ -85,28 +86,8 @@ static const char USAGE[] = "\n" " -rev, --reversible\n" " Set the compression to be lossless (reversible in j2c parlance).\n" " Only valid for output j2c images.\n" -" -f, --filter []\n" -" Apply the filter to the input images using the optional value. Admissible names:\n" -" - 'grayscale' converts to grayscale (no param).\n" -" - 'sepia' converts to sepia (no param).\n" -" - 'saturate' changes color saturation according to : < 1.0 will desaturate, > 1.0 will saturate.\n" -" - 'rotate' rotates the color hue according to (in degree, positive value only).\n" -" - 'gamma' applies gamma curve to all channels: > 1.0 will darken, < 1.0 will lighten.\n" -" - 'colorize' applies a red tint to the image using as an alpha (transparency between 0.0 and 1.0) value.\n" -" - 'contrast' modifies the contrast according to : > 1.0 will enhance the contrast, <1.0 will flatten it.\n" -" - 'brighten' adds light to the image ( between 0 and 255).\n" -" - 'darken' substracts light to the image ( between 0 and 255).\n" -" - 'linearize' optimizes the contrast using the brightness histogram. is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" -" - 'posterize' redistributes the colors between classes per channel ( between 2 and 255).\n" -" - 'newsscreen' applies a 2D sine screening to the red channel and output to black and white.\n" -" - 'horizontalscreen' applies a horizontal screening to the red channel and output to black and white.\n" -" - 'verticalscreen' applies a vertical screening to the red channel and output to black and white.\n" -" - 'slantedscreen' applies a 45 degrees slanted screening to the red channel and output to black and white.\n" -" - Any other value will be interpreted as a file name describing a sequence of filters and parameters to be applied to the input images.\n" -" -v, --vignette [ ]\n" -" Apply a circular central vignette to the filter using the optional and values. 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" +" -f, --filter \n" +" Apply the filter to the input images.\n" " -log, --logmetrics \n" " Log performance data for . Results in .slp\n" " Note: so far, only ImageCompressionTester has been tested.\n" @@ -120,123 +101,6 @@ static const char USAGE[] = "\n" // true when all image loading is done. Used by metric logging thread to know when to stop the thread. static bool sAllDone = false; -// Load filter from file -LLSD load_filter_from_file(const std::string& file_path) -{ - //std::cout << "Loading filter settings from : " << file_path << std::endl; - llifstream filter_xml(file_path); - if (filter_xml.is_open()) - { - // load and parse it - LLSD filter_data(LLSD::emptyArray()); - LLPointer parser = new LLSDXMLParser(); - parser->parse(filter_xml, filter_data, LLSDSerialize::SIZE_UNLIMITED); - filter_xml.close(); - return filter_data; - } - else - { - return LLSD(); - } -} - -// Apply the filter data to the image passed as parameter -void execute_filter(const LLSD& filter_data, LLPointer raw_image) -{ - //std::cout << "Filter : size = " << filter_data.size() << std::endl; - for (S32 i = 0; i < filter_data.size(); ++i) - { - std::string filter_name = filter_data[i][0].asString(); - // Dump out the filter values (for debug) - //std::cout << "Filter : name = " << filter_data[i][0].asString() << ", params = "; - //for (S32 j = 1; j < filter_data[i].size(); ++j) - //{ - // std::cout << filter_data[i][j].asString() << ", "; - //} - //std::cout << std::endl; - - // Execute the filter described on this line - if (filter_name == "blend") - { - raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); - } - else if (filter_name == "fade") - { - raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); - } - else if (filter_name == "lines") - { - raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_LINES,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal())); - } - else if (filter_name == "sepia") - { - raw_image->filterSepia(); - } - else if (filter_name == "grayscale") - { - raw_image->filterGrayScale(); - } - else if (filter_name == "saturate") - { - raw_image->filterSaturate((float)(filter_data[i][1].asReal())); - } - else if (filter_name == "rotate") - { - raw_image->filterRotate((float)(filter_data[i][1].asReal())); - } - else if (filter_name == "gamma") - { - LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); - raw_image->filterGamma((float)(filter_data[i][1].asReal()),color); - } - else if (filter_name == "colorize") - { - LLColor3 color((float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal())); - LLColor3 alpha((F32)(filter_data[i][4].asReal()),(float)(filter_data[i][5].asReal()),(float)(filter_data[i][6].asReal())); - raw_image->filterColorize(color,alpha); - } - else if (filter_name == "contrast") - { - LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); - raw_image->filterContrast((float)(filter_data[i][1].asReal()),color); - } - else if (filter_name == "brighten") - { - LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); - raw_image->filterBrightness((S32)(filter_data[i][1].asReal()),color); - } - else if (filter_name == "darken") - { - LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); - raw_image->filterBrightness((S32)(-filter_data[i][1].asReal()),color); - } - else if (filter_name == "linearize") - { - LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); - raw_image->filterLinearize((float)(filter_data[i][1].asReal()),color); - } - else if (filter_name == "posterize") - { - LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal())); - raw_image->filterEqualize((S32)(filter_data[i][1].asReal()),color); - } - else if (filter_name == "screen") - { - std::string screen_name = filter_data[i][1].asString(); - EScreenMode mode = SCREEN_MODE_2DSINE; - if (screen_name == "2Dsine") - { - mode = SCREEN_MODE_2DSINE; - } - else if (screen_name == "line") - { - mode = SCREEN_MODE_LINE; - } - raw_image->filterScreen(mode,(S32)(filter_data[i][2].asReal()),(F32)(filter_data[i][3].asReal())); - } - } -} - // Create an empty formatted image instance of the correct type from the filename LLPointer create_image(const std::string &filename) { @@ -492,10 +356,6 @@ int main(int argc, char** argv) int levels = 0; bool reversible = false; std::string filter_name = ""; - double filter_param = 0.0; - std::string vignette_name = ""; - double vignette_param_1 = 1.0; - double vignette_param_2 = 0.0; // Init whatever is necessary ll_init_apr(); @@ -686,53 +546,6 @@ int main(int argc, char** argv) arg += 1; // Skip that arg now we know it's a valid test name if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list break; - // --filter 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 filter parameter value - { - filter_param = atof(value_str.c_str()); - arg += 1; // Skip that arg now we used it as a valid filter 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], "--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 optional parameters - 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_1 = 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; - 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_2 = 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")) @@ -781,85 +594,12 @@ int main(int argc, char** argv) continue; } - // Set the vignette if any - if (vignette_name == "blend") - { - raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2)); - } - else if (vignette_name == "fade") - { - raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2)); - } - - // Apply filter if any - if (filter_name == "sepia") - { - raw_image->filterSepia(); - } - else if (filter_name == "grayscale") - { - raw_image->filterGrayScale(); - } - else if (filter_name == "saturate") - { - raw_image->filterSaturate((float)(filter_param)); - } - else if (filter_name == "rotate") - { - raw_image->filterRotate((float)(filter_param)); - } - else if (filter_name == "gamma") - { - raw_image->filterGamma((float)(filter_param),LLColor3::white); - } - else if (filter_name == "colorize") - { - // 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),LLColor3::white); - } - else if (filter_name == "brighten") - { - raw_image->filterBrightness((S32)(filter_param),LLColor3::white); - } - else if (filter_name == "darken") - { - raw_image->filterBrightness((S32)(-filter_param),LLColor3::white); - } - else if (filter_name == "linearize") - { - raw_image->filterLinearize((float)(filter_param),LLColor3::white); - } - else if (filter_name == "posterize") - { - raw_image->filterEqualize((S32)(filter_param),LLColor3::white); - } - else if (filter_name == "newsscreen") - { - raw_image->filterScreen(SCREEN_MODE_2DSINE,(S32)(filter_param),0.0); - } - else if (filter_name == "horizontalscreen") - { - raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),0.0); - } - else if (filter_name == "verticalscreen") - { - raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),90.0); - } - else if (filter_name == "slantedscreen") - { - raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),45.0); - } - else if (filter_name != "") + if (filter_name != "") { // We're interpreting the filter as a filter file name - LLSD filter_data = load_filter_from_file(filter_name); - execute_filter(filter_data,raw_image); + LLImageFilter filter; + filter.loadFromFile(filter_name); + filter.executeFilter(raw_image); } // Save file diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt index e837b0cac2..293ada7548 100755 --- a/indra/llimage/CMakeLists.txt +++ b/indra/llimage/CMakeLists.txt @@ -27,6 +27,7 @@ set(llimage_SOURCE_FILES llimage.cpp llimagedimensionsinfo.cpp llimagedxt.cpp + llimagefilter.cpp llimagej2c.cpp llimagejpeg.cpp llimagepng.cpp @@ -42,6 +43,7 @@ set(llimage_HEADER_FILES llimagebmp.h llimagedimensionsinfo.h llimagedxt.h + llimagefilter.h llimagej2c.h llimagejpeg.h llimagepng.h diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp new file mode 100755 index 0000000000..e2d281e48d --- /dev/null +++ b/indra/llimage/llimagefilter.cpp @@ -0,0 +1,269 @@ +/** + * @file llimagefilter.cpp + * @brief Simple Image Filtering. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llimagefilter.h" + +#include "llmath.h" +#include "v3color.h" +#include "v4coloru.h" +#include "m3math.h" +#include "v3math.h" +#include "llsdserialize.h" + +//--------------------------------------------------------------------------- +// LLImageFilter +//--------------------------------------------------------------------------- + +LLImageFilter::LLImageFilter() : + mFilterData(LLSD::emptyArray()) +{ +} + +LLImageFilter::~LLImageFilter() +{ +} + +/* + " -f, --filter []\n" + " Apply the filter to the input images using the optional value. Admissible names:\n" + " - 'grayscale' converts to grayscale (no param).\n" + " - 'sepia' converts to sepia (no param).\n" + " - 'saturate' changes color saturation according to : < 1.0 will desaturate, > 1.0 will saturate.\n" + " - 'rotate' rotates the color hue according to (in degree, positive value only).\n" + " - 'gamma' applies gamma curve to all channels: > 1.0 will darken, < 1.0 will lighten.\n" + " - 'colorize' applies a red tint to the image using as an alpha (transparency between 0.0 and 1.0) value.\n" + " - 'contrast' modifies the contrast according to : > 1.0 will enhance the contrast, <1.0 will flatten it.\n" + " - 'brighten' adds light to the image ( between 0 and 255).\n" + " - 'darken' substracts light to the image ( between 0 and 255).\n" + " - 'linearize' optimizes the contrast using the brightness histogram. is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n" + " - 'posterize' redistributes the colors between classes per channel ( between 2 and 255).\n" + " - 'newsscreen' applies a 2D sine screening to the red channel and output to black and white.\n" + " - 'horizontalscreen' applies a horizontal screening to the red channel and output to black and white.\n" + " - 'verticalscreen' applies a vertical screening to the red channel and output to black and white.\n" + " - 'slantedscreen' applies a 45 degrees slanted screening to the red channel and output to black and white.\n" + " - Any other value will be interpreted as a file name describing a sequence of filters and parameters to be applied to the input images.\n" + " -v, --vignette [ ]\n" + " Apply a circular central vignette to the filter using the optional and values. 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" + + // Set the vignette if any + if (vignette_name == "blend") + { + raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2)); + } + else if (vignette_name == "fade") + { + raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2)); + } + + // Apply filter if any + if (filter_name == "sepia") + { + raw_image->filterSepia(); + } + else if (filter_name == "grayscale") + { + raw_image->filterGrayScale(); + } + else if (filter_name == "saturate") + { + raw_image->filterSaturate((float)(filter_param)); + } + else if (filter_name == "rotate") + { + raw_image->filterRotate((float)(filter_param)); + } + else if (filter_name == "gamma") + { + raw_image->filterGamma((float)(filter_param),LLColor3::white); + } + else if (filter_name == "colorize") + { + // 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),LLColor3::white); + } + else if (filter_name == "brighten") + { + raw_image->filterBrightness((S32)(filter_param),LLColor3::white); + } + else if (filter_name == "darken") + { + raw_image->filterBrightness((S32)(-filter_param),LLColor3::white); + } + else if (filter_name == "linearize") + { + raw_image->filterLinearize((float)(filter_param),LLColor3::white); + } + else if (filter_name == "posterize") + { + raw_image->filterEqualize((S32)(filter_param),LLColor3::white); + } + else if (filter_name == "newsscreen") + { + raw_image->filterScreen(SCREEN_MODE_2DSINE,(S32)(filter_param),0.0); + } + else if (filter_name == "horizontalscreen") + { + raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),0.0); + } + else if (filter_name == "verticalscreen") + { + raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),90.0); + } + else if (filter_name == "slantedscreen") + { + raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),45.0); + } + + */ + +// Load filter from file +void LLImageFilter::loadFromFile(const std::string& file_path) +{ + //std::cout << "Loading filter settings from : " << file_path << std::endl; + llifstream filter_xml(file_path); + if (filter_xml.is_open()) + { + // Load and parse the file + LLPointer parser = new LLSDXMLParser(); + parser->parse(filter_xml, mFilterData, LLSDSerialize::SIZE_UNLIMITED); + filter_xml.close(); + } + else + { + // File couldn't be open, reset the filter data + mFilterData = LLSD(); + } +} + +// Apply the filter data to the image passed as parameter +void LLImageFilter::executeFilter(LLPointer raw_image) +{ + //std::cout << "Filter : size = " << mFilterData.size() << std::endl; + for (S32 i = 0; i < mFilterData.size(); ++i) + { + std::string filter_name = mFilterData[i][0].asString(); + // Dump out the filter values (for debug) + //std::cout << "Filter : name = " << mFilterData[i][0].asString() << ", params = "; + //for (S32 j = 1; j < mFilterData[i].size(); ++j) + //{ + // std::cout << mFilterData[i][j].asString() << ", "; + //} + //std::cout << std::endl; + + // Execute the filter described on this line + if (filter_name == "blend") + { + raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal())); + } + else if (filter_name == "fade") + { + raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal())); + } + else if (filter_name == "lines") + { + raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_LINES,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal())); + } + else if (filter_name == "sepia") + { + raw_image->filterSepia(); + } + else if (filter_name == "grayscale") + { + raw_image->filterGrayScale(); + } + else if (filter_name == "saturate") + { + raw_image->filterSaturate((float)(mFilterData[i][1].asReal())); + } + else if (filter_name == "rotate") + { + raw_image->filterRotate((float)(mFilterData[i][1].asReal())); + } + else if (filter_name == "gamma") + { + LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal())); + raw_image->filterGamma((float)(mFilterData[i][1].asReal()),color); + } + else if (filter_name == "colorize") + { + LLColor3 color((float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal())); + LLColor3 alpha((F32)(mFilterData[i][4].asReal()),(float)(mFilterData[i][5].asReal()),(float)(mFilterData[i][6].asReal())); + raw_image->filterColorize(color,alpha); + } + else if (filter_name == "contrast") + { + LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal())); + raw_image->filterContrast((float)(mFilterData[i][1].asReal()),color); + } + else if (filter_name == "brighten") + { + LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal())); + raw_image->filterBrightness((S32)(mFilterData[i][1].asReal()),color); + } + else if (filter_name == "darken") + { + LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal())); + raw_image->filterBrightness((S32)(-mFilterData[i][1].asReal()),color); + } + else if (filter_name == "linearize") + { + LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal())); + raw_image->filterLinearize((float)(mFilterData[i][1].asReal()),color); + } + else if (filter_name == "posterize") + { + LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal())); + raw_image->filterEqualize((S32)(mFilterData[i][1].asReal()),color); + } + else if (filter_name == "screen") + { + std::string screen_name = mFilterData[i][1].asString(); + EScreenMode mode = SCREEN_MODE_2DSINE; + if (screen_name == "2Dsine") + { + mode = SCREEN_MODE_2DSINE; + } + else if (screen_name == "line") + { + mode = SCREEN_MODE_LINE; + } + raw_image->filterScreen(mode,(S32)(mFilterData[i][2].asReal()),(F32)(mFilterData[i][3].asReal())); + } + } +} + + +//============================================================================ diff --git a/indra/llimage/llimagefilter.h b/indra/llimage/llimagefilter.h new file mode 100755 index 0000000000..5598fa69f5 --- /dev/null +++ b/indra/llimage/llimagefilter.h @@ -0,0 +1,73 @@ +/** + * @file llimagefilter.h + * @brief Simple Image Filtering. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLIMAGEFILTER_H +#define LL_LLIMAGEFILTER_H + +#include "llimage.h" + +/* +class LLImageRaw; +class LLColor4U; +class LLColor3; +class LLMatrix3; + +typedef enum e_vignette_mode +{ + VIGNETTE_MODE_NONE = 0, + VIGNETTE_MODE_BLEND = 1, + VIGNETTE_MODE_FADE = 2 +} EVignetteMode; + +typedef enum e_vignette_type +{ + VIGNETTE_TYPE_CENTER = 0, + VIGNETTE_TYPE_LINES = 1 +} EVignetteType; + +typedef enum e_screen_mode +{ + SCREEN_MODE_2DSINE = 0, + SCREEN_MODE_LINE = 1 +} EScreenMode; +*/ +//============================================================================ +// Image Filter + +class LLImageFilter +{ +public: + LLImageFilter(); + ~LLImageFilter(); + + void loadFromFile(const std::string& file_path); + void executeFilter(LLPointer raw_image); +private: + LLSD mFilterData; +}; + + +#endif -- cgit v1.3 From fda7b94f490564568dee0ba6d6516943b0fd82a0 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 16 Jan 2014 18:34:51 -0800 Subject: ACME-1236 : Small LLImageFilter clean up --- .../llimage_libtest/llimage_libtest.cpp | 14 ++++----- indra/llimage/llimagefilter.cpp | 33 +++++++--------------- indra/llimage/llimagefilter.h | 6 ++-- indra/newview/llfloaterflickr.cpp | 2 -- indra/newview/llsnapshotlivepreview.cpp | 6 ++-- 5 files changed, 21 insertions(+), 40 deletions(-) (limited to 'indra/integration_tests/llimage_libtest/llimage_libtest.cpp') diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index d3373a61f2..3d27b4a5b5 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -578,7 +578,10 @@ int main(int argc, char** argv) fast_timer_log_thread = new LogThread(LLFastTimer::sLogName); fast_timer_log_thread->start(); } - + + // Load the filter once and for all + LLImageFilter filter(filter_name); + // Perform action on each input file std::list::iterator in_file = input_filenames.begin(); std::list::iterator out_file = output_filenames.begin(); @@ -594,13 +597,8 @@ int main(int argc, char** argv) continue; } - if (filter_name != "") - { - // We're interpreting the filter as a filter file name - LLImageFilter filter; - filter.loadFromFile(filter_name); - filter.executeFilter(raw_image); - } + // Apply the filter + filter.executeFilter(raw_image); // Save file if (out_file != out_end) diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp index 5c969001b7..cd03454cdd 100755 --- a/indra/llimage/llimagefilter.cpp +++ b/indra/llimage/llimagefilter.cpp @@ -39,7 +39,7 @@ // LLImageFilter //--------------------------------------------------------------------------- -LLImageFilter::LLImageFilter() : +LLImageFilter::LLImageFilter(const std::string& file_path) : mFilterData(LLSD::emptyArray()), mImage(NULL), mHistoRed(NULL), @@ -50,6 +50,15 @@ LLImageFilter::LLImageFilter() : mVignetteGamma(1.0), mVignetteMin(0.0) { + // Load filter description from file + llifstream filter_xml(file_path); + if (filter_xml.is_open()) + { + // Load and parse the file + LLPointer parser = new LLSDXMLParser(); + parser->parse(filter_xml, mFilterData, LLSDSerialize::SIZE_UNLIMITED); + filter_xml.close(); + } } LLImageFilter::~LLImageFilter() @@ -113,28 +122,6 @@ LLImageFilter::~LLImageFilter() " - 'fade' : the filter is applied with full intensity in the center and fades to black to the periphery.\n" */ -//============================================================================ -// Load filter from file -//============================================================================ - -void LLImageFilter::loadFromFile(const std::string& file_path) -{ - //std::cout << "Loading filter settings from : " << file_path << std::endl; - llifstream filter_xml(file_path); - if (filter_xml.is_open()) - { - // Load and parse the file - LLPointer parser = new LLSDXMLParser(); - parser->parse(filter_xml, mFilterData, LLSDSerialize::SIZE_UNLIMITED); - filter_xml.close(); - } - else - { - // File couldn't be open, reset the filter data - mFilterData = LLSD(); - } -} - //============================================================================ // Apply the filter data to the image passed as parameter //============================================================================ diff --git a/indra/llimage/llimagefilter.h b/indra/llimage/llimagefilter.h index c67789ede0..dc092a47a5 100755 --- a/indra/llimage/llimagefilter.h +++ b/indra/llimage/llimagefilter.h @@ -54,15 +54,15 @@ typedef enum e_screen_mode } EScreenMode; //============================================================================ -// Image Filter +// LLImageFilter +//============================================================================ class LLImageFilter { public: - LLImageFilter(); + LLImageFilter(const std::string& file_path); ~LLImageFilter(); - void loadFromFile(const std::string& file_path); void executeFilter(LLPointer raw_image); private: diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp index cff57bfa13..c34124caf5 100644 --- a/indra/newview/llfloaterflickr.cpp +++ b/indra/newview/llfloaterflickr.cpp @@ -334,7 +334,6 @@ void LLFlickrPhotoPanel::updateResolution(BOOL do_update) S32 height = sdres[1]; const std::string& filter_name = filterbox->getSimple(); - llinfos << "Merov : filter name is : " << filter_name << llendl; LLSnapshotLivePreview * previewp = static_cast(mPreviewHandle.get()); if (previewp && combobox->getCurrentIndex() >= 0) @@ -358,7 +357,6 @@ void LLFlickrPhotoPanel::updateResolution(BOOL do_update) checkAspectRatio(width); previewp->getSize(width, height); - // Merov : // Get the old filter, compare to the current one "filter_name" and set if changed // If changed, also force the updateSnapshot() here under std::string original_filter = previewp->getFilter(); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 21abdd2675..ee74dbdb0f 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -594,8 +594,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(getFilter()); if (filter_path != "") { - LLImageFilter filter; - filter.loadFromFile(filter_path); + LLImageFilter filter(filter_path); filter.executeFilter(raw); } else @@ -713,8 +712,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(previewp->getFilter()); if (filter_path != "") { - LLImageFilter filter; - filter.loadFromFile(filter_path); + LLImageFilter filter(filter_path); filter.executeFilter(previewp->mPreviewImage); } else -- cgit v1.3