1
votes

I have a custom function to calculate the weight between two pixels (that represent nodes on a graph) of an image

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);

where a = [x1 y1] and b = [x2 y2] are coordinates that represents pixels of the image, img is a gray-scale image and r and L are constants. Within the function imgint1 and imgint2 are gray intensities of the pixels on a and b.

I need to calculate the weight among set of points of the image.

Instead of two nested loops, I want to use the pdist function because it is WAY FASTER!

For instance, let nodes a set of pixel coordinates

nodes  =
 1     1
 1     2
 2     1
 2     2

And img = [ 128 254; 0 255], r = 3, L = 255

In order to get these weights, I am using an intermediate function.

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

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

In order to finally get the whole set of weights

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

But it always get me an error

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.

EDIT 1

This is a short example of my code that it should work, but I got the error mentioned above. If you copy/paste the code on MATLAB and run the code you will see the error

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

My goal is to obtain an adjacency matrix that represents the distance between pixels. For the above example, the desired adjacency matrix is:

adjacencyMatrix =    
          0         0.2634     0.2641
          0.2634    0          0.4163
          0.2641    0.4163     0
1
Please provide a a Minimal, Complete, and Verifiable example. see stackoverflow.com/help/mcve In particular, values for img, R and L are missing.A. Donda
@A.Donda I added values for the other parameters a 2x2 image img = [ 128 254; 0 255], r = 3, L = 55, I hope it could be clear now. I appreciate if you can help me.zeellos
Thanks, but there are still undefined variables: ac and bc. Make the code so we can reproduce your problem, but there's no other problem. :-)A. Donda
@A.Donda I'm sorry for the imcomplete information. I edit in order to put de ac, bc variables. I hope It would be more clear, I really need to solve the problem.zeellos
zeellos, I still cannot reproduce your problem. Please include in your question one or more code sections corresponding to one or more m-files, that we can copy-and-paste and run, such that it leads to the error you want to solve, and no other error.A. Donda

1 Answers

0
votes

The problem is that you are neither fulfilling the expectations for a function to be used with pdist, nor those for a function to be used with bsxfun.

– From the documentation of pdist:

A distance function must be of form

d2 = distfun(XI,XJ)

taking as arguments a 1-by-n vector XI, corresponding to a single row of X, and an m2-by-n matrix XJ, corresponding to multiple rows of X. distfun must accept a matrix XJ with an arbitrary number of rows. distfun must return an m2-by-1 vector of distances d2, whose kth element is the distance between XI and XJ(k,:).

However, by using bsxfun in fxIntermediate, this function always returns a matrix of values whose size is the larger of the sizes of the two inputs.

– From the documentation of bsxfun:

A binary element-wise function of the form C = fun(A,B) accepts arrays A and B of arbitrary but equal size and returns output of the same size. Each element in the output array C is the result of an operation on the corresponding elements of A and B only. fun must also support scalar expansion, such that if A or B is a scalar, C is the result of applying the scalar to every element in the other input array.

However, your getWeight appears to always return a scalar.

I do not understand your problem well enough in order to repair this. Moreover, I think if speed is what you are after, feeding pdist with a function handle is not the way to go. pdist does not perform magic; it is only fast because its built-in distance functions are implemented efficiently. Also, you are using anonymous function handles and conversions to and from cell arrays, all of which slow the process down. I think you should post a new question where you start with a description of what you are trying to compute, include some code that does the job even if inefficiently, and ask how to improve that.