Способ решить эту проблему - найти способ объединить информацию из A и B, чтобы сама фильтрация стала проще.
Первое, о чем я подумал, - это объединить А и В в третьем измерении и передать маску фильтра, которая будет брать 8 элементов из «А-среза» и центральный элемент из «В-среза». Это, к сожалению, не поддерживается Matlab.
Хотя nlfilter работает только с 2D-изображениями, он позволяет вам указать любую функцию для фильтрации. Таким образом, вы можете создать функцию, которая каким-то образом сможет искать правильные значения A и B. Таким образом, я пришел к своему первому решению.
Вы создаете новый массив C, который содержит индекс элемента для каждого элемента, то есть первый элемент равен 1, второй элемент равен 2 и т. Д. Затем вы запускаете nlfilter, который берет скользящее окно 3x3 и пропускает значения C внутри окна для функции фильтрации, ffn. ffn - это анонимная функция, которая вызывает crazyFilter и инициализирована так, что A и B передаются при каждом вызове. CrazyFunction берет значения из скользящего окна C, которые являются ничем иным, как индексами, в A и B, и собирает значения из A и B из них.
Второе решение точно такое же, за исключением того, что вместо перемещения скользящего окна вы создаете новый массив, в каждом столбце которого содержится содержимое скользящего окна во всех возможных местах. При перекрывающемся окне массив столбцов становится больше исходного массива. Опять же, вам просто нужно использовать значения массива столбцов C, которые являются индексами для A и B, чтобы найти значения A и B в соответствующих местах.
EDIT
Если у вас достаточно памяти, im2col и col2im могут значительно ускорить процесс
%# define A,B
A = randn(100);
B = rand(100);
%# pad A, B - you may want to think about how you want to pad
Ap = padarray(A,[1,1]);
Bp = padarray(B,[1,1]);
#% EITHER -- the more more flexible way
%# create a pseudo image that has indices instead of values
C = zeros(size(Ap));
C(:) = 1:numel(Ap);
%# convert to 'column image', where each column represents a block
C = im2col(C,[3,3]);
%# read values from A
data = Ap(C);
%# replace centers with values from B
data(5,:) = Bp(C(5,:));
%# OR -- the more efficient way
%# reshape A directly into windows and fill in B
data = im2col(Ap,[3,3]);
data(5,:) = B(:);
% median and reshape
out = reshape(median(data,1),size(A));
Старая версия (использует меньше памяти, может потребоваться заполнение)
%# define A,B
A = randn(100);
B = rand(100);
%# define the filter function
ffun = @(x)crazyFilter(x,A,B);
%# create a pseudo image that has indices instead of values
C = zeros(size(A));
C(:) = 1:numel(A);
%# filter
filteredImage = nlfilter(C,[3,3],ffun);
%# filter function
function out = crazyFilter(input,A,B)
%#CRAZYFILTER takes the median of a 3x3 mask defined by input, taking 8 elements from A and 1 from B
%# read data from A
data = A(input(:));
%# replace center element with value from B
data(5) = B(input(5));
%# return the median
out = median(data);