diff options
| author | Merov Linden <merov@lindenlab.com> | 2014-01-21 13:05:54 -0800 | 
|---|---|---|
| committer | Merov Linden <merov@lindenlab.com> | 2014-01-21 13:05:54 -0800 | 
| commit | 6c630b73a825befb6eeef66d7ed0063b1b891df7 (patch) | |
| tree | e3ba95bc7a6668a5db9ae3f9193c9c2345745bd8 /indra | |
| parent | d14392f55f9c47ba121d5470a3deb153a16b1cfb (diff) | |
ACME-1240 : Implement convolve filter for 3x3 kernels. Implements sharpen, blur and edge detection as examples and tests.
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/integration_tests/llimage_libtest/blur.xml | 7 | ||||
| -rw-r--r-- | indra/integration_tests/llimage_libtest/edges.xml | 24 | ||||
| -rw-r--r-- | indra/integration_tests/llimage_libtest/sharpen.xml | 7 | ||||
| -rwxr-xr-x | indra/llimage/llimagefilter.cpp | 164 | ||||
| -rwxr-xr-x | indra/llimage/llimagefilter.h | 1 | 
5 files changed, 203 insertions, 0 deletions
| diff --git a/indra/integration_tests/llimage_libtest/blur.xml b/indra/integration_tests/llimage_libtest/blur.xml new file mode 100644 index 0000000000..addd056855 --- /dev/null +++ b/indra/integration_tests/llimage_libtest/blur.xml @@ -0,0 +1,7 @@ +<llsd> +    <array> +        <array> +            <string>blur</string> +        </array> +    </array> +</llsd> diff --git a/indra/integration_tests/llimage_libtest/edges.xml b/indra/integration_tests/llimage_libtest/edges.xml new file mode 100644 index 0000000000..a66b81d01e --- /dev/null +++ b/indra/integration_tests/llimage_libtest/edges.xml @@ -0,0 +1,24 @@ +<llsd> +    <array> +        <array> +            <string>gradient</string> +        </array> +        <array> +            <string>blur</string> +        </array> +        <array> +            <string>linearize</string> +            <real>0.0</real> +            <real>1.0</real> +            <real>1.0</real> +            <real>1.0</real> +        </array> +        <array> +            <string>contrast</string> +            <real>2.0</real> +            <real>1.0</real> +            <real>1.0</real> +            <real>1.0</real> +        </array> +    </array> +</llsd> diff --git a/indra/integration_tests/llimage_libtest/sharpen.xml b/indra/integration_tests/llimage_libtest/sharpen.xml new file mode 100644 index 0000000000..6d3f9ae1a2 --- /dev/null +++ b/indra/integration_tests/llimage_libtest/sharpen.xml @@ -0,0 +1,7 @@ +<llsd> +    <array> +        <array> +            <string>sharpen</string> +        </array> +    </array> +</llsd> diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp index 0f11b1037f..75661a6d4b 100755 --- a/indra/llimage/llimagefilter.cpp +++ b/indra/llimage/llimagefilter.cpp @@ -34,6 +34,7 @@  #include "m3math.h"  #include "v3math.h"  #include "llsdserialize.h" +#include "llstring.h"  //---------------------------------------------------------------------------  // LLImageFilter @@ -281,6 +282,32 @@ void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image)              }              filterScreen(mode,(S32)(mFilterData[i][2].asReal()),(F32)(mFilterData[i][3].asReal()));          } +        else if (filter_name == "blur") +        { +            LLMatrix3 kernel; +            for (S32 i = 0; i < NUM_VALUES_IN_MAT3; i++) +                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++) +                    kernel.mMatrix[i][j] = 1.0; +            convolve(kernel,true,false); +        } +        else if (filter_name == "sharpen") +        { +            LLMatrix3 kernel; +            for (S32 i = 0; i < NUM_VALUES_IN_MAT3; i++) +                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++) +                    kernel.mMatrix[i][j] = -1.0; +            kernel.mMatrix[1][1] = 9.0; +            convolve(kernel,false,false); +        } +        else if (filter_name == "gradient") +        { +            LLMatrix3 kernel; +            for (S32 i = 0; i < NUM_VALUES_IN_MAT3; i++) +                for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++) +                    kernel.mMatrix[i][j] = -1.0; +            kernel.mMatrix[1][1] = 8.0; +            convolve(kernel,false,true); +        }      }  } @@ -365,6 +392,143 @@ void LLImageFilter::colorTransform(const LLMatrix3 &transform)  	}  } +void LLImageFilter::convolve(const LLMatrix3 &kernel, bool normalize, bool abs_value) +{ +	const S32 components = mImage->getComponents(); +	llassert( components >= 1 && components <= 4 ); +     +    // Compute normalization factors +    F32 kernel_min = 0.0; +    F32 kernel_max = 0.0; +    for (S32 i = 0; i < NUM_VALUES_IN_MAT3; i++) +    { +        for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++) +        { +            if (kernel.mMatrix[i][j] >= 0.0) +                kernel_max += kernel.mMatrix[i][j]; +            else +                kernel_min += kernel.mMatrix[i][j]; +        } +    } +    if (abs_value) +    { +        kernel_max = llabs(kernel_max); +        kernel_min = llabs(kernel_min); +        kernel_max = llmax(kernel_max,kernel_min); +        kernel_min = 0.0; +    } +    F32 kernel_range = kernel_max - kernel_min; +     +    // Allocate temporary buffers and initialize algorithm's data +	S32 width  = mImage->getWidth(); +    S32 height = mImage->getHeight(); +     +	U8* dst_data = mImage->getData(); + +	S32 buffer_size = width * components; +	llassert_always(buffer_size > 0); +	std::vector<U8> even_buffer(buffer_size); +	std::vector<U8> odd_buffer(buffer_size); +	 +    U8* south_data = dst_data + buffer_size; +    U8* east_west_data; +    U8* north_data; +     +    // Line 0 : we set the line to 0 (debatable) +    memcpy( &even_buffer[0], dst_data, buffer_size );	/* Flawfinder: ignore */ +    for (S32 i = 0; i < width; i++) +    { +        blendStencil(getStencilAlpha(i,0), dst_data, 0, 0, 0); +        dst_data += components; +    } +    south_data += buffer_size; +     +    // All other lines +    for (S32 j = 1; j < (height-1); j++) +	{ +        // We need to buffer 2 lines. We flip north and current to avoid moving too much memory around +        if (j % 2) +        { +            memcpy( &odd_buffer[0], dst_data, buffer_size );	/* Flawfinder: ignore */ +            east_west_data = &odd_buffer[0]; +            north_data = &even_buffer[0]; +        } +        else +        { +            memcpy( &even_buffer[0], dst_data, buffer_size );	/* Flawfinder: ignore */ +            east_west_data = &even_buffer[0]; +            north_data = &odd_buffer[0]; +        } +        // First pixel : set to 0 +        blendStencil(getStencilAlpha(0,j), dst_data, 0, 0, 0); +        // Set pointers to kernel +        U8* NW = north_data; +        U8* N = NW+components; +        U8* NE = N+components; +        U8* W = east_west_data; +        U8* C = W+components; +        U8* E = C+components; +        U8* SW = south_data; +        U8* S = SW+components; +        U8* SE = S+components; +        dst_data += components; +        // All other pixels +        for (S32 i = 1; i < (width-1); i++) +        { +            // Compute convolution +            LLVector3 dst; +            dst.mV[VRED] = (kernel.mMatrix[0][0]*NW[VRED] + kernel.mMatrix[0][1]*N[VRED] + kernel.mMatrix[0][2]*NE[VRED] + +                            kernel.mMatrix[1][0]*W[VRED]  + kernel.mMatrix[1][1]*C[VRED] + kernel.mMatrix[1][2]*E[VRED] + +                            kernel.mMatrix[2][0]*SW[VRED] + kernel.mMatrix[2][1]*S[VRED] + kernel.mMatrix[2][2]*SE[VRED]); +            dst.mV[VGREEN] = (kernel.mMatrix[0][0]*NW[VGREEN] + kernel.mMatrix[0][1]*N[VGREEN] + kernel.mMatrix[0][2]*NE[VGREEN] + +                              kernel.mMatrix[1][0]*W[VGREEN]  + kernel.mMatrix[1][1]*C[VGREEN] + kernel.mMatrix[1][2]*E[VGREEN] + +                              kernel.mMatrix[2][0]*SW[VGREEN] + kernel.mMatrix[2][1]*S[VGREEN] + kernel.mMatrix[2][2]*SE[VGREEN]); +            dst.mV[VBLUE] = (kernel.mMatrix[0][0]*NW[VBLUE] + kernel.mMatrix[0][1]*N[VBLUE] + kernel.mMatrix[0][2]*NE[VBLUE] + +                             kernel.mMatrix[1][0]*W[VBLUE]  + kernel.mMatrix[1][1]*C[VBLUE] + kernel.mMatrix[1][2]*E[VBLUE] + +                             kernel.mMatrix[2][0]*SW[VBLUE] + kernel.mMatrix[2][1]*S[VBLUE] + kernel.mMatrix[2][2]*SE[VBLUE]); +            if (abs_value) +            { +                dst.mV[VRED]   = llabs(dst.mV[VRED]); +                dst.mV[VGREEN] = llabs(dst.mV[VGREEN]); +                dst.mV[VBLUE]  = llabs(dst.mV[VBLUE]); +            } +            if (normalize) +            { +                dst.mV[VRED]   = (dst.mV[VRED] - kernel_min)/kernel_range; +                dst.mV[VGREEN] = (dst.mV[VGREEN] - kernel_min)/kernel_range; +                dst.mV[VBLUE]  = (dst.mV[VBLUE] - kernel_min)/kernel_range; +            } +            dst.clamp(0.0f,255.0f); +             +            // Blend result +            blendStencil(getStencilAlpha(i,j), dst_data, dst.mV[VRED], dst.mV[VGREEN], dst.mV[VBLUE]); +             +            // Next pixel +            dst_data += components; +            NW += components; +            N += components; +            NE += components; +            W += components; +            C += components; +            E += components; +            SW += components; +            S += components; +            SE += components; +        } +        // Last pixel : set to 0 +        blendStencil(getStencilAlpha(width-1,j), dst_data, 0, 0, 0); +        dst_data += components; +        south_data += buffer_size; +	} +     +    // Last line +    for (S32 i = 0; i < width; i++) +    { +        blendStencil(getStencilAlpha(i,0), dst_data, 0, 0, 0); +        dst_data += components; +    } +} +  void LLImageFilter::filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle)  {  	const S32 components = mImage->getComponents(); diff --git a/indra/llimage/llimagefilter.h b/indra/llimage/llimagefilter.h index 19ac7e81d6..738c693686 100755 --- a/indra/llimage/llimagefilter.h +++ b/indra/llimage/llimagefilter.h @@ -91,6 +91,7 @@ private:      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 blendStencil(F32 alpha, U8* pixel, U8 red, U8 green, U8 blue); +    void convolve(const LLMatrix3 &kernel, bool normalize, bool abs_value);      // Procedural Stencils      void setStencil(EStencilBlendMode mode, EStencilShape type, F32 gamma, F32 min, F32 max); | 
