mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 04:43:22 -05:00
imgproc: support arbitrary channel counts in medianBlur #29638 ## Summary Fixes #29592. `cv::medianBlur`/`cv2.medianBlur` rejects `CV_8U` images with channel counts other than 1, 3, or 4 whenever the optimized large-kernel path is needed — `ksize >= 7` always, and `ksize == 5` on SIMD-enabled builds (the `ksize == 3`/`ksize == 5`-without-SIMD "sort net" path already handles arbitrary channel counts generically, so this only affects the fast path): ``` src.depth() == CV_8U && (cn == 1 || cn == 3 || cn == 4) ``` Median filtering is channel-independent, so there's no correctness reason for this restriction — it's an implementation detail of the optimized SIMD kernels (which hard-code 1/3/4-channel-interleaved layouts), not a property of the algorithm. Users with 2, 5, 6, 9+ channel images (multispectral, feature maps, stacked masks) currently have to split, filter, and re-concatenate manually outside the library — exactly the workaround already implemented downstream in Albucore, per the issue. ## Fix In `cv::medianBlur` (`modules/imgproc/src/median_blur.dispatch.cpp`), before dispatching to HAL/OpenCL/the optimized SIMD path: if the channel count isn't 1, 3, or 4, split the image into individual channels, run `medianBlur` on each one independently (a single channel is always supported by every existing path, recursively), and merge the results back together. This touches none of the performance-critical kernels — it's a fallback that only runs for channel counts those kernels don't support, and the existing 1/3/4-channel fast paths are completely unaffected. ## Test plan - [x] Added `Imgproc_MedianBlur.arbitrary_channel_count_29592` in `modules/imgproc/test/test_filter.cpp`, covering channel counts `{1,2,3,4,5,6,9}` × kernel sizes `{3,5,7,9}`. For each combination it asserts `medianBlur` doesn't throw, preserves size/type, and — critically — produces output bit-identical to filtering each channel independently via `cv::split`/`cv::merge` (the reference/expected behavior). - [x] Built `opencv_core` + `opencv_imgproc` + `opencv_test_imgproc` locally (MSVC) and ran the new test — passes. - [x] Ran the full existing `Imgproc_MedianBlur.*`, `Imgproc_Filter2D.*`, `Imgproc_Blur.*`, `Imgproc_GaussianBlur.*` suites — all 14 pass, no regressions. - Note: `GaussianBlurVsBitexact`, `sepFilter2D_types`, and `StackBlur` tests in the same binary fail/crash in this local environment, but reproduce identically on unmodified `4.x` with no changes at all — confirmed pre-existing and unrelated to this change (not investigated further, out of scope here).