# Cuda median filer performance

**URL:** <https://forum.opencv.org/t/cuda-median-filer-performance/20318>\
**Category:** C++\
**Tags:** cuda\
**Created:** [February 23, 2025, 6:31pm UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318 "2025-02-23T18:31:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![drdgcc](https://avatars.discourse-cdn.com/v4/letter/d/bc79bd/32.png) [@drdgcc](https://forum.opencv.org/u/drdgcc)\
**Post date:** [February 23, 2025, 6:31pm UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318/1 "2025-02-23T18:31:13Z")

</div>

I am applying a 5x5 median filter using the cuda library and getting quite poor results. I wrote my own 5x5 function and reduced the time by a quarter.

It seems that the opencv uses the histogram technique (I think) this is fast but maybe isn’t best for cuda which doesn’t like different code paths (i.e. if statements and the like). My method was to code up a sorting network, which has almost no variation in code paths, maybe opencv should try this?

---

<div class="post-metadata">

**Author:** ![cudawarped](https://avatars.discourse-cdn.com/v4/letter/c/9dc877/32.png) [@cudawarped](https://forum.opencv.org/u/cudawarped)\
**Post date:** [February 23, 2025, 6:56pm UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318/2 "2025-02-23T18:56:33Z")

</div>

I haven’t tested it but he latest version of OpenCV should be using a wavelet based approach.

> <https://github.com/opencv/opencv_contrib/pull/3627>
>
> I replaced the existing CUDA implementation of the histogram-based median filter… with an implementation of a new wavelet matrix-based median filter algorithm, which I presented at SIGGRAPH Asia 2022.
> This paper won the Best Paper Award in the journal track of technical papers (ACM Transactions on Graphics).
> 
> This new algorithm, like the histogram method, has the property that the window radius does not affect the computation time, and is several times faster than the histogram method. Furthermore, while the histogram method does not support HDR and only supports 8U images, this new algorithm supports HDR and also supports 16U and 32F images.
> 
> I (the author) have published the implementation on my personal GitHub and made some modifications for OpenCV to make it accessible from OpenCV. I used the CUB library, which is part of the standard toolkit since CUDA 11.0. Therefore, depending on the CUDA\_VERSION, the code is written to use the new algorithm for versions 11.0 and above, and the existing histogram method for versions 10 and below.
> 
> Regarding the old histogram-based code, the CPU version of the median filter supports 16U and 32F for window sizes up to 5, but it seems that the histogram CUDA version of the median filter does not. Also, the number of channels supported is different: the CPU version supports 1, 3, and 4 channels, while the CUDA version supports only 1 channel. In addition, for the CUDA version of the histogram method, pixels at the edges of the image, i.e. where the window is insufficient, were set to zero. For example, if the window size is 7, the width of the 3 pixels at the top, bottom, left, and right were not calculated correctly. When checking the tests, it was found that they compared with the CPU version by cropping the edges with rect, and also the cropping area was too wide, with 8 pixels cropped from the top, bottom, left, and right when the window size was 7.
> 
> In this PR, I first corrected the rect range for the tests so that both the old histogram method and the new wavelet matrix method can pass. Also, the CUDA version now supports 16U, 32F, and multi-channel formats such as 3 and 4 channels. In addition, while the CPU version only supports window sizes up to 5 for HDR, the new CUDA Wavelet Matrix method supports sizes of 7 and above. Additionally, I have added new tests for 16U, 32F, and multi-channel formats, specifically 3 and 4 channels.
> 
> 
> Paper’s project page: \[Constant Time Median Filter using 2D Wavelet Matrix | Interactive Graphics & Engineering Lab\](https://cgenglab.github.io/en/publication/sigga22\_wmatrix\_median/)
> My implementation (as author): \[GitHub - TumoiYorozu/WMatrixMedian\](https://github.com/TumoiYorozu/WMatrixMedian)
> 
> 
> 
> 
> \### Pull Request Readiness Checklist
> 
> See details at https://github.com/opencv/opencv/wiki/How\_to\_contribute#making-a-good-pull-request
> 
> \- \[x\] I agree to contribute to the project under Apache 2 License.
> \- \[x\] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
> \- \[x\] The PR is proposed to the proper branch
> ~~- \[\] There is a reference to the original bug report and related work~~
> \- \[x\] There is accuracy test, performance test and test data in opencv\_extra repository, if applicable
> Patch to opencv\_extra has the same branch name.
> \- \[x\] The feature is well documented and sample code can be built with the project CMake

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [February 24, 2025, 11:36am UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318/3 "2025-02-24T11:36:49Z")

</div>

usually with filters, cuda or not, you’ve got smart “good complexity” (e.g. constant time) but slow implementations for huge kernel sizes, and dumb “bad complexity” (n², n³, or worse…) but fast special cases for small kernel sizes. each will trump the other in their intended kernel sizes. a generic implementation would then pick (dispatch to) one or the other, depending on the actual kernel size,

sometimes there is just one implementation, or the decision thresholds are decided on one system and don’t quite fit another system.

since you were able to reduce “the time by a quarter”, maybe you’d like to contribute a special case implementation… that is, if you can beat the wavelet thing at 5x5

---

<div class="post-metadata">

**Author:** ![drdgcc](https://avatars.discourse-cdn.com/v4/letter/d/bc79bd/32.png) [@drdgcc](https://forum.opencv.org/u/drdgcc)\
**Post date:** [February 26, 2025, 10:06pm UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318/4 "2025-02-26T22:06:05Z")

</div>

I may tidy the and post it here. I admit sorting networks are not very flexible and fit the “small custom kernel” stereotype. But data heavy and code light techniques seems to be a good fit for Cuda.  
(Here small are is probably under 9x9.)

p.s. No doubt the minute I post it, someone will point out how wrong it is. I am too old to expect less. 🙂

---

<div class="post-metadata">

**Author:** ![drdgcc](https://avatars.discourse-cdn.com/v4/letter/d/bc79bd/32.png) [@drdgcc](https://forum.opencv.org/u/drdgcc)\
**Post date:** [February 27, 2025, 10:17pm UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318/5 "2025-02-27T22:17:32Z")

</div>

Can’t attach file to the post, don’t really want to drop 20k of code here (mostly tables) unless that’s the only way!

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [February 27, 2025, 10:47pm UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318/6 "2025-02-27T22:47:17Z")

</div>

dropping it here won’t do much good, except to get it “out there” at all.

if you think it’s a good idea to incorporate into the library, you could open an issue for discussion leading to a pull request, or jump right to the PR.

if the code for a 5x5 median filter requires 20k of code, maybe I misunderstood what you did there.

---

<div class="post-metadata">

**Author:** ![drdgcc](https://avatars.discourse-cdn.com/v4/letter/d/bc79bd/32.png) [@drdgcc](https://forum.opencv.org/u/drdgcc)\
**Post date:** [February 28, 2025, 5:04pm UTC](https://forum.opencv.org/t/cuda-median-filer-performance/20318/7 "2025-02-28T17:04:41Z")

</div>

I implemented filters for 2x2 to 9x9 median filters, for the 9x9 that’s 700 swaps for the 3x3 that’s 20 swaps. The time to do the all swaps is very fast under cuda as all the cores are always in parallel (but each one doing lots swaps for each pixel). 5x5 is about 100 swaps. These swaps form a sorting network and it is these which take up the lines of code. In actual space, they are byte table, so to do a 9x9 is about a 1.5k table of bytes.

* * *

To find the median of four numbers:-

```auto
int data [4] = { what ever }
const uint8_t median_network4[] = {
0,2, 1,3, 0,1, 2,3, 1,2, 255 }; // <-- these explode in size as inputs increases

uint * sort = median_network4; // fixed code for all sizes, but iterations increase
while( *sort != 255 )
{
      int tmp = data[*sort];
      data[*sort] = max (data[*sort], data[*(sort+1)] );
      data[*(sort+1)] = min(tmp, data[*(sort+1)] );
      sort +=2;
}

int median = (data[2] + data[1])/2;

```
