C / C ++中的快速7x7 2D中值滤波器

时间:2016-02-23 11:25:06

标签: c++ c opencv image-processing simd

我正在尝试将以下代码从matlab转换为c ++

function data = process(data)
    data = medfilt2(data, [7 7], 'symmetric');
    mask = fspecial('gaussian', [35 35], 12);
    data = imfilter(data, mask, 'replicate', 'same');
    maximum = max(data(:));
    data = 1 ./ ( data/maximum );
    data(data > 10) = 16;
end

我在medfilt2中的问题 - 这是一个2D中值滤波器,我需要它支持每像素10位和更多图像。

1.我研究过openCV它有一个5x5中值滤波器,支持16位,但7x7只支持字节。

http://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html?highlight=medianblur#medianblur

2.我也有,看看英特尔IPP,但我只能看到一维中值滤波器 https://software.intel.com/en-us/node/502283

2D滤镜是否有快速实施?
寻找类似的东西:

  1. Fast Median Search: An ANSI C Implementation使用并行编程和矢量化(AVX / SSE)操作......
  2. 二维数字信号处理II。变换和中值滤波器。 由T.S.Huang编辑。施普林格出版社。 1981。
  3. FAST MEDIAN FILTERING WITH IMPLEMENTATIONS IN C/C++/C#/VB.NET/Delphi中有更多代码示例。

    我还找到了Median Filtering in Constant Time

2 个答案:

答案 0 :(得分:6)

由于OpenCV没有为大内核大小(大于5)实现16位中值滤波器,我尝试了三种不同的策略。

所有这些都基于Huang的[2]滑动窗口算法。也就是说,当窗口从左向右滑动时,通过移除和插入像素条目来更新直方图。这对于8位图像来说非常简单,并且已经在OpenCV中实现。但是,大的65536 bin直方图使计算有点困难。

  

...算法仍然保持为O(log r),但存储注意事项使其对16位图像不实用,对浮点图像不可能。 [3]

我在适用的地方使用了algorithm C ++标准库,并没有实现Weiss'其他优化策略。

1)一种天真的排序实现。我认为这是任意像素类型的最佳起点(特别是浮动)。

// copy pixels in the sliding window to a temporary vec and
// compute the median value (size is always odd)
memcpy( &v[0], &window[0], window.size() * sizeof(_Type) );
std::vector< _Type >::iterator it = v.begin() + v.size()/2;
std::nth_element( v.begin(), it, v.end() );
return *it;

2)稀疏直方图。我们不想跨越65536个箱来找到每个像素的中位数,那么如何存储稀疏直方图呢?同样,这适用于所有像素类型,但如果窗口中的所有像素都不同(例如浮点数),它就没有意义。

typedef std::map< _Type, int > Map;
//...
// inside the sliding window, update the histogram as follows
for ( /* pixels to remove */ )
{
    // _Type px
    Map::iterator it = map.find( px );
    if ( it->second > 1 )
        it->second -= 1;
    else
        map.erase( it );
}
// ...
for ( /* pixels to add */ )
{
    // _Type px
    Map::iterator lower = map.lower_bound( px );
    if ( lower != map.end() && lower->first == px )
        lower->second += 1;
    else
        map.insert( lower, std::pair<_Type,int>( px, 1 ) );
}
//... and compute the median by integrating from the one end until
// until the appropriate sum is reached ..

3)密集的直方图。所以这是密集的直方图,但是我们不是简单的65536数组,而是通过将搜索划分为子区域来使搜索更容易,例如:

[0...65535] <- px
[0...4095] <- px / 16
[0...255] <- px / 256
[0...15] <- px / 4096

这使插入速度变慢(按常数时间),但搜索速度要快得多。我找到了16个很好的数字。

comparison

我测试了方法(1)红色,(2)蓝色和(3)黑色相互对比和8bpp OpenCV(绿色)。除OpenCV外,输入图像均为16-bpp灰度。虚线在动态范围[0,255]处被截断,平滑线在[0,8020]被截断(通过乘以16并平滑以在像素值上添加更多方差)。

有趣的是随着像素值的方差增加,稀疏直方图的偏差。 Nth-element总是安全的,OpenCV是最快的(如果8bpp没问题),密集的直方图落后。

我使用的是Windows 7,8 x 3.4 GHz和Visual Studio v.10。我的运行是多线程的,OpenCV实现是单线程的。输入图像大小2136x3201(http://i.imgur.com/gg9Z2aB.jpg,来自Vogue)。

[2]:Huang,T:&#34;二维信号处理II:变换 和中位数滤波器&#34;,1981

[3]:Weiss,B:&#34; Fast median and Bilateral Filtering&#34;,2006

答案 1 :(得分:1)

我在网上找到了这个,它与OpenCV的算法相同,但扩展到16位并优化为SSE。

https://github.com/aoles/EBImage/blob/master/src/medianFilter.c