MATLAB Game with GUIDE - matlab

I'm creating a game (similar to Space Invaders) in MATLAB using Guide, where the player's ship is controlled by an accelerometer. So far, my GUI is nearly complete and I have managed to import an image of a ship and move it along the x-axis of main axes with the accelerometer. However, I cannot get enemy ships to be generated on the axes at the same time. After adding just a second image, the first one never generates. The code that loads the images is as follows:
handles.spaceShipImg = flipdim(imread('spaceship.jpg'),1);
handles.enemyShipImg = flipdim(imread('enemy1.jpg'),1);
Here is the part where I attempt to display the images:
handles.step = handles.step + handles.gx; %handles.gx is the reading from the accelerometer
axes(handles.magaxes)
image([handles.gx+handles.step 0.7+handles.gx+handles.step],[0 0.7],handles.spaceShipImg);
image([8 8.7],[8 8.7],handles.enemyShipImg);
set(gca,'YDir','normal')
axis([0 10 0 10]);
I'm wondering if it is possible to just use rectangular objects, and then paint them with an image instead. I also have to create collision detection, and I'm not sure how to implement that with images or rectangles. Any help is appreciated.

Try using the hold on and hold off commands to prevent the axes from refreshing when painting the 2nd image. Put the hold on after axes(handles.magaxes) and use 'hold off` after axis([0 10 0 10]);

Related

matlab - figure keeps blinking when streaming webcam

I first created a figure to stream webcam images onto it. I then created a 3D axes on the figure while streaming from the webcam. Note that the webcam frame streaming is not set inside the 3D axes but is set outside of the 3D axes in the figure itself. The problem is that the figure keeps blinking when I stream the webcam due to the uistack(ah,'bottom') function. I need this function to keep the 3D axes ah in front of the streaming figure background frame.
As you can see, I am using my webcam to stream apples. You can also see that the 3D axes is in front of the background thanks to the uistack(ah,'bottom') function. If I didn't use this function, the 3D axes would be hidden behind the background.
% turn on webcam
camList = webcamlist;
cam = webcam(camList{1});
% stream webcam
while(1)
frame = snapshot(cam);
ah = axes('unit','normalized','position',[0 0 1 1]);
imagesc(frame)
drawnow
set(ah,'handlevisibility','off','visible','off','Clipping','off')
uistack(ah,'bottom')
end
I solved the problem.
You need to define two axes: (i) one for the streaming images az and (ii) another one for the static image ah outside of the loop. Also, place the uistack function outside since it is redundant to tell the program to keep ah on top of the az axes every loop.
camList = webcamlist;
cam = webcam(camList{1});
hold on
az = axes('unit','normalized','position',[0 0 1 1]);
ah = axes('unit','normalized','position',[0 0 1 1]);
uistack(ah,'top')
while(1)
frame = snapshot(cam);
imagesc(az,frame)
drawnow
end

Simultaneous Controlling of image position via slider in MATLAB

I am working with multiple images stored in 3D structure in MATLAB. In the first step, I have done the following implementation of slider for controlling of individual images stored in 3D structure:
b(:,:,1)=zeros(300,300);
b(:,:,2)=ones(300,300);
b(:,:,3)=zeros(300,300);
b(:,:,4)=ones(300,300);
b(:,:,5)=zeros(300,300);
smin=1;
smax=5;
hsl = uicontrol('Style','slider','Min',smin,'Max',smax,...
'SliderStep',[1 1]./(smax-smin),'Value',1,...
'Position',[20 20 200 20]);
set(hsl,'Callback',#(hObject,eventdata) imshow(b(:,:,round(get(hObject,'Value')))))
I would like to kindly ask you about implementation of slider controlling simultaneously of two subplots. I need to create a one figure containing of two subplots. The one slider will control both subplots simultaneously. Thank you very much in advance for help.
Keep the handles to each of your subplots:
allPlots = [subplot(121) subplot(122)];
Then simply modify your callback to call imshow for each subplot, passing that subplot's handle as the parent axes:
set(hsl,'Callback',#(hObject,~) arrayfun(#(thisPlot) imshow(b(:,:,round(get(hObject,'Value'))),'Parent',thisPlot),allPlots))

Image gradually erased when overlayed with lines

Apart from the fact there exist special functions to plot vector fields, I have encountered a strange Matlab behaviour: Plotting an image (with imagesc or imshow) and overlaying it with colored lines (with plot or line) leads at some point to an erasement of the background image.
%% some data...
% random image
Image = rand(200,400);
% 900 lines of random color
color1 = rand(1,900);
color2 = rand(2,900);
color3 = rand(3,900);
% some positions
x = 31:60;
y = 31:60;
[X,Y] = meshgrid(x,y);
%% plot process
% plot Image (with 'imshow' or 'imagesc')
imshow(Image);
hold on;
% plot the lines (with 'line' or 'plot')
for i = 1:900
line([X(i), X(i)+1],[Y(i),Y(i)+2],'color',[color1(i),color2(i),color3(i)]);
if i == 100 % nothings happens to background image after 100 vectors
pause();
elseif i == 200 % gradually starts to change...
pause();
end
end
% ... at the end it is completely erased
Result: 100 lines
Result: 200 lines
Result: 900 lines
Nice side fact Saving the image as PNG restores the image (but destroys the line resolution).
This is not properly an answer, as it doesn't exactly explain why this is happening, but it provides a workaround, along with some more observations of the weird behaviour.
Scope:
I tried your example and indeed:
pre HG2 (R2013a): Same behavior than you described
HG2 (R2015a) : No problem, everything is there.
Workaround:
After a few trial and error, I worked out that it is a specific behaviour of the painter renderer in pre HG2 versions.
If you change the renderer to any other than the default painter, you get back your image and your superimposed lines.
set(gcf,'Renderer','zbuffer')
%// OR
set(gcf,'Renderer','opengl')
Observations:
Note that I also tried to:
display the lines first (no problem), then the image (and reorder using uistack) => same black image.
use multiple axes => black frame
And to show you how persistent is the glitch:
if you delete all the lines, the image does not reappear (=black frame).
if you delete all graphics objects, then re display the image => black frame
if you cla or even clf then re display the image => black frame
The only way I found to get the image displayed is to change the renderer as described above.
Printing/Saving
Initially, I thought the change of renderer was happening behind the scene when you were saving the figure, thereby allowing the final output to be fully displayed. Unfortunately, by exploring a bit more it doesn't seem to be so simple.
I tried different version with print (instead of saveas) since it allows you to select the renderer. For each renderer I chose 2 formats, PDF which uses the ghostscript engine, and PNG which uses the Matlab engine:
%%
print(1,'-dpng','-painters','testimageP.png')
print(1,'-dpng','-zbuffer' ,'testimageZ.png')
print(1,'-dpng','-opengl' ,'testimageO.png')
%%
print(1,'-dpdf','-painters','testimageP.pdf')
print(1,'-dpdf','-zbuffer' ,'testimageZ.pdf')
print(1,'-dpdf','-opengl' ,'testimageO.pdf')
Well, after results I am still unsure of what is happening. All these saved figures show the proper image and the lines on top... But:
The 3x png images (Matlab engine) are exactly similar. They do not even show slight difference in saturation like you can observe when you switch the renderer manually. This made me think that Matlab chose to ignore my renderer specification. It just decided which one was the most relevant and went ahead printing 3 times the same figure. So I thought may be the painter renderer wasn't used and that's why the images were shown.
Well not so fast. On the 3x pdf images (ghostscript engine) ... I can observe the small nuances between the 3 pictures ... so the renderer wasn't the same between them. The painter was used on one of them, and successfully rendered the image.
So in conclusion, it seems the painter renderer is only glitchy when applied to a (pre-HG2) figure!

Rotating a patch to face the camera in Matlab

This short code plots a flat patch (adapted from Matlab's manual):
t = 0:pi/5:2*pi;
figure
x=sin(t); y=cos(t); z=ones(size(x));
patch(x,y,z,'y')
axis equal
This results with a nice patch facing the camera:
However, I want to plot this patch on top of an already plotted 3D object, with the camera set on a fixed arbitrary view. My question is: how to rotate the patch's coordinates so the patch will face the camera and will have the right roll? A correct solution will make the patch look the same from any given arbitrary view (uniform scaling is permitted).
I guess that the camera's position, target and up-vector have to be taken into account, but it's not clear to me how.
It's funny, but today I was doing exactly the same thing :)
My approach is the following
Put your camera somewhere on the positive half of the X axis and set camera target to (0,0,0)
Draw your object the way you need it
Store X, Y, and Z coordinates of your object
Use rotate3d function and the make callbacks for ActionPreCallback and ActionPostCallback events of the rotate3d mode object
You'll need also to provide your routine for 'WindowButtonMotionFcn' event of the active figure
The whole logic works like this.
After you clicked rotate3d icon or call the rotate3d function, right after you click the left button on axes to start rotation, the ActionPreCallback event is fired. There you have to set flag (WeAreRotating in the code below) that rotation started. Then in the 'WindowButtonMotionFcn' callback function you retrieve camera view position using
[az,el] = view(ah);
function and rotate your object. The rotation is tricky, because you have to set its X, Y, and Z coordinates to the original ones you stored before and apply the rotate function to it. Something like this:
function fig_WindowButtonMotionFcn_callback(obj,evd)
if getappdata(gca,'WeAreRotating')
newView = round(get(gca,'View'));
set( ObjectHandle, ...
'XData',XData0, ...
'YData',YData0, ...
'ZData',ZData0 );
rotate( ObjectHandle, [1 0 0],-newView(2), RotationOrigin );
rotate( ObjectHandle, [0 0 1],+newView(1), RotationOrigin );
end
end % if FogProps.SimpleWhenRotated
The ActionPostCallback event is triggered when you release the mouse button and finish rotation. There you have to clear the rotation flag so moving your mouse will not change the object until you start rotation again.
Sorry if my explanation is somewhat unclear.
It is a little tricky to arrange all the flags properly, especially if you have several axes on the figure.
Actually, after your question I decided to clean my code and post it to FEX so everyone can use it so there you'll see how I achieved desired behavior.
UPDATE1
See http://www.mathworks.com/matlabcentral/fileexchange/47275-fog3d for full example

Making a 2D Matlab figure that contains multiple images which start at a given point (x,y)

Problem
I am trying to make a 2D figure in Matlab which consists of multiple images and a graph with plot data (which I could eventually convert into an image too). For these images and graph, I need to be able to specify where they are located in my cartesion coordinate system.
For my specific case, it is sufficient to be able to "tell" Matlab where the left-bottom corner of the image is.
So for the example above. I would need some "trick" to let "bird1.jpg" start at position (a,b), "bird2.jpg" at position (c,d) and my plot at position (e,f) in one Matlab figure.
Solution to problem
Thanks to chappjc I was able to find a solution for my problem. Here is the code I used such that other people can use it in the future too.
figure_color = [.741 .717 .42];
axe_color = [1 1 1];
Screen.fig = figure('units','pixels',...
'name','Parallel projection',...
'menubar','none',...
'numbertitle','off',...
'position',[100 100 650 720],...
'color',figure_color,...
'busyaction','cancel',...
'renderer','opengl');
Screen.axes = axes('units','pix',...
'position',[420 460 200 200],... % (420,460) is the position of the first image
'ycolor',axe_color,...
'xcolor',axe_color,...
'color',axe_color,...
'xtick',[],'ytick',[],...
'xlim',[-.1 7.1],...
'ylim',[-.1 7.1],...
'visible','On');
Screen.img = imshow(phantom);
Screen.axes2 = axes('units','pix',...
'position',[0 0 200 200],... % (0,0) is the position of the second image
'ycolor',axe_color,...
'xcolor',axe_color,...
'color',axe_color,...
'xtick',[],'ytick',[],...
'xlim',[-.1 7.1],...
'ylim',[-.1 7.1],...
'visible','On');
Screen.img2 = imshow(phantom);
Basically what I do is first creating a (big) figure, and then create a first axe at a certain position in this big picture, and make it the default axe. In this axe I display my first image (made with the phantom function). After that I make a new axe at a another position and make it again the default axe. After I have done that, I place an image there too (the same picture, but you can also use another one if you want). You can also use handles which is the more clean method, as chappjc describes.
Positioning axes in a figure
One approach would be to manipulate the Position property of multiple axes in a figure. To make multiple axes in a figure:
hf = figure;
ha0 = axes('parent',hf,'Position',[x0 y0 w0 h0]);
ha1 = axes('parent',hf,'Position',[x1 y1 w1 h1]);
Then display your images and plots into the axes by specifying the handle (i.e. ha0 or ha1). For example: image(img0,'Parent',ha0) or imshow(img1,'parent',ha1).
Single Large Image
Another approach is to make a single large image and simply display it with image/imshow/etc.
First for the plots, you can use getframe followed by frame2im to get an image in a matrix format.
Next, decide what goes into your combined image and compute the largest box required to circumscribe the images (using their origins and sizes find the largest x and y coordinate), which includes the origin presumably. Use this info to make a blank image (e.g. img = zeros(h,w,3) for and RGB image).