-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Faster Gaussian blur implementation for PhotoModularFX #4
Comments
Thank you, I'll see. |
200 px radius. (So sorry that I forgot to mention this in the first post!) |
I removed some unnecessary IFs |
I translated gaussianiir2d from your link http://www.getreuer.info/home/gaussianiir About license , (If I decide to put this update) do I have to mention that link somewhere ? PS: |
Nice work!! Fast gaussian blur is really helpful for many things, so I think it is a good one to optimize, and IIR is a great technique for this. (For example, I use gaussian blur at large radius for shadow/highlight correction - if you blend the result with the original image, using different blend modes, you can get many useful effects.)
At the link, he says the code is licensed by Simplified BSD license. This is one of the easiest open-source licenses (https://opensource.org/licenses/bsd-license.html). You can just put some text in your instruction manual, I think - from the link:
|
Updated with Gaussian IIR [Modules] https://miorsoft.github.io/Site/PhotoModularFX/PhotoModularFX.zip |
I need a fast Bilateral now. Then I found Tanner's useful link on my vbForums page: Fast O(1) bilateral filtering using trigonometric range kernels Tanner, did you implement it ? |
Sorry that I have not had time to try your new Fast Blur implementation! I have been really busy and had not had time for VB6 stuff for many weeks... Unfortunately, I have not implemented trigonometric range kernel bilateral filtering. :( I don't understand all the math involved, either. I think they do have a source code implementation available here: http://bigwww.epfl.ch/algorithms/bilateral-filter/ It is implemented as an ImageJ plugin, but maybe there is enough code to get started? I am happy to help if I can find some free time. One thing I did to improve bilateral performance in PhotoDemon is offer a "Fast" separable option (like gaussian blur). If you run the bilateral filter in the horizontal direction, then run the filter in the vertical direction, it only takes O(w + h) time instead of O(w * h). The results are not exactly the same (because the algorithm is not technically separable) but they are close, and for large radii especially the visual difference is not too noticeable. On a 10 megapixel photo, bilateral filter radius 25 takes about 11 seconds separable, compared to 240 seconds in regular mode. So for me, this is a good trade-off. Maybe it's an easier thing to try first? |
Tanner, if you'd like to implement Possion Disc sampling |
Wow, great link!! That is a beautiful visualization, very easy to understand and follow. Thank you for sharing the screenshots of your results; the large radius looks very good to me. I would need to study the algorithm further to know if the small radii result is expected, or if something else is wrong. (Many approximation algorithms seem to have mixed results at small radii, so it's entirely possible that the small radius problem lies with the algorithm itself.) I have used Voronoi diagrams before (for "Stained Glass" and "Crystallize" effects) and it is interesting to see a similar approach for sampling. I would like to investigate Bridson's algorithm further for my own code - thank you for showing it to me. I have used some fixed supersampling techniques before (for example, all Distort tools in PhotoDemon require it), but they are much simpler than Bridson's algorithm, and probably not as high-quality. Re: separable bilateral, I have not noticed problems in my own work with it, but maybe I have not studied it closely? For example, here is my result on your sample image from above, with the displayed settings (the "use estimation" checkbox toggles separable vs standard algorithm): They look very close to my eye, but it is always possible that I have missed something in my implementation. (Or maybe, a certain combination of settings causes bad results?) I just mention this in case you notice something I didn't, or maybe there are different ways to implement separable bilateral, with varying results! Either way, if you would like me to test any of these updates for you, please let me know. It may take me a few days but I am always happy to help. Congratulations on your great work on this topic. |
Thank you very much Tanner. About Separable, Yes, I was wrong, it is not so bad, I noticed it too in my algorithm. I'm curious about your 2 parameters : "Color Strenght" and "Color Preservation", Another algorithm I try to implement without success is this: |
You're right, I did miss that! Thank you for the clarification. I apologize for not reading your original post carefully.
Sometimes I try to create names that are easier for users to understand, even if they don't have a technical background. These parameters are just basic adjustments that control the kernel used for intensity differences - e.g., to build a lookup table for RGB colors on the byte range [0, 255]:
The full source is here.
That looks like a very interesting algorithm, especially running in real-time on HD video! I will download the PDF and study it more closely. Thank you for the link. |
About bilateral I found an interesting code. It is in C If you could understand something, let me know. |
Hi @miorsoft, sorry that it has taken me so long to reply. I have been on paternity leave with my new baby girl. I return to work this month and will hopefully have time for VB hobbies again. Congratulations on your custom-built edge-preserving smoothing filter! I am always impressed by time-invariant implementations of complicated filters. It looks like you have done a great job. I am excited to run some tests on it when the next version of PMFX releases. |
hi ! ORIGINAL |
@tannerhelland BTW First of all Click "Add FX-Module" Button Then click the Module you are interested to. Finally you can Enable/Disable the projects Filter ( to display only the projects that contains selected Node or All projects ) (First time of filtering may take a while for intensive disk access ) ... waiting to know what you think of these modules. |
👍 Looks like you've done a great job on this, @miorsoft. When iterations are 4+, the horizontal and vertical banding is barely noticeable, and performance remains very good, even on large images. Adding diagonals further improves the results, without too much of a performance hit. Do you plan to publish details on your algorithm, or will it remain a "secret"? |
I will not publish the code, but I can give a small description of the FastEPS algorithm. Fast Edge Preserve Smoothing Filter Algorithm Description: Let's assume we work on a single channel (GrayScale). Well, the process consists of the following steps.
In this way the new value Very simple and effective isn't it ? Then there is the variant + Diagonals which practically does (and adds) the same operation along the diagonals in four directions. Honestly, I'm a little sorry to have opened it, it's a creature of mine, but what can I do with it? PS: @tannerhelland , do you have any suggestions about how I should behave to get this? |
Thank you for the comprehensive description, @miorsoft! It looks like a very fast and clever solution. Your description actually reminds me a lot of anisotropic diffusion: https://en.wikipedia.org/wiki/Anisotropic_diffusion . The similarity makes me wonder if you can use a "trick" of anisotropic diffusion in your own filter - if you reverse small aspects of the calculation, you can use the exact same code to intelligently sharpen an image along boundaries only. (I think you already have an anisotropic filter in your app? If not, I have VB code for it in PhotoDemon, or you can see the original paper on the topic: http://authors.library.caltech.edu/6498/1/PERieeetpami90.pdf )
For better or worse, it's not possible to copyright an algorithm "idea". This is why Adobe can put a feature in Photoshop, for example, and I can develop my own version of that feature in my software without consequence. You can, however, copyright the specific source code you use to accomplish something. It's a lot like books - you can't copyright the idea of "a fantasy book about hobbits and a magic ring", but if you actually wrote Lord of the Rings, you could copy that specific text. (Hopefully that makes sense.) If you want to protect something that is just an "idea", you have to apply for a patent. It's a much more complicated and expensive process. This link goes into more detail on copyright vs patents. I mostly ask for details on the algorithm because it is very difficult to offer constructive feedback without understanding the underlying algorithm. Otherwise, I just have to "guess" at what the code is doing, and I will probably guess wrong. (Also, maybe a Google search will lead other developers here, and you can get input from someone a lot more knowledgeable than me! :) Anyway, I think you have made great strides on a lot of different features lately. Nice work, and thanks for discussing these topics with me! |
Thank you very much! (it would be nice to talk about other alorithms too) Yes, my algorithm has a small similarity with anisotropic diffusion.
As I said, the algorithm is really very simple.
Similarly one can add diagonal passes and change it to perform 3 (4) channels at a time. (I know , pre calculating |
Thank you to @miorsoft for first recommending Poisson Disc sampling to me: miorsoft/Site#4 (comment) The original paper on Bridson's algorithm is just one page long, and easily understandable: https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf I wish more algorithms were this simple. I hope to use this class to accelerate some effects and adjustments that currently experience egregious slowdowns when large radii are used. Poisson disc sampling is cool for a lot of reasons, but one of the ones I'm most excited about is that you can easily mask the sample area to restrict the list of sampled points to an arbitrary geometric shape. PD could use this for something like a fast bokeh effect (hypothetically... let's see how it pans out in practice). Note that supersampling like this doesn't necessarily free a function from perf constraints tied to radius; instead, it greatly reduces the slope of the penalty associated with large r values. Specific effects (e.g. gaussian blur(s)) will still benefit from application-specific implementations.
Thank you to @miorsoft for first pointing me toward this constant-time recursive BF approach, which is the current "state-of-the-art" in bilateral filtering (miorsoft/Site#4 (comment)). This commit implements such a filter, and it entirely replaces the existing Effects > Blur > Surface Blur tool. (The old Effects > Noise > Bilateral filter is now redundant and has been removed.) PD's version of a recursive BF is adapted from the C++ implementation available here: https://github.com/ufoym/recursive-bf Thank you to the original author(s) for sharing their code under an MIT license. Translating the original function to VB6 was straightforward enough. What was not straightforward was the large number of surprise caveats with this particular approach. It's very fast, as promised (faster even than Photoshop, yay!), but I had to implement a worrisome amount of fixes to make it usable in a general context... 1) The original used a sigma interpretation different from standard BFs - it scales all sigmas against image dimensions! I've worked around this by entirely rewriting the way sigmas are handled - details are in the comments. 2) Higher sigma values were originally relatively useless because of severe vertical banding. (I built the original using VS 2019 and the results are identical, so it's not an issue with my translation, for better or worse.) This can be "fixed" by a combination of better sigma handling (see above) and simply limiting the maximum radius allowed, but it's an unfortunate caveat that is not easy to solve algorithmically. 3) The original is incompatible with 32-bpp source data, despite claiming to handle more than 3 channels. I've fixed this by adding alpha to the bilateral computation where required (and adjusting various offset calculations to match). 4) The original experienced noticeable distortion along the right side of the image, and formal issues were even reported on this in the original repo. I've also fixed this problem (comments in the code) and edges on all sides are now handled correctly. The end result is a fully functional bilateral filter than runs in comparable time to PD's standard gaussian blur tool (!!!). It's faster than any other open-source photo editor I've tested, typically by an order-of-magnitude or more. For example, Paint.NET takes ~70 seconds to render a 100px BF on a 20 megapixel image (using their Blur > Surface Blur which claims to be a bilateral filter). PhotoDemon's Effects > Noise > Bilateral Filter does the same thing in less than 6 seconds, despite being single-threaded and using no SIMD whatsoever. 👍 Anyway, I've also reworked the UI for PD's Blur > Surface Blur tool so that it now uses this new implementation exclusively. Thank you also to Roy K for an updated German localization!
Hi @miorsoft. I just wanted to drop by and let you know that I've recently translated the recursive bilateral filter you mentioned to VB6. Here is a link: https://github.com/tannerhelland/PhotoDemon/blob/master/Classes/pdFxBilateral.cls You can try it in PhotoDemon's latest nightly builds under the Effects > Blur > Surface blur menu, same as Photoshop. The performance of the recursive algorithm is excellent. On my old VB6 development PC, the function can process 3-4 megapixels of RGBA data per second. This outperforms Photoshop and most other photo editors by a significant margin. For example, applying a 100-radius bilateral filter to a 20-megapixel RGBA image takes ~70 seconds in Paint.NET, but less than 6 seconds in PhotoDemon. The filter is only an approximation of a true bilateral, obviously, but it is so much faster that it is hard to dislike it! If you are still looking for a fast bilateral filter implementation, I think the recursive approach is currently the best anyone can hope for. 👋 |
Thank you very much @tannerhelland ! I think the Bilateral is one of the most useful filter. In case I'll put here my progress-state. Thanks again, I can't wait to try it. PS: |
Now looking at your code. I don't remember well, probably my FastEPS is a simplification of the algorithm I managed to draw/understand from the code. (https://github.com/ufoym/recursive-bf) At a quick look the things I am missing are:
For sure your version appropriately manage Spatial and Range parameters. (hopefully maybe my code just need a little tweak) I'll dig in to it, EDIT:
That is:
but... I mean:
Another difference seems to me that I do it in the 4 directions at a time and then add them together |
At the moment I don't think I will change my code so much... |
Hi, brilliant discussion about fast implementation of Gaussian blur and Bilaterial filtering. I'm looking for a fast implementation of Gaussian Blur and notice the link @tannerhelland provided is lost. May you share your code in a new location? |
Hi @usherbob. I recently took a deep dive into this topic thanks to a dedicated user, and I currently think this paper by Pascal Getreuer is the ideal starting point for surveying gaussian blur strategies: http://www.ipol.im/pub/art/2013/87/ Getreuer is the same author of the broken link; in that paper he surveys multiple strategies and compares performance and accuracy. The anisotropic diffusion strategy I originally linked at the top of this page has a large error (10+% as a 3rd-order function). Based on Getreuer's paper, I changed to a recursive approach by Rachid Deriche, which has an error of less than 1% as a 3rd-order function, and less than 0.1% as a 4th-order, specifically this technique: https://hal.inria.fr/inria-00074778/document There are many trade-offs depending on your ultimate goal. Pascal Getreuer's paper is excellent for discussing all those trade-offs. Good luck! |
Thanks for your quick reply. I'll read these docs and better my code. |
hi @usherbob |
I notice that PMFX's current Gaussian Blur filter slows down significantly as radius increases. Since (I think?) PhotoModularFX works on floating-point data, it is a good candidate for an IIR implementation of Gaussian Blur, similar to what GIMP uses.
A nice BSD-licensed reference implementation is available here:
http://www.getreuer.info/home/gaussianiir
The original 1994 paper that inspired the approach is available here (free download):
https://www.researchgate.net/publication/236268568_Signal_and_Image_Restoration_Using_Shock_Filters_and_Anisotropic_Diffusion
On a 10-megapixel image (3872x2592), PMFX takes about 135 seconds to process a 3-channel gaussian blur. In PhotoDemon, IIR code very similar to the above project does the same thing in about 6 seconds, and that's including the overhead of moving all data from 8-bit integer RGB to 32-bit floating-point RGB and back again, plus processing a fourth channel (alpha )- so PMFX could be even faster, I think.
The text was updated successfully, but these errors were encountered: