Я пытаюсь преобразовать следующий код из 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. Я также смотрю на Intel IPP, но я вижу только одномерный медианный фильтр https://software.intel.com/en-us/node/502283

Есть ли быстрая реализация для 2D-фильтра?
ищу что-то вроде:

  1. Быстрый поиск медианы: реализация ANSI C с использованием параллельного программирования и векторизованных (AVX / SSE) операций ...
  2. Двумерная цифровая обработка сигналов II. Преобразования и медианные фильтры. Под редакцией Т.С. Хуана. Springer-Verlag. 1981 г.

Больше примеров кода можно найти в БЫСТРАЯ МЕДИАННАЯ ФИЛЬТРАЦИЯ С РЕАЛИЗАЦИЯМИ НА C / C ++ / C # / VB.NET / Delphi.

Я также нашел медианную фильтрацию в постоянное время.

3
Gilad 23 Фев 2016 в 14:25

2 ответа

Лучший ответ

Руководствуясь тем фактом, что OpenCV не реализует 16-битный медианный фильтр для больших размеров ядра (больше 5), я попробовал три разные стратегии.

Все они основаны на алгоритме скользящего окна Хуанга [2]. То есть гистограмма обновляется путем удаления и вставки записей пикселей по мере того, как окно перемещается слева направо. Это довольно просто для 8-битного изображения и уже реализовано в OpenCV. Однако большая гистограмма в 65536 бинов немного затрудняет вычисления.

... Алгоритм по-прежнему остается O (log r), но соображения хранения делают его непрактичным для 16-битных изображений и невозможным для изображений с плавающей запятой. [3]

Я использовал стандартную библиотеку C ++ algorithm там, где это возможно, и не реализовывал дополнительные стратегии оптимизации 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 бит на пиксель. Пунктирные линии усекаются в динамическом диапазоне [0,255], а плавные линии усекаются в диапазоне [0, 8020] (посредством умножения на 16 и сглаживания для увеличения дисперсии значений пикселей).

Интересным является расхождение разреженной гистограммы при увеличении разброса значений пикселей. N-й элемент всегда безопасен, OpenCV - самый быстрый (если 8bpp в порядке), а плотная гистограмма отстает.

Я использовал Windows 7, 8 x 3,4 ГГц и Visual Studio v. 10. Мои были многопоточными, реализация OpenCV однопоточная. Размер входного изображения 2136x3201 (http://i.imgur.com/gg9Z2aB.jpg, с Vogue).

[2]: Хуанг, Т: "Обработка двумерных сигналов II: преобразования и медианные фильтры", 1981

[3]: Вайс, B: «Быстрая медиана и двусторонняя фильтрация», 2006 г.

7
mainactual 26 Фев 2016 в 13:34

Я нашел это в Интернете, это тот же алгоритм, что и OpenCV, но расширенный до 16 бит и оптимизированный для SSE.

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

1
Gilad 12 Мар 2016 в 21:10