Distance Transform Behaviors Differently Between Matlab and OpenCV - matlab

I am currently translating code from Matlab to OpenCV but found the distance transform function behaviors differently between Matlab and OpenCV.
Take the simple matrix as an example
bw =
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
Matlab version distance transform assigns a number that is the distance between that pixel and the nearest nonzero pixel of BW, which makes sense and I got
1.4142 1.0000 1.4142 2.2361 3.1623
1.0000 0 1.0000 2.0000 2.2361
1.4142 1.0000 1.4142 1.0000 1.4142
2.2361 2.0000 1.0000 0 1.0000
3.1623 2.2361 1.4142 1.0000 1.4142
In OpenCV, I choose the DIST_L2 (the simple euclidean distance). it gives me
1.3692 0.9550 1.3692 2.3242 3.2792
0.9550 0 0.9550 1.9100 2.3242
1.3692 0.9550 1.3692 2.3242 1.3692
2.3242 1.9100 0.9550 0 0.9550
3.2792 2.3242 1.3692 0.9550 1.3692
I don't understand why and it doesn't make sense to me. I realized that OpenCV compute the pixel with nearest zero pixel, so I already inverted the input matrix.

maskSize – Size of the distance transform mask. It can be 3, 5, or CV_DIST_MASK_PRECISE (the latter option is only supported by the first function).
It looks like OpenCV version distance transform is doing some normalization using maskSize. Set it to 0 (Even the documentation didn't mention it) and it solves the issue.

Related

Fill convex area between 3D points in Matlab

I have a collection of 3D points in Matlab
PY=0.5000 0 0.5000;
0.5000 0.1250 0.3750;
0.5000 0.2500 0.2500;
0.5000 0.3750 0.1250;
0.6250 0 0.3750;
0.6250 0.1250 0.2500;
0.6250 0.2500 0.1250;
0.6250 0.3750 0;
0.7500 0 0.2500;
0.7500 0.1250 0.1250;
0.7500 0.2500 0];
These points are parts of the unit simplex
close all
patch([0 0 1],[0 1 0],[1 0 0],[0.8 0.8 0.8]);
axis equal
axis([0 1 0 1 0 1])
view(120,30)
hold on
scatter3(PY(:,1), PY(:,2), PY(:,3))
Question: I would like to fill the convex region that one gets by connecting these points. I'm unable to do that. Could you help?
This is what I tried
1) CHPY=convhull(PY(:,1),PY(:,2),PY(:,3) );
which gives me as error
Error computing the convex hull. The points may be coplanar or collinear.
2)
T = delaunayTriangulation(PY);
K = convexHull(T);
which gives me as error
Error using delaunayTriangulation/convexHull
The triangulation is empty.

special point distance transform in matlab

