Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как сравнить все патчи на двух изображениях в Matlab?

Автор вопроса: akhilcОтветов: 2

У меня есть два изображения, скажем, A и B, размеры которых не обязательно должны быть одинаковыми. A иметь размер 255×255 и B иметь размер 100×100. А размер патча для моей задачи 5х5. Что мне нужно сделать, так это сравнить все патчи в A со всеми патчами в B.

Каждый патч будет перекрываться с некоторыми соседними патчами. Чтобы очистить эту точку, первым патчем в A будет A(1:5,1:5) (нотация MATLAB). Второй патч A(2:6,1:5) и так далее, вплоть до A(251:255,1:5) в конце первой строки и до A(251:255,251:255) для последнего патча в A.

Мне нужно сравнить каждое из этих исправлений с всеми исправлениями в B. Как видите, есть 251*251 патчей в A и 96*96 патчей в B. Так что есть много сравнений, которые нужно сделать. А сравнение - это просто евклидово расстояние, т. е. я просто возьму разность двух участков и суммирую квадраты. Для каждого сравнения патчей я получу в результате скалярное значение.

Я реализовал это в MATLAB, но выполнение занимает несколько минут. Поэтому, пожалуйста, предложите мне самый быстрый способ реализовать это. Этот раздел является узким местом во всем моем проекте. Код, который я написал, приведен ниже. Я не эксперт, так что, пожалуйста, простите за ошибки.

row = size(A,1);
col = size(A,2);

row2 = size(B,1);
col2 = size(B,2);

patch_long = zeros(5,5,(row2-4)*(col2-4));

idx = 1;

for i = 1:row2-4
    for j = 1:col2-4

        patch_long(:,:,idx) = B(i:i+4,j:j+4);

        idx = idx+1;

    end

end

%// I rearranged 'B' matrix as 3d matrix with each patch arranged like
%// slide behind one by one

parfor m = 1:row-4
    for n = 1:col-4

        temp1 = bsxfun(@minus,(A(m:m+4,n:n+4)),patch_long);
        temp2 = sum(sum(temp1.^2));

        count = sum(temp2 <=threshold);

        if count > 1
            % Do xyzend
        end

    end
end

%// count counts how many patches in 'B' are close to a particular patch in 'A'.
  • Вы на самом деле сделали хорошую векторизацию. Кажется, что это не может быть значительно улучшено. Рассмотрим алгоритмические улучшения. Мол, вам действительно нужно сравнивать ВСЕ патчи со ВСЕМИ? Mikhail 25.03.2014
  • У вас есть GPU с двойной точностью? А какая у вас версия MATLAB? Rody Oldenhuis 25.03.2014
  • Я не знаю о GPU. Моя версия Matlab 2012b. akhilc 25.03.2014
  • @RodyOldenhuis: вы имеете в виду, что я должен сначала написать "для столбцов", а затем "для строк" ​​при цикле? akhilc 25.03.2014
  • Что вы увидите, если наберете gpuDevice в командной строке? Rody Oldenhuis 25.03.2014
  • @RodyOldenhuis Я использую Matlab в Ubuntu. Когда я набрал gpuDevice, он показывает ошибку. Возникла проблема с драйвером CUDA, связанным с этим устройством GPU. Причина: Не удалось загрузить драйвер CUDA. Используемое имя библиотеки было "libcuda.so.1". Ошибка: libcuda.so.1: невозможно открыть общий объектный файл: нет такого файла или каталога akhilc 26.03.2014

matlaboptimizationimage-processingnearest-neighbor

Ответы

Ответ 1 · рейтинг 4 · Shai

Вы можете использовать im2col для извлечения всех исправлений.

pA = im2col( A, [5 5], 'sliding' );
pB = im2bol( B, [5 5], 'sliding' );
% compute squared difference
D = sum( bsxfun( @minus, permute( pA, [2 3 1] ), permute( pB, [3 2 1] ) ).^2, 3 );

Кстати, если вам не нужны ВСЕ расстояния и вы готовы пойти на компромисс для приближения для k ближайших соседей, вы можете найти PatchMatch очень полезен:
Это приблизительный алгоритм k ближайших соседей, адаптированный для патчей изображений. Он очень эффективен с точки зрения использования памяти (пространства) и очень быстр.

Ответ 2 · рейтинг 3 · Rody Oldenhuis

Как упомянул Михаил, вы действительно проделали потрясающую работу. На самом деле не так уж много можно улучшить.

Есть только несколько незначительных вещей, которые вы можете сделать:

  1. поменять местами порядок обработки матриц
  2. поменять порядок циклов

Поскольку A меньше, чем B, изменение порядка обработки заставит bsxfun выполнять большую часть тяжелой работы. Поскольку это "ближе к кремнию", чем JIT-цикл MATLAB, это будет выгодно.

Выполнение простого теста tic...toc с A = rand(255) и B = rand(10) (у меня нет всего дня! :) дает

Elapsed time is 3.460361 seconds.  %// original processing order
Elapsed time is 1.629848 seconds.  %// inverted processing order

В вашем случае разница будет меньше, конечно, но это может быть существенно.

Переключение порядка цикла (перебор строк во внутреннем цикле, столбцов во внешнем цикле) работает, потому что MATLAB хранит данные в порядке столбцов. Изменение порядка означает, что вычисление смещения указателя может быть повторно использовано во внутреннем цикле, что требует меньшего количества операций. Обычно это может иметь разницу до ~ 30%, однако последние версии MATLAB значительно улучшили это (до сих пор не знаю, как), и вы используете не 1 столбец, а 5... так что это, вероятно, не будет как значительный.

Выполнение того же теста с другим порядком цикла дает:

Elapsed time is 3.462599 seconds. %// original loop order
Elapsed time is 3.272909 seconds. %// inverted loop order

Соединяем все:

Elapsed time is 1.571496 seconds. %// Both optimizations implemented

Мой код:

%// random data for testing
A = rand(255);
B = rand(10);
threshold = rand;

[rowA, colA] = size(A);
[rowB, colB] = size(B);

patch_long = zeros(5,5, (rowA-4)*(colA-4));

tic

%// re-arrange A into 3D array of 5×5 patches
idx = 1;
for jj = 1:colA-4
    c = jj:jj+4;      %// re-use column indices
    for ii = 1:rowA-4 %// inner loop is over the rows

        patch_long(:,:,idx) = A(ii:ii+4, c);
        idx = idx+1;

    end

end

%// The heavy lifting
for n = 1:colB-4     %// let bsxfun do more work; loop over smallest array here
    c = n:n+4;       %// re-use column indices
    for m = 1:rowB-4 %// inner loop is over the rows

        temp1 = bsxfun(@minus, B(m:m+4, c), patch_long);
        count = sum( sum(temp1.^2) <= threshold );

    end
end

toc

Обратите внимание, что я не использовал parfor, просто чтобы все было доступно для копирования для всех. Использование parfor в реальной задаче дает мне

Elapsed time is 387.802798 seconds. %// original version, but without parfor
Elapsed time is 362.991760 seconds. %// both optimizations, WITH parfor

но я думаю, что это в основном потому, что мой рабочий ПК довольно плохой (AMD-A6 3650 APU).

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы