Fast hardware image blur lazarus / 39-Graphics ---------------------------------------------------------------------- aradeonas · 2015-10-15 16:32 Hi, I want to do fast blur so I need hardware acceleration, for this I found these sources but I dont know how to do it in FPC with OpenGL or OpenCL with or without BGRABitmap. http://www.eriksmistad.no/gaussian-blur-using-opencl-and-the-built-in- images-textures/ https://software.intel.com/en-us/blogs/2014/07/15/an-investigation-of- fast-real-time-gpu-based-image-blur-algorithms ---------------------------------------------------------------------- ChrisR · 2016-05-30 20:41 You can do a blur easily on the CPU. The trick is that the 2D Gaussian blur is separable: a 2D blur can be computed much faster as two 1D blurs instead of an integrated 2D blur (and a 3D blur is much faster when computed as three 1D blurs). When you know this trick, you can get good performance using just the CPU for all but the largest images   http://blog.ivank.net/fastest-gaussian-blur.html   http://www.cabiatl.com/mricro/bounty/   http://mantis.freepascal.org/view.php?id=10275 For very large images, the GPU will be faster. However, remember that transfers from main memory to the GPU is slow, so if you are using OpenGL on the GPU to display your images you will certainly benefit from using the GPU to blur, but if you want to move the image back to the CPU to use a library like BBRABitmap you may find that it is hard to see a huge speedup with the GPU (since you will have to both copy the raw data to the GPU and then retrieve the blurred data). If you want to go this route, I would recommend GLSL rather than OpenCL. This reason is that many older graphics drivers do not support OpenCL and it is harder to get this to work on all platforms. The code I wrote uses GLSL and works on Intel/NVidia/AMD cards with Windows/Linux/OSX. The shaders kSmoothShaderFrag  and kSobelShaderFrag demonstrate how to call GLSL from Lazarus/FPC/Delphi to blur and blur/edgedetect a 3D image. These would be a good starting point for a 2D blur.   https://github.com/neurolabusc/MRIcroGL/blob/master/raycastglsl.pas ---------------------------------------------------------------------- aradeonas · 2016-05-31 07:20 Thank you very much for a useful answer Do you have a performance test that how much time it gets for a simple blur in you machine with or without OpenGL? About MRIcroGL, What it does? and in that unit I see functions that seem to do blur, is that right? is there any demo to give me a easier start point? I'm new in this field About OpenCL, how old machines dont support it? If they are much old I dont care about that if the OpenCL results is better than GLSL (they are?) ---------------------------------------------------------------------- circular · 2016-05-31 11:49 Hello! Regarding software blur, in the latest versions of BGRABitmap, the fast blur it is done using the something similar to algorithm 4 described on http://blog.ivank.net/fastest-gaussian-blur.html To do a "hardware" blur, basically the idea is the following (using TBGLVirtualScreen): in the OnLoadTexture event, create the shader (it takes time to create a shader)   --> create a TBGLShader3D that does the blur (you may need to derive the class to add "variables")in the OnRedraw event, draw a texture with the shader   --> assign the shader to BGLCanvas.Lighting.ActiveShader   --> draw a texture by calling its Draw function or draw a shape   --> assign nil to BGLCanvas.Lighting.ActiveShaderin the OnUnloadTexture event, free the shader Here attached is a sample project for a shader (here it flips the image vertically). ---------------------------------------------------------------------- aradeonas · 2016-05-31 12:34 Hi Circular and thank you for the demo, I didnt know BGRABitmap can do these stuff this easily . I will play with it more but I can understand  whet you said about blur "that does the blur (you may need to derive the class to add "variables")". Also please add a simple demo when you add an ability. complicated demo is complicated and they are good for showing power not how to do that. Doing that is easier than making documentation and also Im sure you make self test project and probably you can put them in tests folder with some cleaning. About blur speed, I tested again BGRABitmap blur and used image from the linked page and in Normal mode with r=10 it takes 700ms in my system (that is not old) and in Fast mode it takes 90 ms. Are you sure it is optimized like that or my machine is heavily slow? (I checked your code and it seems like that but I cant understand why is there such a huge difference) ---------------------------------------------------------------------- ChrisR · 2016-05-31 13:10 My sense is the example from Circular is a great starting point. If you create a blur shader using TBGLVirtualScreen I think it would be useful for a lot of users. My own MRIcroGL is tuned as a 3D volume renderer, rather than a general purpose rendering tool. Since you ask, MRIcroGL uses GLSL for the volume rendering but it can also use GLSL for hardware accelerated computation of image gradients.   http://www.mccauslandcenter.sc.edu/mricrogl/gradients With MRIcroGL the user can set the preferences to either calculate the gradients on the CPU or the GPU. The relative benefit really depends on the quality of the GPU and the CPU, but modern Intel graphics seem about x8 faster on the GPU than on the Intel CPU, with a bigger benefit if you have a dedicated Nvidia or AMD GPU. For writing your shader, I would suggest reading this article:   https://developer.apple.com/library/mac/documentation/Performance/Co nceptual/OpenCL_MacProgGuide/TuningPerformanceOntheGPU/TuningPerforman ceOntheGPU.html ---------------------------------------------------------------------- circular · 2016-05-31 13:35 Quote from: aradeonas on May 31, 2016, 02:34:53 pmHi Circular and thank you for the demo, I didnt know BGRABitmap can do these stuff this easily . I will play with it more but I can understand  whet you said about blur "that does the blur (you may need to derive the class to add "variables")".Cool. QuoteAlso please add a simple demo when you add an abilityYes. QuoteAbout blur speed, I tested again BGRABitmap blur and used image from the linked page and in Normal mode with r=10 it takes 700ms in my system (that is not old) and in Fast mode it takes 90 ms. Are you sure it is optimized like that or my machine is heavily slow? (I checked your code and it seems like that but I cant understand why is there such a huge difference)In Normal mode, it doesn't use the optimisation with box blurs. Only fast blur with radius >= 10 does. ---------------------------------------------------------------------- aradeonas · 2016-05-31 13:56 Thank you ChrisR. circular I had a typo : I can't understand what you said about blur "that does the blur (you may need to derive the class to add "variables")". QuoteIn Normal mode, it doesn't use the optimisation with box blurs. Only fast blur with radius >= 10 does.I just tested and it takes 62ms for r=9 and 90 for r=11. it seems not not to me it has a much difference and I expect faster result. ---------------------------------------------------------------------- circular · 2016-05-31 15:40 QuoteI can't understand what you said about blur "that does the blur (you may need to derive the class to add "variables")".Oh ok. I suggest to look at the example I posted, and look at the GLSL files. There is the code for the shader. And that's where you would need to put some other code. The GLSL code is related to a TBGLShader3D class. In the example it is defined in umyshader.pas. The uniform variables are like parameters that are transmitted to the GLSL code. They are defined both in the class and in the GLSL (in mix.fragment.glsl). For example the blur radius would be a uniform variable, like the fade_factor in the example. QuoteI just tested and it takes 62ms for r=9 and 90 for r=11. it seems not not to me it has a much difference and I expect faster result.Surprising. Well the fast blur without box blur is already optimized so the difference is not that big with a small radius. The difference is significant with a radius like 80 for example. To see the difference, you would need to comment out the "if" block in the fast blur where it calls the box blur. After that, you can try to call box blur directly. Maybe the box blur could be optimized? ---------------------------------------------------------------------- aradeonas · 2016-10-03 08:25 Hi circular, I totally forgot this topic and today I tried to test my version but I coulnt port such thing to your demo, it is more complicated and I dont know about them: http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with- linear-sampling/ Can you help me with that? and also please include previous example with BGRA, its good to have these samples as reference. ---------------------------------------------------------------------- circular · 2016-10-03 09:55 To do this example, you only need to change the code in mix.fragment.glsl file. Some variables need to be replaced: "image" becomes "textures[0]" (what the application refers to) "FragmentColor" becomes "gl_FragColor" because the GLSL variable is used instead of using an output variable. "gl_FragCoord" becomes "texcoord" (what the vertex shader yields). So you would get something like: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uniform float fade_factor;uniform sampler2D textures[1]; varying vec2 texcoord; uniform float offset[5] = float[]( 0.0, 1.0, 2.0, 3.0, 4.0 );uniform float weight[5] = float[]( 0.2270270270, 0.1945945946, 0.1216216216,                                   0.0540540541, 0.0162162162 ); uniform float textureHeight = 200;                                                                                                                                       void main(){        gl_FragColor = texture2D(textures[0], texcoord) * weight[0];        for (int i=1; i<5; i++) {                gl_FragColor +=                      texture2D(textures[0], vec2(texcoord)+vec2(0.0, offset[i]/textureHeight) )                                * weight[i];                gl_FragColor +=                        texture2D(textures[0], vec2(texcoord)-vec2(0.0, offset[i]/textureHeight) )                                * weight[i];        }          // use the fade factor to choose the level of blur        gl_FragColor = gl_FragColor*fade_factor + texture2D(textures[0], texcoord)*(1 - fade_factor);} ---------------------------------------------------------------------- aradeonas · 2016-10-03 10:25 Thank you very much! It made it more clear for me. I tested it and result is fast but I coulnt make the blur more strong. This post seems a good one and I wanted to do such thing like sample in the post or like this implemention: https://github.com/Jam3/glsl-fast-gaussian-blur What is your opinion abut this way? Is it good? ---------------------------------------------------------------------- circular · 2016-10-03 10:46 The level of blur here via fade_factor is just from non-blurred to blurred. It does not go further. For a wider blur, there would be more coefficients of course. Note that this is not the optimised version using the linear interpolation. That's would be the second example of http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with- linear-sampling/ and I leave that to you. Also the blur here is one-dimensional. You can make it two dimensional, but that requires two "for" loops, that's slower obviously. In principle, Guassian blur can be done in two passes, one horizontal and one vertical but that would require to store a temporary image that is blurred in one direction. Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uniform float fade_factor;uniform sampler2D textures[1]; varying vec2 texcoord; uniform float offset[5] = float[]( 0.0, 1.0, 2.0, 3.0, 4.0 );uniform float weight[5] = float[]( 0.2270270270, 0.1945945946, 0.1216216216,                                   0.0540540541, 0.0162162162 ); uniform float textureWidth = 320;uniform float textureHeight = 200;                                                                       void main(){    float w;    gl_FragColor = vec4(0);    for (int y = 0; y < 5; y++) {    for (int x = 0; x < 5; x++) {        w = weight[x]*weight[y];        gl_FragColor += texture2D(textures[0], vec2(texcoord)+vec2(offset[x]/textureWidth, offset[y]/textureHeight) ) * w;        if (x > 0)            gl_FragColor += texture2D(textures[0], vec2(texcoord)+vec2(-offset[x]/textureWidth, offset[y]/textureHeight) ) * w;        if (y > 0)        {            gl_FragColor += texture2D(textures[0], vec2(texcoord)+vec2(offset[x]/textureWidth, -offset[y]/textureHeight) ) * w;            if (x > 0)                gl_FragColor += texture2D(textures[0], vec2(texcoord)+vec2(-offset[x]/textureWidth, -offset[y]/textureHeight) ) * w;        }    }    }     // use the fade factor to choose the level of blur    gl_FragColor = gl_FragColor*fade_factor + texture2D(textures[0], texcoord)*(1 - fade_factor);} On the page https://github.com/Jam3/glsl-fast-gaussian-blur the algorithm is also one-dimensional. It needs to be called twice to get a regular blur (two-dimensional). I wonder if that would be doable by rendering the texture first in a framebuffer with the blur in one direction and then displaying from that framebuffer while applying the blur in the other direction. ---------------------------------------------------------------------- aradeonas · 2016-10-03 11:15 Thanks. So I should learn this way and make a better version of it. ---------------------------------------------------------------------- aradeonas · 2016-10-03 12:41 I am learning GLSL as I didnt knew it before. Im reading the code too and here : Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i                       for (int i=1; i