I use matlab to calculate the distance transform of a binary image, and I found that bwdist() can calculate distances of all the points of the image, but I just want to know the distance of a special point.
for example,I have a binary image like this
image =
1 0 0
0 0 1
0 0 0
The bwdist() compute the distance transform of all points
>> bwdist(a)
ans =
0 1.0000 1.0000
1.0000 1.0000 0
2.0000 1.4142 1.0000
But I just want to compute distance of the point image(3,2), so the function give me 1.4142
any function can do?
You can use find to find row and column indices for all 1's, then use pdist2 from Statistics and Machine Learning Toolbox to calculate distances for all 1's from the search point (3,2) and finally choose the minimum of those distances to get the final output. Here's the implementation shown as a sample run -
>> image
image =
1 0 0
0 0 1
0 0 0
>> point
point =
3 2
>> [R,C] = find(image);
>> min(pdist2([R C],point))
ans =
1.4142
If you don't have access to pdist2, you can use bsxfun to replace it like so -
min(sqrt(sum(bsxfun(#minus,[R C],point).^2,2)))

Jaccard index on Matlab produces wrong results

I have the following matrix
a =
0 10 10 0 0
0 5 5 0 0
1 0 0 50 51
0 0 10 100 100
I compute the Jaccard distances
D = pdist(a,'jaccard');
D =
1.0000 1.0000 0.7500 1.0000 1.0000 1.0000
and finally I put the distances in a matrix
sim = squareform(D)
sim =
0 1.0000 1.0000 0.7500
1.0000 0 1.0000 1.0000
1.0000 1.0000 0 1.0000
0.7500 1.0000 1.0000 0
The jaccard index is computed as "One minus the Jaccard coefficient, which is the percentage of nonzero coordinates that differ." (http://www.mathworks.it/help/stats/pdist.html)
The distance between row 1 and 4 is correct (0.75), while the distance between row 1 and 2 should be 0 and is, instead, 1. It seems that when the jaccard similarity is 1, matlab doesn't execute the 1-similarity computation. What am I doing wrong?
MATLAB seems right to me.
All of the non-zero numbers in rows 1 and 2 differ (in row 1 they're all 10, in row 2 they're all 5), so rows 1 and 2 should have a distance of 1.
Three out of four of the non-zero numbers in rows 1 and 4 differ (10:0, 10:10, 0:100, 0:100), so rows 1 and 4 should have a distance of 0.75.
There seems to be a lot of disagreement about what thing is the Jaccard "coefficient", the Jaccard "index", the Jaccard "similarity" and the Jaccard "distance", and which is one minus the other. MATLAB's documentation doesn't help, as it's not obvious, in the sentence you quote, whether "which" refers to (what MATLAB is describing as) the Jaccard coefficient, or to one minus the Jaccard coefficient.
In any case, whether the terminology used by the MATLAB documentation is correct, the function pdist seems to be giving consistent results, and you can always take one minus whatever it outputs if you want something different.

How to find a set of maximum independent vectors given a matrix?

Given a matrix A, I want to find a set of maximum linearly independent columns ? I have tried use rref(A) in matlab, then find all the pivot, it works well in general matrix. But when the matrix is special, it seems given the wrong answer, for example A =
1.6180 1.0000 1.0000 1.0000 0 1.0000
1.0000 1.6180 1.0000 1.0000 1.0000 0
1.0000 1.0000 1.6180 0 1.0000 1.0000
1.0000 1.0000 0 1.6180 0 0
0 1.0000 1.0000 0 1.6180 0
1.0000 0 1.0000 0 0 1.6180
then the rref(A)=
1.0000 0 0 0 0 0.8730
0 1.0000 0 0 0 -1.6180
0 0 1.0000 0 0 0.7450
0 0 0 1.0000 0 0.4604
0 0 0 0 1.0000 0.5396
0 0 0 0 0 0
this cannot be right. because the rank(A)=4. I have done the search, someone said that rref is not accurate and SVD will help ? but I really don't know how to do it ? Help me with the example matrix A will help me much more. 3Q !

Blockdiagonal variation grid

I have the feeling I am missing something intuitive in my solution for generating a partially varied block-diagonal grid. In any case, I would like to get rid of the loop in my function (for the sake of challenge...)
Given tuples of parameters, number of intervals and percentage variation:
params = [100 0.5 1
24 1 0.9];
nint = 1;
perc = 0.1;
The desired output should be:
pspacegrid(params,perc,nint)
ans =
90.0000 0.5000 1.0000
100.0000 0.5000 1.0000
110.0000 0.5000 1.0000
100.0000 0.4500 1.0000
100.0000 0.5000 1.0000
100.0000 0.5500 1.0000
100.0000 0.5000 0.9000
100.0000 0.5000 1.0000
100.0000 0.5000 1.1000
21.6000 1.0000 0.9000
24.0000 1.0000 0.9000
26.4000 1.0000 0.9000
24.0000 0.9000 0.9000
24.0000 1.0000 0.9000
24.0000 1.1000 0.9000
24.0000 1.0000 0.8100
24.0000 1.0000 0.9000
24.0000 1.0000 0.9900
where you can see that the variation occurs at the values expressed by this mask:
mask =
1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 0 1
0 0 1
0 0 1
1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 0 1
0 0 1
0 0 1
The function pspacegrid() is:
function out = pspacegrid(params, perc, nint)
% PSPACEGRID Generates a parameter space grid for sensitivity analysis
% Size and number of variation steps
sz = size(params);
nsteps = nint*2+1;
% Preallocate output
out = reshape(permute(repmat(params,[1,1,nsteps*sz(2)]),[3,1,2]),[],sz(2));
% Mask to index positions where to place interpolated
[tmp{1:sz(2)}] = deal(true(nsteps,1));
mask = repmat(logical(blkdiag(tmp{:})),sz(1),1);
zi = cell(sz(1),1);
% LOOP per each parameter tuple
for r = 1:sz(1)
% Columns, rows, rows to interpolate and lower/upper parameter values
x = 1:sz(2);
y = [1; nint*2+1];
yi = (1:nint*2+1)';
z = [params(r,:)*(1-perc); params(r,:)*(1+perc)];
% Interpolated parameters
zi{r} = interp2(x,y,z, x, yi);
end
out(mask) = cat(1,zi{:});
I think I got it, building off your pre-loop code:
params = [100 0.5 1
24 1 0.9];
nint = 1;
perc = 0.1;
sz = size(params);
nsteps = nint*2+1;
% Preallocate output
out = reshape(permute(repmat(params,[1,1,nsteps*sz(2)]),[3,1,2]),[],sz(2));
%Map of the percentage moves
[tmp{1:sz(2)}] = deal(linspace(-perc,perc,nint*2+1)');
mask = repmat(blkdiag(tmp{:}),sz(1),1) + 1; %Add one so we can just multiply at the end
mask.*out
So instead of making your mask replicate the ones I made it replicate the percentage moves each element makes which is a repeating pattern, the basic element is made like this:
linspace(-perc,perc,nint*2+1)'
Then it's as simple as adding 1 to the whole thing and multiplying by your out matrix
I tested it as follows:
me = mask.*out;
you = pspacegrid(params, perc, nint);
check = me - you < 0.0001;
mean(check(:))
Seemed to work when I fiddled with the inputs. However I did get an error with your function, I had to change true(...) to ones(...). This might be because I'm running it online which probably uses Octave rather than Matlab.