Fast glsl deNoise spatial filter, with circular gaussian kernel, full configurable

Overview

glslSmartDeNoise

Fast glsl spatial deNoise filter, with circular gaussian kernel and smart/flexible/adaptable -> full configurable:

  • Standard Deviation sigma radius
  • K factor sigma coefficient
  • Edge sharpening threshold

*result depends on settings and input signal

Enhancements

Some enhancements can be obtained using "other color spaces" on noise evaluation (not on final image), to emphasize pixel differences/threshold.

  • sRGB with gamma correction.
  • Luminance
  • HSL using HL components and leaving out S (saturation)
  • ... other possibles (write me)

All this can lead to better results, under certain circumstances, but at the expense of performance, so these are not inserted in the main filter: use live WebGL demo to try they. *full source is provided in example folder - main filter variants are contained in Shaders/frag.glsl file

Live WebGL2 demo -> glslSmartDeNoise
Tree - Sunset
Runner - on the beach
Tree - Daylight

About live WebGL2 demos

You can run/test WebGL 2 examples of glslSmartDeNoise also from following links:

It works only on browsers with WebGl 2 and webAssembly support (FireFox/Opera/Chrome and Chromium based)

Test if your browser supports WebGL 2, here: WebGL2 Report

glslSmartDeNoise is used in glChAoS.P poroject to produce a effect like a "stardust" or "particle-dust" (it's the "bilinear threshold" filter in GLOW section) You can watch a graphical example at glChAoS.P glow threshold effect link

glslSmartDeNoise filter

Below there is the filter source code with parameters description: this is everything you need.

To view its use you can also examine the Shader\frag.glsl file (all other files are only part of the C++ examples)

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  Copyright (c) 2018-2019 Michele Morrone
//  All rights reserved.
//
//  https://michelemorrone.eu - https://BrutPitt.com
//
//  [email protected] - [email protected]
//  twitter: @BrutPitt - github: BrutPitt
//  
//  https://github.com/BrutPitt/glslSmartDeNoise/
//
//  This software is distributed under the terms of the BSD 2-Clause license
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#define INV_SQRT_OF_2PI 0.39894228040143267793994605993439  // 1.0/SQRT_OF_2PI
#define INV_PI 0.31830988618379067153776752674503

//  smartDeNoise - parameters
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  sampler2D tex     - sampler image / texture
//  vec2 uv           - actual fragment coord
//  float sigma  >  0 - sigma Standard Deviation
//  float kSigma >= 0 - sigma coefficient 
//      kSigma * sigma  -->  radius of the circular kernel
//  float threshold   - edge sharpening threshold 

vec4 smartDeNoise(sampler2D tex, vec2 uv, float sigma, float kSigma, float threshold)
{
    float radius = round(kSigma*sigma);
    float radQ = radius * radius;

    float invSigmaQx2 = .5 / (sigma * sigma);      // 1.0 / (sigma^2 * 2.0)
    float invSigmaQx2PI = INV_PI * invSigmaQx2;    // 1/(2 * PI * sigma^2)

    float invThresholdSqx2 = .5 / (threshold * threshold);     // 1.0 / (sigma^2 * 2.0)
    float invThresholdSqrt2PI = INV_SQRT_OF_2PI / threshold;   // 1.0 / (sqrt(2*PI) * sigma^2)

    vec4 centrPx = texture(tex,uv); 

    float zBuff = 0.0;
    vec4 aBuff = vec4(0.0);
    vec2 size = vec2(textureSize(tex, 0));

    vec2 d;
    for (d.x=-radius; d.x <= radius; d.x++) {
        float pt = sqrt(radQ-d.x*d.x);       // pt = yRadius: have circular trend
        for (d.y=-pt; d.y <= pt; d.y++) {
            float blurFactor = exp( -dot(d , d) * invSigmaQx2 ) * invSigmaQx2PI;

            vec4 walkPx =  texture(tex,uv+d/size);
            vec4 dC = walkPx-centrPx;
            float deltaFactor = exp( -dot(dC, dC) * invThresholdSqx2) * invThresholdSqrt2PI * blurFactor;

            zBuff += deltaFactor;
            aBuff += deltaFactor*walkPx;
        }
    }
    return aBuff/zBuff;
}

Below there are considerations about parameters utilization and the optimizations description.

//  About Standard Deviations (watch Gauss curve)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  kSigma = 1*sigma cover 68% of data
//  kSigma = 2*sigma cover 95% of data - but there are over 3 times 
//                   more points to compute
//  kSigma = 3*sigma cover 99.7% of data - but needs more than double 
//                   the calculations of 2*sigma


//  Optimizations (description)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  fX = exp( -(x*x) * invSigmaSqx2 ) * invSigmaxSqrt2PI; 
//  fY = exp( -(y*y) * invSigmaSqx2 ) * invSigmaxSqrt2PI; 
//  where...
//      invSigmaSqx2     = 1.0 / (sigma^2 * 2.0)
//      invSigmaxSqrt2PI = 1.0 / (sqrt(2 * PI) * sigma)
//
//  now, fX*fY can be written in unique expression...
//
//      e^(a*X) * e^(a*Y) * c*c
//
//      where:
//        a = invSigmaSqx2, X = (x*x), Y = (y*y), c = invSigmaxSqrt2PI
//
//           -[(x*x) * 1/(2 * sigma^2)]             -[(y*y) * 1/(2 * sigma^2)] 
//          e                                      e
//  fX = -------------------------------    fY = -------------------------------
//                ________                               ________
//              \/ 2 * PI  * sigma                     \/ 2 * PI  * sigma
//
//      now with... 
//        a = 1/(2 * sigma^2), 
//        X = (x*x) 
//        Y = (y*y) ________
//        c = 1 / \/ 2 * PI  * sigma
//
//      we have...
//              -[aX]              -[aY]
//        fX = e      * c;   fY = e      * c;
//
//      and...
//                 -[aX + aY]    [2]     -[a(X + Y)]    [2]
//        fX*fY = e           * c     = e            * c   
//
//      well...
//
//                    -[(x*x + y*y) * 1/(2 * sigma^2)]
//                   e                                
//        fX*fY = --------------------------------------
//                                        [2]           
//                          2 * PI * sigma           
//      
//      now with assigned constants...
//
//          invSigmaQx2   = 1/(2 * sigma^2)
//          invSigmaQx2PI = 1/(2 * PI * sigma^2) = invSigmaQx2 * INV_PI 
//
//      and the kernel vector 
//
//          k = vec2(x,y)
//
//      we can write:
//
//          fXY = exp( -dot(k,k) * invSigmaQx2) * invSigmaQx2PI
//

*can find it also in Shader/frag.glsl file

Building Example

The C++ example shown in the screenshot is provided. To build it you can use CMake (3.15 or higher) or the Visual Studio solution project (for VS 2017/2019) in Windows. You need to have installed GLFW (v.3.3 or above) in your compiler search path (LIB/INCLUDE). Other tools: ImGui, lodePNG and glad are attached, and already included in the project.

To build example with CMake in Linux / MacOS / Windows uses follow command:

# cmake -DBuildTarget:String=<BuildVer> -G <MakeTool> -B<FolderToBuild>
#   where:
#       <BuildVer> must be one of follow strings:
#           OpenGL_45
#           OpenGL_41
#           OpenGL_ES
#       <MakeTool> is your preferred generator like "Unix Makefiles" or "Ninja"
#       <FolderToBuild> is the folder where will be generated Makefile, move in it and run your generator
#       - Default build is "Release" but it can be changed via CMAKE_BUILD_TYPE definition:
#           command line: -DCMAKE_BUILD_TYPE:STRING=<Debug|Release|MinSizeRel|RelWithDebInfo>
#           cmake-gui: from combo associated to CMAKE_BUILD_TYPE var
#
# Example:
#   to build example compliant to OpenGL 4.5, with "make" utility, in "./build" folder, type:
#
#       > cmake -DBuildTarget:String=OpenGL_45 -G Unix\ Makefiles -B./build
#       > cd build
#       > make
#

The CMake file is able to build also an EMSCRIPTEN version, obviously you need to have installed EMSCRIPTEN SDK on your computer (1.38.10 or higher):

# To build example with EMSCRIPTEN uses follow command:
# cmake cmake -DCMAKE_TOOLCHAIN_FILE:STRING=<EMSDK_PATH>/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DBuildTarget:String=<BuildVer> -G "Unix Makefiles"|"ninja" -B<FolderToBuild>
#   where:
#       <EMSDK_PATH> is where was installed EMSCRIPTEN: you need to have it in EMSDK environment variable
#       <BuildVer> must be one of follow strings:
#           WebGL
#       <MakeTool> is your preferred generator like "Unix Makefiles" or "ninja"
#           Windows users need to use MinGW-make utility (by EMSCRIPTEN specification): ninja or othe can not work.
#       <FolderToBuild> is the folder where will be generated Makefile, move in it and run your generator
#       - Default build is "MinSizeRel" but it can be changed via CMAKE_BUILD_TYPE definition:
#           command line: -DCMAKE_BUILD_TYPE:STRING=<Debug|Release|MinSizeRel|RelWithDebInfo>
#           cmake-gui: from combo associated to CMAKE_BUILD_TYPE var

To build the EMSCRIPTEN version, in Windows, with CMake, need to have mingw32-make.exe in your computer and search PATH (only the make utility is enough): it is a condition of EMSDK tool to build with CMake in Windows.

Issues
  • Potential issues in the shader

    Potential issues in the shader

    Hello!

    I've noticed a number of peculiar things in the fragment shader code, which I believe are bugs:

    1. float invSigmaQx2PI = INV_PI * invSigmaQx2; // 1.0 / (sqrt(PI) * sigma) This line is not equal to 1.0 / (sqrt(PI) * sigma), which seems to simply be a comment error. However, this variable is also not used anywhere in the code, see point 3.

    2. vec2 d = vec2(x,y)/size; Dividing d by the texture size implies that the standard deviation (sigma) is in normalized texture coordinates. In fact, dot(d, d) is so close to zero that the resulting denoised image looks identical if it is simply replaced with 0.0. I believe the correct value should be vec2(x, y);, without the division.

    3. float blurFactor = exp( -dot(d , d) * invSigmaQx2 ) * invSigmaQx2; The multiplication by invSigmaQx2 seems incorrect and should be invSigmaQx2PI.

    Thanks for the nice and simple denoising filter!

    Edit: Here's my hopefully fixed ShaderToy code, also switched to using texelFetch() instead of texture(). https://pastebin.com/FUScJxgK

    Edit2: Forcing float blurFactor = 1.0; gives visually indistuingishable results to the original shader, and most likely behaves more like a smart box filter than a smart gaussian blur. It does however still look good, and is presumably a decent bit cheaper to evaluate.

    bug 
    opened by theagentd 5
  • glslSmartDeNoise is now utilized in JWildfireSwan

    glslSmartDeNoise is now utilized in JWildfireSwan

    Hi BrutPitt, I just wanted to mention that I'm now using an adoption of your glslSmartDeNoise-algorithm in my project, which is an advanced flame-fractal-generator based on WebGl and Vaadin: https://github.com/thargor6/JWildfireSwan There is also a live demo: https://herokuapp.overwhale.com/

    Thanks for your work and best regards, Andreas

    opened by thargor6 0
  • Is this shader separable?

    Is this shader separable?

    I noticed this shader is quite similar to a gaussian blur, which is a separable filter (blurring on just the X axis, and then blurring that image on just the Y axis gives the same results as doing a full convolution).

    Do you think this could be turned into a separable version? I'm attempting that now, but I may have my math incorrect and I'm not 100% sure if it's even possible. If I come up with something I'll be sure to submit a PR, but I'm curious if you've already evaluated this.

    enhancement 
    opened by bschwind 4
  • Using this shader with HDR tonemapping image: before or after?

    Using this shader with HDR tonemapping image: before or after?

    I'm looking at integrating this denoising shader in Godot Engine and was wondering about denoising an HDR viewport. The engine uses a tonemapping shader to convert the viewport into a LDR image for display. For best results, should I run the denoising shader before or after tonemapping? My gut feeling tells me I should do this after tonemapping, but I'm not sure exactly.

    This should be documented in the README and/or in the shader code. Thanks in advance for replying :slightly_smiling_face:

    opened by Calinou 1
Owner
Michele Morrone
Software Engineer
Michele Morrone
glslcc: Cross-compiler for GLSL shader language (GLSL->HLSL,METAL,GLES,GLSLv3)

glslcc: Cross-compiler for GLSL shader language (GLSL->HLSL,METAL,GLES,GLSLv3) @septag glslcc is a command line tool that converts GLSL code to HLSL,

Sepehr Taghdisian 405 Jun 23, 2022
LLVM IR and optimizer for shaders, including front-end adapters for GLSL and SPIR-V and back-end adapter for GLSL

Licensing LunarGLASS is available via a three clause BSD-style open source license. Goals The primary goals of the LunarGLASS project are: Reduce the

LunarG, Inc. 151 Jun 18, 2022
⚔️ A tool for cross compiling shaders. Convert between GLSL, HLSL, Metal Shader Language, or older versions of GLSL.

A cross compiler for shader languages. Convert between SPIR-V, GLSL / GLSL ES, HLSL, Metal Shader Language, or older versions of a given language. Cross Shader wraps glslang and SPIRV-Cross, exposing a simpler interface to transpile shaders.

Alain Galvan 157 Jun 23, 2022
GLSL optimizer based on Mesa's GLSL compiler. Used to be used in Unity for mobile shader optimization.

GLSL optimizer ⚠️ As of mid-2016, the project is unlikely to have any significant developments. At Unity we are moving to a different shader compilati

Aras Pranckevičius 1.5k Jun 23, 2022
Unified Gaussian Preintegrated Measurements (UGPMs)

This repository provides the C++ implementation of the preintegration methods presented in our RSS'21 paper titled Continuous Integration over SO(3) for IMU Preintegration (with video here ). If you are using that code for any purpose, please cite the corresponding work as explained at the end of this page.

Centre for Autonomous Systems, University of Technology Sydney 58 Jun 28, 2022
Embox is a configurable RTOS designed for resource constrained and embedded systems

Embox is a configurable RTOS designed for resource constrained and embedded systems. Embox main idea is using Linux software without Linux.

Embox 820 Jun 24, 2022
CML - The Configurable Math Library

Configurable Math Library For CML version 1, please see https://github.com/demianmnave/CML1. License The Configurable Math Library (CML) is released u

null 79 Jun 10, 2022
Randomized configurable bodies for Skyrim: Anniversary Edition

autoBody AE A SKSE Plugin for distributing CBBE and HIMBO presets throughout the gameworld Configurable through morphs.ini files (optionally created b

null 9 May 28, 2022
A configurable in-memory binary patcher.

?? Lyptus ?? A configurable in-memory binary patcher. ?? Usage Set up the Lyptus config with a list of patches to apply, and inject the Lyptus DLL int

null 11 Jun 5, 2022
An example spatial lookup service. In-memory reverse geocode backed by GEOS.

Spatial Lookup Web Service This GEOS example program demonstrates the use of the STRtree index and PreparedGeometry to create a high-performance in-me

Paul Ramsey 27 May 6, 2022
A cross-platform framework for developing spatial audio algorithms and software in C/C++

git: https://github.com/leomccormack/Spatial_Audio_Framework doxygen: https://leomccormack.github.io/Spatial_Audio_Framework/ About The Spatial_Audio_

Leo McCormack 339 Jun 21, 2022
this is my simple voxel engine, appart from librairies like glad it is entierly written in C++ and GLSL

simple-voxel-raycaster this is my simple voxel engine, appart from librairies like glad it is entierly written in C++ and GLSL here is a gif: https://

null 1 Jun 4, 2022
glsl code blocks for org-mode

GLSL code blocks for Emacs Org-mode This org-mode extension adds the capability to run GLSL code blocks directly from inside Emacs and immediately dis

null 27 Jun 14, 2022
VSIX Project that provides GLSL language integration.

GLSL language integration (for VS2017, 2019 and 2022) Download this extension from Visual Studio Marketplace version VS2017 & 2019 or VS 2022 preview

Daniel Scherzer 193 Jun 22, 2022
HLSL Parser and Translator for HLSL, GLSL, and MSL.

HLSLParser This is a fork of Unknownworld's hlslparser adapted to our needs in The Witness. We currently use it to translate pseudo-HLSL shaders (usin

null 2 May 19, 2020
HLSL to GLSL language translator based on ATI's HLSL2GLSL. Used in Unity.

HLSL to GLSL shader language translator ⚠️ As of mid-2016, the project is unlikely to have any significant developments. At Unity we are moving to a d

Aras Pranckevičius 512 Jun 21, 2022
HLSL Parser and Translator for HLSL, GLSL, and MSL.

HLSLParser This is a fork of Unknownworld's hlslparser adapted to our needs in The Witness. We currently use it to translate pseudo-HLSL shaders (usin

null 310 May 28, 2022
Simple printf functionality for GLSL.

Simple printf functionality for GLSL. This library is a simple proof of concept of using printf directly from a shader. The main point of being able

null 200 Jun 19, 2022
Minify and obfuscate GLSL or HLSL code

Shader Minifier Shader Minifier is a tool that minifies and obfuscates shader code (GLSL and HLSL). Its original use-case is for the demoscene, for op

Laurent Le Brun 219 Jun 23, 2022