I would like to know how I can to take each D(Points) and look at its connexed points (in 8 connex) but only on the side of the limit (ie the diagonal points top and bottom right and on the same line to the right, ie 3 points Connect on 8) and select the coordinates of the connexed point which has the smallest value of D. And I would like to repeat this until I obtain that the smallest value of D equal 0
% Creation of matrix example
c=zeros(500,500);
c(1:100,250)=1;c(100:300,200)=1;c(300:400,270)=1; c(400:500,250)=1;
c(100,200:250)=1;c(300,200:270)=1;c(400,250:270)=1;
figure, imagesc(c)
Points= [211,388;64,200;160,437;237,478;110,270;100,34];
hold on, plot(Points(:,1),Points(:,2),'ro'), hold off
%Distance map
D = bwdist(cumsum(c, 2) > 0, 'euclidean');
figure, imagesc(D)
The key function here is sub2ind which converts subscripts to linear indices. It is very handy when you need to work on specific points inside an array.
% Let's prepare the 8 shifts needed (i add a no-move shift in first place to simplify the algorithm)
delta_x = [0, -1, -1, -1, 0, 0, 1, 1, 1];
delta_y = [0, -1, 0, 1, -1, 1, -1, 0, 1];
sz_D = size(D);
n_points = size(Points, 1);
is_running = true;
while is_running
% All the shift combinaisons
new_ind_x = bsxfun(#plus, Points(:,1), delta_x);
new_ind_y = bsxfun(#plus, Points(:,2), delta_y);
% Saturation to stay in the image
new_ind_x = min(max(new_ind_x, 1), sz_D(2));
new_ind_y = min(max(new_ind_y, 1), sz_D(1));
% Get the values in D and find the index of the minimum points
points_lin_ind = sub2ind(sz_D, new_ind_y, new_ind_x);
points_val = D(points_lin_ind);
[min_values, min_ind] = min(points_val, [], 2);
% Select subscripts in new_ind_x and new_ind_y
min_lin_ind = sub2ind([n_points, 9], (1:n_points).', min_ind);
Points = [new_ind_x(min_lin_ind), new_ind_y(min_lin_ind)];
% Exit condition
if all(min_values == 0)
is_running = false;
end
end
PS : Not tested.
Related
I have a list of vertices where each row corresponds to a (x, y) coordinate.
For example, the following includes the vertices (0, 0), (1, 0), and (0, 1)
V = [0 0;
1 0;
0 1];
I also have a list of edges where the first column specifies the row of the starting vertex and the second column specifies the row of the ending vertex.
For example, the following includes the edges (0, 0) to (1, 0) and (0, 0) to (0, 1)
E = [1 2; % V(1) -> V(2) = (0, 0) -> (1, 0)
1 3] % V(1) -> V(3) = (0, 0) -> (0, 1)
I need to produce a list of edges with their actual coordinates from these two lists. That is, from V and E, I need
edge1 = [0 0]; % = E(1, 1) = V(1)
edge2 = [0 0]; % = E(2, 1) = V(1)
edge3 = [1 0]; % = E(1, 2) = V(2)
edge4 = [0 1]; % = E(2, 2) = V(3)
I know how to do this with for loops, but my supervisor said there is a more optimal solution using the function find(x), which returns the nonzero indices in an array. I do not see how this could be done with find. Is there a way that this could be done without using for loops but using the find function?
As far as I remember find is not really recommended when it comes to runtime, and for loops are not as bad as they where in the past taking JIT into consideration and MATLAB's effort to improve them.
However one possible solution without using for-loops (and without find) would be:
E = [1 2;
1 3];
V = [0 0;
1 0;
0 1];
Edges=V(E(:),:)
Edges =
0 0
0 0
1 0
0 1
So the output is not a list of different variables / edges but rather a matrix holding all of them row-wise.
I have a function (so to speak, i actually have data with this characteristic) with one variable x and several parameters a, b and c, so y = f(x, a, b, c).
Now i want to interpolate within families of parameters (for example for variations of a).
I'm currently doing this for data with one parameter (here, y is the data matrix)
% generate variable and data
x = linspace(0, 1, 100);
a = [0, 1]; % parameter
for i = 1:length(a)
y(:, i) = x.^2 + a(i);
end
% interpolate:
yi = interp1(a, y.', 0.5);
This works fine, but how do i expand this to more dimensions?
My current data format is like this: Each column of my data matrix represents one specific set of parameters, so for example:
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 3
where the first column denotes a = 0, b = 0, the second a = 1, b = 0, the third a = 0, b = 1 and the last a = 1, b = 1 (values are just for clarification, this is not on purpose binary. Also, the data columns are obviously not the same).
This data format is just the consequence of my data aquisition scheme, but i'm happy to change this into something more useful. Whatever works.
Works well for me:
% generate variable and data
x = linspace(0, 1, 100);
a = [0, 1, 2]; % parameter
b = [3, 4, 5]; % parameter
c = [6, 7, 8]; % parameter
% Create grid
[X,A,B,C]=ndgrid(x,a,b,c);
% define function
foo = #(x,p1,p2,p3) p1.*x.^2 + p2.*x + p3;
% evaluate function
Y = foo(X,A,B,C);
% interpolate:
yi = interpn(X,A,B,C,Y,x,1,4,6);
#zlon's answer works fine for the interpolation part, here i want to show how to convert the data from the format i provided to the needed format for the interpolation.
The two-dimensional matrix must be transformed into a N-dimensional one. Since the columns are not necessarily in order, we need to find the right ones. This is what i did:
First, we need to know the parameter set of each column:
a = [ 2, 2, 1, 0, 0, 1 ];
b = [ 1, 0, 0, 1, 0, 1 ];
These vectors length match the number of columns in the data matrix. The first column for example now contains the data for a = 2 and b = 1.
Now we can generate the new table:
A = -Inf;
i = 1;
while true
A = min(a(a > A)); % find next a
if isempty(A)
break
end
idxa = find(a == A); % store possible indices
B = -Inf;
j = 1;
while true
B = min(b(b > B))); % find next b
if isempty(B)
break
end
idxb = find(b == B); % store possible indices
% combine both indices
idx = intersect(idxa, idxb);
% save column in new data table
data(:, i, j) = olddata(:, idx);
% advance
j = j + 1;
end
i = i + 1;
end
I've been working with feature extraction and epipolar geometry. However, I'm constantly coming across the the following error:
Warning: Converting non-floating point data to single.
In pdist2 (line 219)
In extractFeaturesU (line 93)
The code line that is returning a warning message is:
[distance, position] = sort(pdist2(double(repmat(featuresA, size(xPoints, 1))), featuresB), 2, 'ascend');
The part of the code containing the above line is displayed below.
%% extract features
corresponding = [];
rightBound = size(sharpImageB, 2);
xPoints = 3 : 3 : rightBound - 3;
for index = 1 : size(realWantedPoints, 2)
%extract features from wanted points
disp('extracting features from wanted points...');
if strcmp(desc, 'hog')
[featuresA, pointsA] = extractHOGFeatures(sharpImageA, realWantedPoints(:, index)', ...
'CellSize', [8 8], 'BlockSize', [2 2], 'NumBins', 9, 'UseSignedOrientation', true);
elseif strcmp(desc, 'block')
[featuresA, pointsA] = extractFeatures(sharpImageA, realWantedPoints(:, index)', ...
'Method', 'Block', 'BlockSize', 21, 'Upright', true);
elseif strcmp(desc, 'surf')
[featuresA, pointsA] = extractFeatures(sharpImageA, realWantedPoints(:, index)', ...
'Method', 'SURF', 'SURFSize', 64, 'Upright', true);
end
% generate epipolar line points
liner = star([1 0 0]) * [realWantedPoints(:, index); 1];
yPoints = -(liner(3) + (liner(1) * xPoints)) / liner(2);
matrixB = [xPoints', yPoints'];
% extract features from epipolar line points
disp('extracting features from epipolar line points...');
if strcmp('hog', desc)
[featuresB, pointsB] = extractHOGFeatures(sharpImageB, matrixB, ...
'CellSize', [8 8], 'BlockSize', [2 2], 'NumBins', 9, 'UseSignedOrientation', true);
elseif strcmp('block', desc)
[featuresB, pointsB] = extractFeatures(sharpImageB, matrixB, ...
'Method', 'Block', 'BlockSize', 21, 'Upright', true);
elseif strcmp('surf', desc)
[featuresB, pointsB] = extractFeatures(greyB, matrixB, ...
'Method', 'SURF', 'SURFSize', 64, 'Upright', true);
end
% calculate similarity
[distance, position] = sort(pdist2(double(repmat(featuresA, size(xPoints, 1))), featuresB), 2, 'ascend');
corresponding = [corresponding; pointsB(position(1), :)];
end
xB = corresponding(:, 1);
yB = corresponding(:, 2);
I can generate that error by calling pdist2 on two variables: one of type double and one of type single. Eg.
x = ones(5,1,'single');
y = ones(5,1,'double');
pdist2(x,y);
My guess is that your featuresB variable is single precision floating point and hence doesn't match the type of your first argument to pdist2 (which is double because you explicitly convert it).
I would like to write a matlab function to find an equation of a linear classifier for 2 separable sets of points using one single-layer perceptron. I have got 2 files:
script file - run.m:
x_1 = [3, 3, 2, 4, 5];
y_1 = [3, 4, 5, 2, 2];
x_2 = [6, 7, 5, 9, 8];
y_2 = [3, 3, 4, 2, 5];
target_array = [0 0 0 0 0 1 1 1 1 1];
[ func ] = classify_perceptron([x_1 x_2; y_1 y_2], target_array);
x = -2:10;
y = arrayfun(func, x);
plot(x_1, y_1, 'o', x_2, y_2, 'X', x, y);
axis([-2, 10, -2, 10]);
classify_perceptron.m
function [ func ] = classify_perceptron( points, target )
% points - matrix of x,y coordinates
% target - array of expected results
% func - function handler which appropriately classifies a point
% given by x, y arguments supplied to this function
target_arr = target;
weights = rand(1, 2);
translation = rand();
for i=1:size(points, 2)
flag = true;
while flag
result = weights * points(:, i) + translation;
y = result > 0;
e = target_arr(1, i) - y;
if e ~= 0
weights = weights + (e * points(:, i))';
translation = translation + e;
else
flag = false;
end
end
end
func = #(x)(-(translation + (weights(1, 1) * x)) / weights(1, 2));
return
end
The problem is that I don't know where I am making the mistake that leads to incorrect result. It looks like the slope of the line is right, however translation should be a bit bigger. I would be really thankful for pointing me in the right direction. The result I get is presented in the picture below:
Ok, so I have made a significant progress. In case someone runs into the same problem I present to you the solution. The problem has been solved by adding a variable learning_rate = 0.1 and packing the loop iterating over points into another loop iterating as many times as specified in the variable epochs (e.g. 300) .
I have a problem adjusting the result of number randoming,
jum_k = 14;
jum_b = 12;
result = randint(jum_k, jum_b, [0 2]);
so that there is a constraint on the final result. There should not be a value "0" appearing more than three times in row.
Your random entries are then non-uniformly distributed with unknown weights, i.e. the number of zero per line can be <=3 ([0, 1, 2, 3]). I would hack around it this way: Populate an [m x n] matrix uniformly in [1,2], choose (random) number of zeros per line, then choose (random) their locations. Example:
jum_k = 14;
jum_b = 12;
result = randi([1, 2], jum_k, jum_b);
for i = 1:jum_k
nZeros = randi([0, 3]); % number of zeros (random)
result(i, randi(jum_b, 1, nZeros)) = 0; % locations in line (random)
end;
If you need an exact number of zeros per line you can modify accordingly.
EDIT (after clarifications on question from comments): To accomodate for no more than 3 zeros in sequence per each line, e.g. [1,0,0,0...2] you can populate the matrix element-wise and check for the pattern [0,0,0,0] in previous elements (keeping a buffer of previous values).
result = nan(jum_k, jum_b); % intitialize
for i = 1:jum_k
for j = 1:jum_b
result(i, j) = randi([0, 2]); % assign value
if j>3 && ~all(result(i, j-3:j)) % check previous values
result(i, j-randi([0, 3])) = randi([1, 2]); % randomly change one
end
end
end
%% check/test that all lines have less 4 zeros in sequence
f = #strfind;
for i = 1:jum_k
t(i) = isempty(f(result(i,:),[0 0 0 0]));
end
T = all(t);
It's not optimal (MATLAB-wise) but will do the job.