How to continuously update 2 plots and plotted Camera in same figure (MATLAB) - matlab

My goal is to continuously plot the position & orientation of camera relative to marker using MATLAB.
There are three thing to plot.(1)camera (2)all circle points (3)origin point '*'
Both the camera and points will be moving in each frame.I plotted all these three things in a static figure i.e. using hold on. as shown in the attached figure.
Now i want to plot them all continuously (real time) in the same figure as the values change.Till now i have only been able to dynamically update only one of these things i.e. the circular points for some random values. If I add another plot ,it conflicts.Can you please tell me how to update multiple plots in same figure and the plotCamera.
hF = figure;
hAx = gca;
im_pt_2world=rand(3,3);
x_o=im_pt_2world(1,1); y_o=im_pt_2world(1,2); %origin of the calibrated world points
x_ip=im_pt_2world(:,1); y_ip=im_pt_2world(:,2);
hpoints = plot3(x_ip, y_ip,zeros(size(im_pt_2world, 1),1),'ro');
% I added the "ishandle" so the program will end in case u closed the figure
while (1) & ishandle(hpoints)
%instead of using plot I directly change the data in the line
% this is faster the plot if only because you don't need to reedefine the limits and labels...
im_pt_2world=rand(3,3);
x_ip=im_pt_2world(:,1); y_ip=im_pt_2world(:,2);
set(hpoints,'ydata',y_ip);
set(hpoints,'xdata',x_ip);
drawnow %updates the display
end

The plotCamera function (Computer Vision System Toolbox) returns a handle to the graphical object, which you can manipulate programmatically. Changing the object's properties, such as Location and Orientation will move the camera in the plot. The help example for plotCamera shows how to make the camera fly in a circle:
% Plot a camera pointing along the Y-axis
R = [1 0 0;
0 0 -1;
0 1 0];
% Setting opacity of the camera to zero for faster animation.
cam = plotCamera('Location', [10 0 20], 'Orientation', R, 'Opacity', 0);
% Set view properties
grid on
axis equal
axis manual
% Make the space large enough for the animation.
xlim([-15, 20]);
ylim([-15, 20]);
zlim([15, 25]);
% Make the camera fly in a circle
for theta = 0:pi/64:10*pi
% Rotation about cameras y-axis
T = [cos(theta) 0 sin(theta);
0 1 0;
-sin(theta) 0 cos(theta)];
cam.Orientation = T * R;
cam.Location = [10 * cos(theta), 10 * sin(theta), 20];
drawnow();
end
If you really want to have fun with this, you can supply a function handle to be called when you click on the camera. For example, the function can display the image that the camera sees.

Related

Avoiding buggy/jerky animation

I have this code here below. It basically rotates a box in 3D. I know I can rotate the camera using camorbit but I actually want to rotate the object, not the camera around it. So the strategy is to create an element in so(3) and take the exponential map to SO(3) as the element is varied continuously over time.
% Create object
yo = unique([-1 -1 -1; perms([1 1 -1]); perms([1 -1 -1]); 1 1 1], 'rows');
yo2 = delaunay(yo(:,1), yo(:,2), yo(:,3));
box=tetramesh(yo2, yo);
% Create prescribed rotation
seedMat=skewdec(3,1)*skewdec(3,2)*skewdec(3,3); % so(3)
t=linspace(0,20,500);
r=zeros(1,4,length(t));
reqTraj=zeros(3,3,length(t));
for i=1:length(t)
reqTraj(:,:,i)=expm(seedMat*t(i)); % SO(3)
r(:,:,i) = vrrotmat2vec(expm(seedMat*t(i))); %Axis angle form
end
% Freeze axis
axis vis3d
axis([ -2 2 -2 2 -2 2])
% Rotate
for i=1:length(t)
rotate(box,r(1,1:3,i),r(1,4,i))
pause(0.001)
end
My question is why is this animation jerky? Is there something that I can do to fix it?
EDIT: Changing the last part as follows, made the buggy/jerky behavior go away, but resulted in an entirely new rotation behavior. So i am not sure if it is the correct approach or not. Can someone comment?
% Rotate
for i=2:length(t)
rotate(box,r(1,1:3,i),r(1,4,i-1)-r(1,4,i))
pause(0.001)
end

How to draw a line at a bearing angle in matlab?

I'm trying to simulate the movement of a target in Matlab, whose initial x and y co-ordinates, true bearing and speed (in m/s) are specified. I am wondering if there is a way to simply draw a straight line, at the specified bearing angle to show the path taken by the target (as shown in the image below)
Thanks in advance!
Your best bet is to rely on one of the built-in polar plotting functions to do this. I think the one that is most similar to your needs would be compass. It essentially plots an arrow pointing from the center to a point (defined in cartesian coordinates) on a polar plot.
theta = deg2rad(130);
% Your speed in m/s
speed = 5;
hax = axes();
c = compass(hax, speed * cos(theta), speed * sin(theta));
% Change the view to orient the axes the way you've drawn
view([90 -90])
Then in order to change the bearing and speed, you simply call the compass function again with your new bearing/speed.
new_theta = deg2rad(new_angle_degrees);
c = compass(hax, new_speed * cos(new_theta), new_speed * sin(new_theta));
Other polar plotting options include polar and polarplot which accept polar coordinates but don't have an arrow head. If you don't like the polar plot you could always go with quiver on a cartesian axes (making sure you specify the same axes).
Edit
Based on your feedback and request, below is an example of a polar plot of the distance traveled.
% Speed in m/s
speed = 5;
% Time in seconds
time = 1.5;
% Bearing in degrees
theta = 130;
hax = axes();
% Specify polar line from origin (0,0) to target position (bearing, distance)
hpolar = polar(hax, [0 deg2rad(theta)], [0 speed * time], '-o');
% Ensure the axis looks as you mentioned in your question
view([90 -90]);
Now to update this plot with a new bearing, speed, time you would simply call polar again specifying the axes.
hpolar = polar(hax, [0 theta], [0 speed], '-o');
I am not sure if I got it correctly, here is my solution:
figure;hold on; % Create figure
x_start = 10;% Starting position
y_start = 20;
plot(x_start+[-1 1],[y_start y_start],'k');% Plot crosshairs
plot([x_start x_start],y_start+[-1 1],'k');
angle = -(130-90)*pi/180; % Bearing angle 130° like in your graph
x_target = x_start+10*cos(angle); % Calculation of target position
y_target = y_start+10*sin(angle);
plot(x_target+[-1 1],[y_target y_target],'k');% Plot crosshairs
plot([x_target x_target],y_target+[-1 1],'k');
% Draw line between start and target
plot([x_start x_target],[y_start y_target],'g');
set(gca,'xlim',[0 30],'ylim',[0 30]); % Adjust axes
text(x_start+1,y_start,'Start'); % Write text to points
text(x_target+1,y_target,'End');

Rotate MATLAB legend

Is there a way to rotate the MATLAB legend inside a plot? The image below should clarify my requirement.
the legend function can return serval of args:
[leg,labelhandles,outH,outM] = legend(varargin)
When you ask for the 2nd argument you get a list of all the Children and then you can use what phil's answer:
set(hc(3),'Position',[0.5 0.6 0],'Rotation',90); % Relocate and rotate text
set(hc(2),'Xdata',[0.5 0.5],'YData',[0.1 0.5]); % rotate the line
set(hc(1),'XData',0.5,'YData',0.3); % R
This is correct for matlab 2021b
You'll need to play around with the positioning, and need to do more work if you have more than one line plotted, but the following does it for your example.
plot(1:10); % create a dummy line
ha = legend('Plot'); %create a legend
set(ha,'Units','pixels'); % set axes unit to pixels
pos = get(ha,'Position'); % get the axes position
set(ha,'Position',[pos(1) pos(2)-pos(3) pos(4) pos(3)]); % Set the new position
hc = get(ha,'Children'); % Get the legend contents
set(hc(3),'Position',[0.5 0.6 0],'Rotation',90); % Relocate and rotate text
set(hc(2),'Xdata',[0.5 0.5],'YData',[0.1 0.5]); % rotate the line
set(hc(1),'XData',0.5,'YData',0.3); % Rotate the Marker
The example is not fully automated but should set you on the right route. You need to rotate the box containing the legend, and the label with the text./
% Example plot
plot(1:10)
h = legend('something')
% Rotate legend
set(h,'CameraUpVector', [1 0 0], 'Units','pixels','position',[460 230 25 150])
% Rotate text label
txt = findobj(h,'type','text');
set(txt,'rotation',90)
Unfortunately, the save as function restores the 'CameraUpVector'.

MATLAB keeps updating the wrong plot

I'm really hoping this isn't some stupid little thing I'm missing, but I've been trying to figure this thing out for a couple hours now and haven't made any progress. Basically, I've created a figure with 3 subplots. For neatness, I made a function out of setting up the plots, then I made another function that constantly updates the plot with real time data.
The problem is, in the real time update function, the third subplot works perfectly fine, but now I want my second subplot to also real-time update, which I have not gotten done yet. For some reason, whenever I put in my code to access the 2nd plot, it keeps updating the 3rd plot and writing right over it! Meanwhile, the second plot stays in it's initial state...
Here is the code...I've looked over it a billion times so I'm at a loss at this point, I don't know what else to do....like I said really hoping it isn't something dumb lol...thanks a bunch =).
EDIT: The part that's going wrong starts where it says "%refresh plot
Real Time Plot Function
function [ ] = EndoSliceViewerJP( Naviparam, DICOMparam)
%RGBparam should be included later - add +1 to nargin values
%visualizes:
%1st: RGB camera Live view
%2nd: Orientation and Position of Navigation System
%3rd: DICOM Slice relative to navigated Endoscope in a and its orientation
%in a Slice perpendicular to the endoscope
%assumes Navigation system running with referenced tool (Naviparam.tool=4 or Naviparam.tool=5)
%currently this plots slices according to Endoscope position, could add
%vector in plot that shows orientation of the scope...
disp('Endo Slice Viewer');
disp('" ": exit on space key');
global kpressed;
kpressed = 0;
global Fig
Fig=EndoSliceViewer_createFigure(1);
set(Fig.fig,'KeyPressFcn','global kpressed; global Fig; kpressed = get(Fig.fig,''CurrentChar'');');
%create matrices and filter for smoothing of Endo Slice Data
xrel=-(ones(Fig.resolEndoSlice,1)*(1:Fig.resolEndoSlice)-Fig.resolEndoSlice/2);
yrel=-(ones(Fig.resolEndoSlice,1)*(1:Fig.resolEndoSlice)-Fig.resolEndoSlice/2);
SLimage=zeros(Fig.resolEndoSlice,Fig.resolEndoSlice);
PosVec=zeros(Fig.resolEndoSlice,Fig.resolEndoSlice,3);
gfilt = fspecial('gaussian',5,1.5);
depth = 50;
exitflag = 0;
while (exitflag == 0)
%check on keyboard input
if kpressed ~= 0
switch kpressed
case 'r'
depth=depth+2
case 'f'
depth=depth-2
case ' '
exitflag = 1;
disp('**** Exit Endo Slice Viewer ****')
end
kpressed = 0;
end
if (nargin>=1) %Naviparam is passed - update Navigation View
%capture new navigation data
Naviparam=Navi_acquire(Naviparam);
Naviparam=Navi_calc_data(Naviparam);
%refreshN avigation View
%NOT YET IMPLEMENTED: UPDATE NAVIGATION PLOT
if (nargin==2) %DICOMparam is also passed - update EndoSlice View
EndoVecX=inv(DICOMparam.calib.navi2dicom(1:3,1:3))*inv(Naviparam.data.Endo_RefHomMat(1:3,1:3))*[1;0;0];
EndoVecY=inv(DICOMparam.calib.navi2dicom(1:3,1:3))*inv(Naviparam.data.Endo_RefHomMat(1:3,1:3))*[0;1;0];
EndoVecZ=inv(DICOMparam.calib.navi2dicom(1:3,1:3))*inv(Naviparam.data.Endo_RefHomMat(1:3,1:3))*[0;0;-1];
EndoVecX=EndoVecX/norm(EndoVecX);
EndoVecY=EndoVecY/norm(EndoVecY);
EndoVecZ=EndoVecZ/norm(EndoVecZ);
mask=ones(Fig.resolEndoSlice,Fig.resolEndoSlice);
S=[DICOMparam.Sx; DICOMparam.Sy; DICOMparam.Sz];
DICOMPos = DICOMparam.calib.navi2dicom*[Naviparam.data.Endo_RefOffsetPosVec;1];
for i=1:3
%Point on Plane defined by Endo Position plus distance*Viewing direction vector
PosVec(:,:,i)=(DICOMPos(i)+depth*EndoVecZ(i))+xrel*EndoVecX(i)+yrel*EndoVecY(i);
%limit positions to integer values inside DICOM data cube
PosVec(:,:,i)=round(PosVec(:,:,i));
PosVec(:,:,i)=min(max(PosVec(:,:,i),1),S(i));
%create mask to set Points outside the data cube to 0
mask=double(PosVec(:,:,i)>1).*double(PosVec(:,:,i)<S(i).*mask(:,:));
end
%access data cube via indexed labelling
XposTemp=PosVec(:,:,1); YposTemp=PosVec(:,:,2); ZposTemp=PosVec(:,:,3);
indexTemp=sub2ind(size(DICOMparam.Vd), XposTemp(:), YposTemp(:),ZposTemp(:));
SLimage(:)=DICOMparam.Vd(indexTemp(:));
SLimage=SLimage.*mask;
SLimage=imfilter(SLimage,gfilt);
%refresh plot
set(Fig.sub3im, 'cdata', SLimage);
hold on;
Fig.sub2im=plot3(PosVec(1),PosVec(2),PosVec(3),'b*',PosVec(1)+depth*EndoVecZ(1),PosVec(2)-depth*EndoVecZ(2),PosVec(3)+depth*EndoVecZ(3),'r*');
hold off;
end
end
%RGBparam is always passed - update RGB camera View
%capture new RGB data
%handles.RGBparam=RGB_acquire(handles.RGBparam);
%refresh RGB camera View
%set(Fig.sub1im, 'CData', imresize(handles.RGBparam.image,[Fig.resolEndoRGB(1) Fig.resolEndoRGB(2)]));
drawnow;
end
close(Fig.fig);
clear global;
end
And here is my function setting up the plot
function [Fig] = EndoSliceViewer_createFigure(Figindex)
%This function creates and returns a Figure object to visualizes DICOM data
%in the plane orthogonal to the endoscopic view, the RGB view of the camera
%and the orientation of the navigation
%set resolution for Endo Slice Plot
Fig.resolEndoSlice=300;
Fig.resolEndoRGB=[720 1280];
Fig.resolEndoNavi=[500 500 500];
%init figure on screen
Fig.fig=figure(Figindex); gcf;
set(Fig.fig,'Position',[50 500 1500 500],'Name','Endo Slice Viewer');
%set(Fig.fig,'KeyPressFcn','global kpressed; global Fig; kpressed = get(Fig.fig,''CurrentChar'');');
Fig.sub1=subplot(1,3,1);
Fig.sub1im=image(uint8(zeros(Fig.resolEndoRGB(1), Fig.resolEndoRGB(2),3)));
title('Endo Camera View');
daspect([1 1 1]);
Fig.sub2=subplot(1,3,2);
Fig.BoxX=[0;1;1;0;0;0;1;1;0;0;1;1;1;1;1;0;0]*Fig.resolEndoNavi(1);
Fig.BoxY=[0;0;1;1;0;0;0;1;1;1;1;1;0;0;0;0;1]*Fig.resolEndoNavi(2);
Fig.BoxZ=[0;0;0;0;0;1;1;1;1;0;0;1;1;0;1;1;1]*Fig.resolEndoNavi(3);
Fig.sub2im=plot3(Fig.BoxX,Fig.BoxY,Fig.BoxZ);
title('Navigation View');
xlim([-0.2*Fig.resolEndoNavi(1), 1.2*Fig.resolEndoNavi(1)]);
ylim([-0.2*Fig.resolEndoNavi(2), 1.2*Fig.resolEndoNavi(2)]);
zlim([-0.2*Fig.resolEndoNavi(3), 1.2*Fig.resolEndoNavi(3)]);
xlabel('X [vox]');
ylabel('Y [vox]');
zlabel('Z [vox]');
daspect([1 1 1]);
Fig.sub3=subplot(1,3,3);
Fig.sub3im=imagesc(zeros(Fig.resolEndoSlice, Fig.resolEndoSlice));
title('Endo Slice View');
xlim([0 Fig.resolEndoSlice]);
ylim([0 Fig.resolEndoSlice]);
xlabel('Xendo [vox]');
ylabel('Yendo [vox]');
daspect([1 1 1]);
colormap bone
drawnow;
%potentially: add subplot for navigation position display later
end
You need to set your second subplot as the current axes before plotting anything in it. You can use axes(Fig.sub2) before the plotting command.

matlab: how to plot multidimensional array

Let's say I have 9 MxN black and white images that are in some way related to one another (i.e. time lapse of some event). What is a way that I can display all of these images on one surface plot?
Assume the MxN matrices only contain 0's and 1's. Assume the images simply contain white lines on a black background (i.e. pixel value == 1 if that pixel is part of a line, 0 otherwise). Assume images are ordered in such a way as to suggest movement progression of line(s) in subsequent images. I want to be able to see a "side-view" (or volumetric representation) of these images which will show the surface that a particular line "carves out" in its movement across the images.
Coding is done in MATLAB. I have looked at plot (but it only does 2D plots) and surf, which does 3D plots but doesn't work for my MxNx9 matrix of images. I have also tried to experiment with contourslice, but not sure what parameters to pass it.
Thanks!
Mariya
Are these images black and white with simple features on a "blank" field, or greyscale, with more dense information?
I can see a couple of approaches.
You can use movie() to display a sequence of images as an animation.
For a static view of sparse, simple data, you could plot each image as a separate layer in a single figure, giving each layer a different color for the foreground, and using AlphaData to make the background transparent so all the steps in the sequenc show through. The gradient of colors corresponds to position in the image sequence. Here's an example.
function plotImageSequence
% Made-up test data
nLayers = 9;
x = zeros(100,100,nLayers);
for i = 1:nLayers
x(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
figure;
hold on;
for i = 1:nLayers
layerData = x(:,:,i);
alphaMask = layerData == 1;
layerData(logical(layerData)) = i; % So each layer gets its own color
image('CData',layerData,...
'AlphaData',alphaMask,...
'CDataMapping','scaled');
end
hold off
Directly showing the path of movement a "line" carves out is hard with raster data, because Matlab won't know which "moved" pixels in two subsequent images are associated with each other. Don't suppose you have underlying vector data for the geometric features in the images? Plot3() might allow you to show their movement, with time as the z axis. Or you could use the regular plot() and some manual fiddling to plot the paths of all the control points or vertexes in the geometric features.
EDIT: Here's a variation that uses patch() to draw each pixel as a little polygon floating in space at the Z level of its index in the image sequence. I think this will look more like the "surface" style plots you are asking for. You could fiddle with the FaceAlpha property to make dense plots more legible.
function plotImageSequencePatch
% Made-up test data
nLayers = 6;
sz = [50 50];
img = zeros(sz(1),sz(2),nLayers);
for i = 1:nLayers
img(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
% With each "pixel" as a separate patch
figure;
set(gca, 'XLim', [0 sz(1)]);
set(gca, 'YLim', [0 sz(2)]);
hold on;
for i = 1:nLayers
layerData = img(:,:,i);
[x,y] = find(layerData); % X,Y of all pixels
% Reshape in to patch outline
x = x';
y = y';
patch_x = [x; x+1; x+1; x];
patch_y = [y; y; y+1; y+1];
patch_z = repmat(i, size(patch_x));
patch(patch_x, patch_y, patch_z, i);
end
hold off