diff options
author | Merov Linden <merov@lindenlab.com> | 2014-01-14 21:01:51 -0800 |
---|---|---|
committer | Merov Linden <merov@lindenlab.com> | 2014-01-14 21:01:51 -0800 |
commit | 7cc64a09a3ca9211354427206f04d157c9ac30a2 (patch) | |
tree | 5d6164d4158d577cfc2e3afa0070a431935e1343 /indra/llimage/llimage.cpp | |
parent | d972efa64c5877c611f9ca583483978dca3c6768 (diff) |
ACME-1236 : Refactor filters and vignette into llimagefilter, add example filters to llimage_libtest
Diffstat (limited to 'indra/llimage/llimage.cpp')
-rwxr-xr-x | indra/llimage/llimage.cpp | 527 |
1 files changed, 1 insertions, 526 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 3105fe3746..7981ca7364 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -98,14 +98,7 @@ LLImageBase::LLImageBase() mHeight(0), mComponents(0), mBadBufferAllocation(false), - mAllowOverSize(false), - mHistoRed(NULL), - mHistoGreen(NULL), - mHistoBlue(NULL), - mHistoBrightness(NULL), - mVignetteMode(VIGNETTE_MODE_NONE), - mVignetteGamma(1.0), - mVignetteMin(0.0) + mAllowOverSize(false) { } @@ -113,10 +106,6 @@ 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 @@ -947,520 +936,6 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) return TRUE ; } -// Filter Operations -void LLImageRaw::filterGrayScale() -{ - LLMatrix3 gray_scale; - LLVector3 luminosity(0.2125, 0.7154, 0.0721); - gray_scale.setRows(luminosity, luminosity, luminosity); - gray_scale.transpose(); - colorTransform(gray_scale); -} - -void LLImageRaw::filterSepia() -{ - LLMatrix3 sepia; - sepia.setRows(LLVector3(0.3588, 0.7044, 0.1368), - LLVector3(0.2990, 0.5870, 0.1140), - LLVector3(0.2392, 0.4696, 0.0912)); - sepia.transpose(); - 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( 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 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); -} - -void LLImageRaw::filterRotate(F32 angle) -{ - // 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; - 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 - LLMatrix3 transfo = Lij_inv * r * Lij; - colorTransform(transfo); -} - -void LLImageRaw::filterGamma(F32 gamma, const LLColor3& alpha) -{ - U8 gamma_red_lut[256]; - U8 gamma_green_lut[256]; - U8 gamma_blue_lut[256]; - - for (S32 i = 0; i < 256; i++) - { - F32 gamma_i = llclampf((float)(powf((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, const LLColor3& alpha) -{ - // 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_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++) - { - 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 - { - // 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++) - { - 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_red_lut,linear_green_lut,linear_blue_lut); -} - -void LLImageRaw::filterEqualize(S32 nb_classes, const LLColor3& alpha) -{ - // 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_red_lut[256]; - U8 equalize_green_lut[256]; - U8 equalize_blue_lut[256]; - for (S32 i = 0; i < 256; i++) - { - // 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; - current_value += delta_value; - current_value = llclampb(current_value); - } - } - - // Apply lookup table - colorCorrect(equalize_red_lut,equalize_green_lut,equalize_blue_lut); -} - -void LLImageRaw::filterColorize(const LLColor3& color, const LLColor3& alpha) -{ - U8 red_lut[256]; - U8 green_lut[256]; - U8 blue_lut[256]; - - 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)((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, const LLColor3& alpha) -{ - 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++) - { - 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_red_lut,contrast_green_lut,contrast_blue_lut); -} - -void LLImageRaw::filterBrightness(S32 add, const LLColor3& alpha) -{ - U8 brightness_red_lut[256]; - U8 brightness_green_lut[256]; - U8 brightness_blue_lut[256]; - - for (S32 i = 0; i < 256; i++) - { - U8 value_i = (U8)(llclampb((S32)((S32)(i) + add))); - // Blend in with alpha values - brightness_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - brightness_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - brightness_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); - } - - colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut); -} - -// Filter Primitives -void LLImageRaw::colorTransform(const LLMatrix3 &transform) -{ - 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++) - { - 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; - } - } -} - -void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue) -{ - 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++) - { - 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::filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle) -{ - const S32 components = getComponents(); - llassert( components >= 1 && components <= 4 ); - - 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 = 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; - 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, 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 - mVignetteCenterX = getWidth()/2; - mVignetteCenterY = getHeight()/2; - mVignetteWidth = llmin(getWidth()/2,getHeight()/2); -} - -F32 LLImageRaw::getVignetteAlpha(S32 i, S32 j) -{ - 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)); -} - -U32* LLImageRaw::getBrightnessHistogram() -{ - if (!mHistoBrightness) - { - computeHistograms(); - } - return mHistoBrightness; -} - -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(); |