MATLAB использует пользовательскую функцию с pdist

У меня есть пользовательская функция для расчета веса между двумя пикселями (которые представляют узлы на графике) изображения

function [weight] = getWeight(a,b,img, r, L)
    ac = num2cell(a);
    bc = num2cell(b);
    imgint1 = img(sub2ind(size(img),ac{:})); 
    imgint2 = img(sub2ind(size(img),bc{:}));
    weight = (sum((a - b) .^ 2) + (r^2/L) * abs(imgint2 - imgint1)) / (2*r^2);

где a = [x1 y1] а также b = [x2 y2] координаты, которые представляют пиксели изображения, img это серое изображение и r а также L являются постоянными. Внутри функции imgint1 а также imgint2 серые интенсивности пикселей на a а также b,

Мне нужно рассчитать вес среди множества точек изображения.

Вместо двух вложенных циклов я хочу использовать функцию pdist, потому что она ПУТЬ БЫСТРО!

Например, пусть nodes набор координат пикселей

nodes  =
 1     1
 1     2
 2     1
 2     2

А также img = [ 128 254; 0 255], r = 3, L = 255

Чтобы получить эти веса, я использую промежуточную функцию.

function [weight] = fxIntermediate(a,b, img, r, L)

    weight = bsxfun(@(a,b) getWeight(a,b,img,r,L), a, b);

Для того, чтобы наконец получить весь набор весов

distNodes = pdist(nodes,@(XI,XJ) fxIntermediate(XI,XJ,img,r,L));

Но это всегда дает мне ошибку

Error using pdist (line 373)
Error evaluating distance function '@(XI,XJ)fxIntermediate(XI,XJ,img,r,L)'.

Error in obtenerMatriz (line 27)
    distNodes = pdist(nodes,@(XI,XJ) fxIntermediate(XI,XJ,img,r,L));

Caused by:
    Error using bsxfun
    Invalid output dimensions.

РЕДАКТИРОВАТЬ 1

Это короткий пример моего кода, который должен работать, но я получил ошибку, упомянутую выше. Если вы скопируете / вставите код в MATLAB и запустите код, вы увидите ошибку

function [adjacencyMatrix] = problem
    img = [123, 229; 0, 45];                % 2x2 Image as example
    nodes  = [1     1;  1     2; 2     2];  % I want to calculate distance function getWeight()
                                            % between pixels img(1,1), img(1,2), img(2,2) 
    r = 3;                                  % r is a constant, doesn't matter its meaning
    L = 255;                                % L is a constant, doesn't matter its meaning

    distNodes = pdist(nodes,@(XI,XJ) fxIntermediate(XI,XJ,img,r,L)); 
    adjacencyMatrix = squareform(distNodes );
end

function [weight] = fxIntermediate(a,b, img, r, L)
    weight = bsxfun(@(a,b) getWeight(a,b,img,r,L), a, b);
end

function [weight] = getWeight(a,b,img, r, L)
    ac = num2cell(a);
    bc = num2cell(b);
    imgint1 = img(sub2ind(size(img),ac{:})); 
    imgint2 = img(sub2ind(size(img),bc{:}));
    weight = (sum((a - b) .^ 2) + (r^2/L) * abs(imgint2 - imgint1)) / (2*r^2);
end

Моя цель - получить матрицу смежности, которая представляет расстояние между пикселями. Для приведенного выше примера желаемая матрица смежности имеет вид:

adjacencyMatrix =    
          0         0.2634     0.2641
          0.2634    0          0.4163
          0.2641    0.4163     0

1 ответ

Проблема в том, что вы не соответствуете ожиданиям для функции, которая будет использоваться с pdistни те, что для функции, которая будет использоваться с bsxfun,

- из документации pdist:

Функция расстояния должна иметь форму

d2 = distfun(XI,XJ)

принимая в качестве аргументов вектор XI 1 на n, соответствующий одной строке X, и матрицу XJ m2-на-n, соответствующую нескольким строкам X. distfun должен принимать матрицу XJ с произвольным числом строк. distfun должен возвращать вектор m2 на 1 расстояний d2, k-й элемент которых является расстоянием между XI и XJ(k,:).

Однако с помощью bsxfun в fxIntermediateэта функция всегда возвращает матрицу значений, размер которых больше размеров двух входных данных.

- из документации bsxfun:

Бинарная поэлементная функция вида C = fun(A,B) принимает массивы A и B произвольного, но одинакового размера и возвращает выходные данные того же размера. Каждый элемент в выходном массиве C является результатом операции только с соответствующими элементами A и B. fun также должен поддерживать скалярное расширение, так что если A или B является скаляром, C является результатом применения скаляра к каждому элементу в другом входном массиве.

Тем не менее, ваш getWeight кажется, всегда возвращает скаляр.

Я не понимаю вашу проблему достаточно хорошо, чтобы исправить это. Более того, я думаю, что если скорость - это то, что вам нужно, кормление pdist с ручкой функции не путь. pdist не выполняет магию; это только быстро, потому что его встроенные функции расстояния реализованы эффективно. Кроме того, вы используете анонимные функции для обработки и преобразования в и из массивов ячеек, которые замедляют процесс. Я думаю, что вы должны опубликовать новый вопрос, где вы начнете с описания того, что вы пытаетесь вычислить, включите некоторый код, который выполняет работу, даже если он неэффективен, и спросите, как его улучшить.

Другие вопросы по тегам