MATLAB won't extract first row & column because of matrix dimensions
I am tracking an object that is thrown in the air, and this object governs a parabolic pattern. I'm tracking the object through a series of 30 images. I managed to exclude all the background and keep the object apparent, then used its centroid to get its coordinates and plot them. Now I'm supposed to predict where the object is going to fall, so I used polyfit & polyval. The problem is, MATLAB says:
??? Index exceeds matrix dimensions.
Now the centroid creates its own structure with a row and two columns. Everytime the object moves in the loop, it updates the first row only.
Here is part of the code:
For N = 1:30
.
.
.
x = centroid(1,1); % extract first row and column for x
y = centroid(1,2); % extract secnd row and column for x
plot_xy = plot(x,y)
set(plot_xy,'XData',x(1:N),'YData',y(1:N));
fitting = polyfit(x(1:N),y(1:N),2);
parabola = plot(x,nan(23,1));
evaluate = polyval(fitting,x);
set(parabola,'YData',evaluate)
.
.
end
The error message I get is:
??? Index exceeds matrix dimensions.
It seems that (1:N) is causing the problems. I honestly do not know why, but when I remove N, the object is plotted along with its points, but polyfitting won't work. It gives me an error saying:
Warning: Polynomial is not unique; degree >= number of
data points.
> In polyfit at 72
If I made it (1:N-1) or something, it plots more points before it starts giving me the same error (not unique ...). But I can't remove (1:N), because I have to evaluate the coefficients of the polynomial in each loop (each value of N), so what's the solution?
Edit 2 :
This is more of my code
for N = 1:30
hold on
I = figure.image.(['j' num2str(N)]);
bw = (I);
imshow(bw)
ss = bwlabel(bw);
s = regionprops(bw,'centroid');
centroids = cat(1, s.Centroid);
hold(imgca,'on')
plot(imgca,centroids(1,1), centroids(1,2),'r*')
x = centroid开发者_运维问答s(1,1);
y = centroids(1,2);
points = plot(x,y,'bo',x,y,'rx');
hold on;
for N>3
C1 = centroids(1,1);
C2 = centroids(1,2);
set(points,'XData',C1,'YData',C2);
poly = polyfit(C1,C2,2);
parabola = plot(C1,nan(size(centroids,1),1));
pval = polyval(poly,x);
set(parabola,'YData',pval);
pause(0.5)
end
end
Edit 3
Code to display object distination:
poly = polyfit(C1,C2,2);
g = roots(poly);
v = max(g)
plot(xPlot,polyval(poly,xPlot),'y')
plot(v,'go')
The parabola line is plotted correctly due to xPlot, but for g
(the prediction), it all goes wrong... Am I using the wrong syntax to get the max value?
I also realized if I put plot(g,'g--')
instead of v, I get:
Wonder if I can get this horizontal instead of vertical. Then I will have a line with a circle where the parabola is predicted to stop.
This is how your code should look like, if I correctly understand what you want to do:
%# if there is only one centroid per image, preassign centroid array like this
centroids = zeros(30,1); %# case A
%# if there can be any number of centroids per image, preassign like this
centroids = cell(30,1); %# case B
for N=1:30
hold on
I = figure.image.(['j' num2str(N)]);
bw=(I);
imshow(bw)
ss = bwlabel(bw);
s = regionprops(bw,'centroid');
%# for case A
centroids(N,:) = cat(1, s.Centroid);
%# for case B
centroids{N} = cat(1,s.Centroid);
hold(imgca,'on')
%# case A
plot(imgca,centroids(N,1), centroids(N,2),'r*')
%# case B
if ~isempty(centroids{N})
plot(imgca,centroids{N}(:,1), centroids{N}(:,2), 'r*');
end
%# I don't think the following lines do anything useful
x=centroids(1,1);
y=centroids(1,2);
points=plot(x,y,'bo',x,y,'rx');
%# update plots
drawnow
%# you can only do the fitting once you collected all centroids
end
%# case A - do nothing b/c centroids is already numeric
%# case B - catenate centroids to make a numeric array with 2 columns
centroids = cat(1,centroids{:});
C1=centroids(:,1);
C2=centroids(:,2);
%#set(points,'XData',C1,'YData',C2);
poly=polyfit(C1,C2,2);
%# you can use the output of polyval directly as y-coordinate
parabola=plot(C1,polyval(poly,C1));
I suspect that you may be confusing yourself with x and y and you might do better without them. Here's how I would rewrite your code, if I have understood your intentions correctly. Note especially the rewritten polyfit call. I also think that you have hard-coded the call to nan incorrectly, so I have 'corrected' that too:
For N=1:30
.
.
.
plot_xy=plot(centroid(1,1),centroid(1,2))
set(plot_xy,'XData',centroid(:,1),'YData',centroid(:,2);
fitting=polyfit(centroid(:,1),centroid(:,2),2);
parabola=plot(centroid(:,1),nan(size(centroid,1),1));
evaluate=polyval(fitting,centroid(1,1));
set(parabola,'YData',evaluate)
.
.
end
[Answer edited to reflect updates]
In your code, you used
C1=centroids(1,1);
C2=centroids(1,2);
After this step, C1 and C2 become single-element scalars. You can check this with size(C1)
and size(C2)
, which will return [1 1]
as the answer. I'm guessing that you wanted to plot the first C1- and C2-point, then extend it all the way to element pair N. That's not necessary, the plot
function can handle vectors (and even matrices, but that will appear as a series of plots).
I'm not familiar with the image processing toolbox, and I do not have that toolbox so I can't check the function outputs. But as far as I can tell, what you need is a 30-row 2-column array of centroid position data, from which you will curve-fit its position at unknown x. I've removed some plotting functions; I trust this will make the code clearer.
for N=1:30
I = figure.image.(['j' num2str(N)]);
bw=(I);
ss = bwlabel(bw);
s = regionprops(bw,'centroid');
centroids = cat(1, centroids, s.Centroid); %Concatenate s.Centroid below centroids
end
%At this point, "centroids" should be a 30-by-2 array
size(centroids) % check if the output from this is [30 2]
x=centroids(:,1);
y=centroids(:,2);
poly=polyfit(x,y,2); %poly is a vector of curve-fitted polynomial coefficients
pval=polyval(poly,x); %pval is a vector of curve-fitted values evaluated at x
parabola=plot(x,pval); %plot the parabola
To get the y-position of the parabola at a point x_i, use polyval(poly,x_i)
.
Note particularly the proper syntax for the cat
function; cat(A,B) concatenates B below A, you can't use cat
with only one argument, as in your original code. This is likely the root cause of your headache, since with only 1 argument MATLAB simply takes "s.Centroid" as your new "centroids" array instead of adding it below the existing "centroids" array.
Reply to EDIT #3
In this part of your code
poly=polyfit(C1,C2,2); %'poly' is a vector of polynomial coefficients
g=roots(poly); %g solves for polynomial roots
v =max(g) %v is the largest root (assumed to be the expected ground-level destination)
plot(xPlot,polyval(poly,xPlot),'y') %plots polynomial at given x-values
%here, one expects to plot a point for the expected destination.
%the call to the plot function should follow syntax similar to the previous line
plot(v,'go') %plot function has syntax plot(x,y,options)
%therefore it should look like plot(v,polyval(poly,v),'go')
I've added some comments. The problem is with the line where you called plot
to plot the expected destination; the syntax seems to be wrong. If only 1 data argument is given, MATLAB assumes the given data to be the y-value, using its array index as the x-value (i.e. plotting y(1) at 1, y(2) at 2, etc). This is not what you want for variable v.
You can also use plot(v,0,'go')
as mentioned by Jonas, but it never hurts to double-check if the extrapolated polynomial value is actually near 0 ;)
精彩评论