{"id":2089,"date":"2016-11-24T10:00:15","date_gmt":"2016-11-24T15:00:15","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/?p=2089"},"modified":"2017-06-29T10:52:40","modified_gmt":"2017-06-29T15:52:40","slug":"video-based-motion-analysis-with-matlab","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2016\/11\/24\/video-based-motion-analysis-with-matlab\/","title":{"rendered":"Video-based Motion Analysis with MATLAB"},"content":{"rendered":"<div class=\"content\"><!--introduction--><p>We love MATLAB and we also have many other interests, too. Today's guest blogger, <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/951521\">Toshi Takeuchi<\/a>, found an interesting way to combine his passion for MATLAB with one of his interests, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Argentine_tango#Dance\">Argentine Tango<\/a>!<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/tango.jpg\" alt=\"\"> <\/p><!--\/introduction--><h3>Contents<\/h3><div><ul><li><a href=\"#1066e027-6323-4655-b80d-1ad85af2ab6c\">Motivation<\/a><\/li><li><a href=\"#e48d5d87-58d2-4a3a-b63d-39362a2db1d6\">Loading Video<\/a><\/li><li><a href=\"#6279ac55-35f6-4d06-b62c-a44c36181523\">Playing Back Video in 1\/2 Time<\/a><\/li><li><a href=\"#a4dd77d7-7cf2-4ea0-bb6e-037fe7017a1b\">Creating the GUI<\/a><\/li><li><a href=\"#b3de69a4-4e03-4d5d-a502-3d37469e3592\">\"Choose File\" Button<\/a><\/li><li><a href=\"#ab756624-41a3-4dff-8027-877ccbc53849\">\"Play\" Button<\/a><\/li><li><a href=\"#9ac38b1d-6875-4474-9b39-9b9905d0ccc4\">TangoPlayer in Action<\/a><\/li><li><a href=\"#37fce3cf-4e5f-4c03-9225-466d4a965b37\">Creating a Standalone App<\/a><\/li><li><a href=\"#577f01ab-60fa-48e4-87aa-ea190a2a650b\">Summary<\/a><\/li><\/ul><\/div><h4>Motivation<a name=\"1066e027-6323-4655-b80d-1ad85af2ab6c\"><\/a><\/h4><p>I started <a href=\"https:\/\/sites.google.com\/site\/mittangoclub\/home\/\">taking Argentine Tango classes at MIT<\/a> when we had a record snow fall a few winters ago in Boston. I was originally planning to learn snowboarding (I even bought a used snowboard) but who would want to spend more time in the snow after having shoveled it day after day?<\/p><p>I was drawn to Tango because I can do the figures once I understand the geometry and physics of the moves. I can't do other dances because I am dyslexic and can't follow steps. Perhaps that's why they say Tango tends to attract people with a technical background? Loren says the same goes for glass blowing.<\/p><p>Argentine Tango is an improvisational partner dance that incorporates a rich variety of elegant figures - watch this <a href=\"https:\/\/www.youtube.com\/watch?v=TG5F4rt2Ol4\">YouTube video<\/a> for example. You have to practice those figures and you often watch videos like this - pausing, rolling back, playing back the same segment over and over - to study how those figures are executed. This is a tedious process often interrupted by a slow connection and annoying ads.<\/p><p>Naturally, I started wondering, \"can I use MATLAB to watch videos at slower speed?\" and of course you can. I am doing this for dancing, but I am sure you can also use it for other activities, such as checking your golf swing or learning how to play an instrument.<\/p><h4>Loading Video<a name=\"e48d5d87-58d2-4a3a-b63d-39362a2db1d6\"><\/a><\/h4><p>In this example, I will use my own video shot on an iPhone rather than professional videos you see on YouTube. I transferred the video from my phone to the current folder. If you want to follow this example, please use your own video. Now how do we load the video into MATLAB?<\/p><p>You can use the <tt><a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/videoreader.html\">VideoReader<\/a><\/tt> object to read video files into MATLAB, and store each frame into a structure array. This will take a bit of time, but this is an important step in order to play back those frames in real time later. I show the progress bar while frames are extracted and then show the first frame when completed. If the orientation of your video is not correct, use <tt><a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/imrotate.html\">imrotate<\/a><\/tt> to correct the orientation after extracting each frame.<\/p><pre class=\"codeinput\">filename = <span class=\"string\">'video-1468594243.mp4'<\/span>;                          <span class=\"comment\">% video to load<\/span>\r\nwb = waitbar(0,<span class=\"string\">'Loading the file...'<\/span>);                      <span class=\"comment\">% show progress bar<\/span>\r\nv = VideoReader(filename);                                  <span class=\"comment\">% create VideoReader object<\/span>\r\nw = v.Width;                                                <span class=\"comment\">% get width<\/span>\r\nh = v.Height;                                               <span class=\"comment\">% get height<\/span>\r\nd = v.Duration;                                             <span class=\"comment\">% get duration<\/span>\r\ns = struct(<span class=\"string\">'cdata'<\/span>,zeros(h,w,3,<span class=\"string\">'uint8'<\/span>),<span class=\"string\">'colormap'<\/span>,[]);     <span class=\"comment\">% struct to hold frames<\/span>\r\nk = 1;                                                      <span class=\"comment\">% initialize counter<\/span>\r\n<span class=\"keyword\">while<\/span> hasFrame(v)                                           <span class=\"comment\">% while object has frame<\/span>\r\n    f = readFrame(v);                                       <span class=\"comment\">% read the frame<\/span>\r\n    s(k).cdata = f; <span class=\"comment\">%  = imrotate(f,90);                    % rotate frame as needed<\/span>\r\n    k = k + 1;                                              <span class=\"comment\">% increment counter<\/span>\r\n    waitbar(v.CurrentTime\/d)                                <span class=\"comment\">% update progress bar<\/span>\r\n<span class=\"keyword\">end<\/span>\r\nv.CurrentTime = 18;                                         <span class=\"comment\">% set current time<\/span>\r\nf = readFrame(v);                                           <span class=\"comment\">% get the frame<\/span>\r\nclose(wb)                                                   <span class=\"comment\">% close progress bar<\/span>\r\naxes                                                        <span class=\"comment\">% create axes<\/span>\r\nimshow(f)                                                   <span class=\"comment\">% show the frame<\/span>\r\ntitle(<span class=\"string\">'Final Tango Frame'<\/span>)                                        <span class=\"comment\">% add title<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/motion_analysis_tango_video_01.png\" alt=\"\"> <h4>Playing Back Video in 1\/2 Time<a name=\"6279ac55-35f6-4d06-b62c-a44c36181523\"><\/a><\/h4><p>You can now play back the video at the speed of your choice with <tt><a href=\"https:\/\/www.mathworks.com\/help\/images\/ref\/imshow.html\">imshow<\/a><\/tt>. To ensure real-time playback, I first create the image, and subsequently update its underlying data for each frame using its handle, because it is too slow to create a new image for each frame. You can only see the final frame here, so I added <a href=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/half_speed.gif\">an animated GIF<\/a> from the figure at the end of this post.<\/p><pre class=\"codeinput\">fps = v.FrameRate;                                          <span class=\"comment\">% get frame rate<\/span>\r\nstartTime = 14;                                             <span class=\"comment\">% in seconds<\/span>\r\nendTime = 17;                                               <span class=\"comment\">% in seconds<\/span>\r\nspeed =  1\/2;                                               <span class=\"comment\">% play back speed<\/span>\r\nstartFrame = floor(startTime * fps);                        <span class=\"comment\">% starting frame<\/span>\r\nendFrame = floor(endTime * fps);                            <span class=\"comment\">% ending frame<\/span>\r\ncurAxes = axes;                                             <span class=\"comment\">% create axes<\/span>\r\nhImage = imshow(s(startFrame).cdata,<span class=\"string\">'Parent'<\/span>,curAxes);      <span class=\"comment\">% create hande<\/span>\r\ntitle(<span class=\"string\">'Tango Video'<\/span>)                                        <span class=\"comment\">% add title<\/span>\r\n<span class=\"keyword\">for<\/span> k = startFrame + 1:endFrame                             <span class=\"comment\">% loop over others<\/span>\r\n    set(hImage,<span class=\"string\">'CData'<\/span>,s(k).cdata);                         <span class=\"comment\">% update underlying data<\/span>\r\n    pause(1\/(fps*speed));                                   <span class=\"comment\">% pause for specified speed<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/motion_analysis_tango_video_02.png\" alt=\"\"> <h4>Creating the GUI<a name=\"a4dd77d7-7cf2-4ea0-bb6e-037fe7017a1b\"><\/a><\/h4><p>It is cumbersome to run the script over and over each time I change settings like the starting frame or speed. It would be much easier if I built a GUI for it. When it comes to building a GUI in MATLAB, you have two options.<\/p><div><ul><li><a href=\"https:\/\/www.mathworks.com\/products\/matlab\/app-designer\/\">App Designer<\/a> - to create an app that runs on MATLAB<\/li><li><a title=\"https:\/\/www.mathworks.com\/help\/matlab\/creating_guis\/about-the-simple-guide-gui-example.html (link no longer works)\">GUIDE<\/a> - to create a GUI that can be compiled as a standalone app<\/li><\/ul><\/div><p>Since this could be useful for other Tango friends of mine, I would like to be able to share it. I will assume they generally don't have MATLAB. I would therefore go with GUIDE in this case. For details of how you create a GUI with GUIDE, please refer to <a href=\"https:\/\/www.mathworks.com\/videos\/creating-a-gui-with-guide-68979.html\">this tutorial video<\/a>.<\/p><p>Here is <a href=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/tangoplayer.fig\">the fig file I created in GUIDE<\/a>. You can open the fig file in GUIDE by typing <tt>guide<\/tt> in Command Window and selecting \"Open Existing GUI\" tab in the Quick Start window. To open the working GUI, you can press the green play button in GUIDE or run the <tt><a href=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/tangoplayer.m\">tangoplayer<\/a><\/tt> callback function for the GUI in Command Window.<\/p><pre class=\"codeinput\">tangoplayer\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/motion_analysis_tango_video_03.png\" alt=\"\"> <h4>\"Choose File\" Button<a name=\"b3de69a4-4e03-4d5d-a502-3d37469e3592\"><\/a><\/h4><p>The callback function file <tt>tangoplayer.m<\/tt> was generated from GUIDE. I then added my custom code in it. The code we saw earlier for loading video is reused for the callback function for the \"Choose File\" button. Here is the relevant section of <tt>chooseBtn_Callback<\/tt> function.<\/p><pre class=\"codeinput\">dbtype <span class=\"string\">'tangoplayer.m'<\/span> <span class=\"string\">408:431<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\n408   % ***  Begin Reuse Example Code ***\r\n409   wb = waitbar(0,'Loading the file...');                  % show progress bar\r\n410   v = VideoReader(filename);                              % create VideoReader object\r\n411   w = v.Width;                                            % get width \r\n412   h = v.Height;                                           % get height\r\n413   d = v.Duration;                                         % get duration\r\n414   s = struct('cdata',zeros(h,w,3,'uint8'),'colormap',[]); % struct to hold frames\r\n415   k = 1;                                                  % initialize counter\r\n416   while hasFrame(v)                                       % while object has frame\r\n417       if rotate == 0                                      % if no rotation\r\n418           s(k).cdata = readFrame(v);                      % read the frame\r\n419       else                                                % otherwise\r\n420           f = readFrame(v);                               % get the frame\r\n421           s(k).cdata = imrotate(f,handles.rotate);        % rotate it\r\n422       end\r\n423       k = k + 1;                                          % increment counter\r\n424       waitbar(v.CurrentTime\/d)                            % update progress bar\r\n425   end\r\n426   v.CurrentTime = 0;                                      % back to the beginning\r\n427   f = readFrame(v);                                       % get the frame\r\n428   close(wb)                                               % close progress bar\r\n429   axes(handles.viewer)                                    % get axes\r\n430   hImage = imshow(imrotate(f,rotate));                    % show the frame\r\n431   % ***  End Reuse Example Code ***\r\n<\/pre><p>We want to share the resulting VideoReader object and structure array that contains extracted frames across other callback functions. You can do this by adding those variables to the <tt>handles<\/tt> structure and store it in the GUI's application data using <tt>guidata(hObject,handles)<\/tt>.<\/p><pre class=\"codeinput\">dbtype <span class=\"string\">'tangoplayer.m'<\/span> <span class=\"string\">437:443<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\n437   % share the loaded data across the GUI app with handles\r\n438   handles.v = v;                                          % add v to handles\r\n439   handles.s = s;                                          % add s to handles\r\n440   handles.t = 0;                                          % add t to handles\r\n441   handles.k = 0;                                          % add k to handle\r\n442   handles.fin = false;                                    % add fin to handle\r\n443   guidata(hObject,handles)                                % update handles\r\n<\/pre><h4>\"Play\" Button<a name=\"ab756624-41a3-4dff-8027-877ccbc53849\"><\/a><\/h4><p>To use the stored application data, you just have to access the relevant fields in the <tt>handles<\/tt> structure.<\/p><pre class=\"codeinput\">dbtype <span class=\"string\">'tangoplayer.m'<\/span> <span class=\"string\">191:193<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\n191   if ismember('v',fieldnames(handles))                    % if VideoReader object exists\r\n192       v = handles.v;                                      % retrieve it\r\n193       s = handles.s;                                      % get frames\r\n<\/pre><p>You can also retrieve, in the same way, the values for the start time and the speed set by the sliders. I invite you to look at the source code to see how the callback functions for those sliders work.<\/p><pre class=\"codeinput\">dbtype <span class=\"string\">'tangoplayer.m'<\/span> <span class=\"string\">201:204<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\n201   fps = v.FrameRate;                                      % get frame rate\r\n202   speed =  str2num(get(handles.speedBox,'String'));       % get speed\r\n203   startTime = handles.t;                                  % get start time\r\n204   startFrame = handles.k;                                 % get start frame\r\n<\/pre><p>The actual code that plays back the video is similar to the earlier example except that it has additional lines to take care of some details related to the GUI such as updating the current time display, adding a context menu to the image, and checking for the button state, etc. The context menu adds the ability to draw lines, rectangles, and circles on the image as defined in another section of the file.<\/p><pre class=\"codeinput\">dbtype <span class=\"string\">'tangoplayer.m'<\/span> <span class=\"string\">214:225<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\n214   % ***  Begin Reuse Example Code ***\r\n215   set(handles.timeBox,'String',sprintf('%.4f',startTime)) % update box text\r\n216   hImage = imshow(s(startFrame).cdata, ...                % create hande and\r\n217       'Parent',handles.viewer);                           % show the first frame\r\n218   ctm = handles.ctm;                                      % get context menu\r\n219   set(hImage,'uicontextmenu',ctm)                         % add context menu\r\n220   \r\n221   for k = startFrame + 1:length(s)                        % for each remaining frame\r\n222       if get(hObject,'Value')                             % if button is down\r\n223           set(hImage,'CData',s(k).cdata);                 % update underlying data\r\n224           pause(1\/(fps*speed));                           % pause for specified speed\r\n225       % ***  End Reuse Example Code ***\r\n<\/pre><h4>TangoPlayer in Action<a name=\"9ac38b1d-6875-4474-9b39-9b9905d0ccc4\"><\/a><\/h4><p>Here is the app in action - the lines were added using the context menu. It shows that I didn't keep my back straight in that particular frame. Ouch - it is painful to watch your own video, but it is more important to know the issues you need to fix.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/tangoplayer.png\" alt=\"\"> <\/p><h4>Creating a Standalone App<a name=\"37fce3cf-4e5f-4c03-9225-466d4a965b37\"><\/a><\/h4><p>Now that the app is working in MATLAB, I would like to share that with other Tango friends of mine who may or may not have MATLAB. If you have the <a href=\"https:\/\/www.mathworks.com\/products\/compiler\/\">MATLAB Compiler<\/a>, you will find the Application Compiler under the Apps tab.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/appcompiler.png\" alt=\"\"> <\/p><p>Open the Application Compiler and add <tt>tangoplayer.m<\/tt> as the main file and the Application Compiler will automatically add <tt>tangoplayer.fig<\/tt> and other dependencies in \"Files required for your application to run\". You can also make other customizations such as adding icons and a splash screen. Then all you need to do is to click \"Package\" to compile an executable. That's it! Since I am running MATLAB on Windows, this compiles a Windows app.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/compiler.png\" alt=\"\"> <\/p><p>Once completed, you find your installer in the \"for_redistribution\" folder and that's what I would give to my friends. The app requires MATLAB Runtime, and the installer automatically downloads it from the web in the installation process.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/installer.png\" alt=\"\"> <\/p><h4>Summary<a name=\"577f01ab-60fa-48e4-87aa-ea190a2a650b\"><\/a><\/h4><p>Learning Tango takes many hours, but you can create a custom app in MATLAB and share it as a standalone application in a mere tiny fraction of that time!<\/p><p>Have you used MATLAB for your hobbies before? What did you create? Did you know that you can buy <a href=\"https:\/\/www.mathworks.com\/products\/matlab-home\/\">MATLAB Home<\/a> to support your MATLAB addiction? Let us know what you've created <a href=\"https:\/\/blogs.mathworks.com\/loren\/?p=2089#respond\">here<\/a>.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/half_speed.gif\" alt=\"\"> <\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_2ca0fcfd0ea948ce886db54cc0c4bb2b() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='2ca0fcfd0ea948ce886db54cc0c4bb2b ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 2ca0fcfd0ea948ce886db54cc0c4bb2b';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2016 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_2ca0fcfd0ea948ce886db54cc0c4bb2b()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2016b<br><\/p><\/div><!--\r\n2ca0fcfd0ea948ce886db54cc0c4bb2b ##### SOURCE BEGIN #####\r\n%% Video-based Motion Analysis with MATLAB\r\n% We love MATLAB and we also have many other interests, too. Today's guest\r\n% blogger, <https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/951521\r\n% Toshi Takeuchi>, found an interesting way to combine his passion for\r\n% MATLAB with one of his interests,\r\n% <https:\/\/en.wikipedia.org\/wiki\/Argentine_tango#Dance Argentine Tango>!\r\n%\r\n% <<tango.jpg>>\r\n% \r\n%% Motivation \r\n% I started <http:\/\/tango.mit.edu taking Argentine Tango classes at MIT>\r\n% when we had a record snow fall a few winters ago in Boston. I was\r\n% originally planning to learn snowboarding (I even bought a used\r\n% snowboard) but who would want to spend more time in the snow after having\r\n% shoveled it day after day?\r\n%\r\n% I was drawn to Tango because I can do the figures once I understand the\r\n% geometry and physics of the moves. I can't do other dances because I am\r\n% dyslexic and can't follow steps. Perhaps that's why they say Tango tends\r\n% to attract people with a technical background? Loren says the same goes\r\n% for glass blowing.\r\n% \r\n% Argentine Tango is an improvisational partner dance that incorporates a\r\n% rich variety of elegant figures - watch this\r\n% <https:\/\/www.youtube.com\/watch?v=TG5F4rt2Ol4 YouTube video> for example.\r\n% You have to practice those figures and you often watch videos like this -\r\n% pausing, rolling back, playing back the same segment over and over - to\r\n% study how those figures are executed. This is a tedious process often\r\n% interrupted by a slow connection and annoying ads. \r\n% \r\n% Naturally, I started wondering, \"can I use MATLAB to watch videos at\r\n% slower speed?\" and of course you can. I am doing this for dancing, but I\r\n% am sure you can also use it for other activities, such as checking your\r\n% golf swing or learning how to play an instrument.\r\n% \r\n%% Loading Video\r\n% In this example, I will use my own video shot on an iPhone rather than\r\n% professional videos you see on YouTube. I transferred the video from my\r\n% phone to the current folder. If you want to follow this example, please\r\n% use your own video. Now how do we load the video into MATLAB?\r\n% \r\n% You can use the\r\n% |<https:\/\/www.mathworks.com\/help\/matlab\/ref\/videoreader.html\r\n% VideoReader>| object to read video files into MATLAB, and store each\r\n% frame into a structure array. This will take a bit of time, but this is\r\n% an important step in order to play back those frames in real time later.\r\n% I show the progress bar while frames are extracted and then show the\r\n% first frame when completed. If the orientation of your video is not\r\n% correct, use |<https:\/\/www.mathworks.com\/help\/images\/ref\/imrotate.html\r\n% imrotate>| to correct the orientation after extracting each frame.\r\n\r\nfilename = 'video-1468594243.mp4';                          % video to load\r\nwb = waitbar(0,'Loading the file...');                      % show progress bar\r\nv = VideoReader(filename);                                  % create VideoReader object\r\nw = v.Width;                                                % get width \r\nh = v.Height;                                               % get height\r\nd = v.Duration;                                             % get duration\r\ns = struct('cdata',zeros(h,w,3,'uint8'),'colormap',[]);     % struct to hold frames\r\nk = 1;                                                      % initialize counter\r\nwhile hasFrame(v)                                           % while object has frame\r\n    f = readFrame(v);                                       % read the frame\r\n    s(k).cdata = f; %  = imrotate(f,90);                    % rotate frame as needed \r\n    k = k + 1;                                              % increment counter\r\n    waitbar(v.CurrentTime\/d)                                % update progress bar\r\nend\r\nv.CurrentTime = 18;                                         % set current time\r\nf = readFrame(v);                                           % get the frame\r\nclose(wb)                                                   % close progress bar\r\naxes                                                        % create axes\r\nimshow(f)                                                   % show the frame\r\ntitle('Final Tango Frame')                                        % add title\r\n\r\n%% Playing Back Video in 1\/2 Time\r\n% You can now play back the video at the speed of your choice with\r\n% |<https:\/\/www.mathworks.com\/help\/images\/ref\/imshow.html imshow>|. To\r\n% ensure real-time playback, I first create the image, and subsequently\r\n% update its underlying data for each frame using its handle, because it is\r\n% too slow to create a new image for each frame. You can only see the final\r\n% frame here, so I added\r\n% <https:\/\/blogs.mathworks.com\/images\/loren\/2016\/half_speed.gif an animated\r\n% GIF> from the figure at the end of this post.\r\n\r\nfps = v.FrameRate;                                          % get frame rate\r\nstartTime = 14;                                             % in seconds\r\nendTime = 17;                                               % in seconds\r\nspeed =  1\/2;                                               % play back speed\r\nstartFrame = floor(startTime * fps);                        % starting frame\r\nendFrame = floor(endTime * fps);                            % ending frame\r\ncurAxes = axes;                                             % create axes\r\nhImage = imshow(s(startFrame).cdata,'Parent',curAxes);      % create hande\r\ntitle('Tango Video')                                        % add title\r\nfor k = startFrame + 1:endFrame                             % loop over others\r\n    set(hImage,'CData',s(k).cdata);                         % update underlying data\r\n    pause(1\/(fps*speed));                                   % pause for specified speed\r\nend\r\n\r\n%% Creating the GUI\r\n% It is cumbersome to run the script over and over each time I change\r\n% settings like the starting frame or speed. It would be much easier if I\r\n% built a GUI for it. When it comes to building a GUI in MATLAB, you have\r\n% two options.\r\n% \r\n% * <https:\/\/www.mathworks.com\/products\/matlab\/app-designer\/ App Designer>\r\n% - to create an app that runs on MATLAB\r\n% * <https:\/\/www.mathworks.com\/help\/matlab\/creating_guis\/about-the-simple-guide-gui-example.html\r\n% GUIDE> - to create a GUI that can be compiled as a standalone app\r\n% \r\n% Since this could be useful for other Tango friends of mine, I would like\r\n% to be able to share it. I will assume they generally don't have MATLAB. I\r\n% would therefore go with GUIDE in this case. For details of how you\r\n% create a GUI with GUIDE, please refer to\r\n% <https:\/\/www.mathworks.com\/videos\/creating-a-gui-with-guide-68979.html\r\n% this tutorial video>.\r\n% \r\n% Here is <https:\/\/blogs.mathworks.com\/images\/loren\/2016\/tangoplayer.fig the\r\n% fig file I created in GUIDE>. You can open the fig file in GUIDE by\r\n% typing |guide| in Command Window and selecting \"Open Existing GUI\" tab in\r\n% the Quick Start window. To open the working GUI, you can press the green\r\n% play button in GUIDE or run the\r\n% |<https:\/\/blogs.mathworks.com\/images\/loren\/2016\/tangoplayer.m\r\n% tangoplayer>| callback function for the GUI in Command Window. \r\n\r\ntangoplayer\r\n%% \"Choose File\" Button\r\n% The callback function file |tangoplayer.m| was generated from GUIDE. I\r\n% then added my custom code in it. The code we saw earlier for loading\r\n% video is reused for the callback function for the \"Choose File\" button.\r\n% Here is the relevant section of |chooseBtn_Callback| function.\r\n\r\ndbtype 'tangoplayer.m' 408:431\r\n%% \r\n% We want to share the resulting VideoReader object and structure array\r\n% that contains extracted frames across other callback functions. You can\r\n% do this by adding those variables to the |handles| structure and store it\r\n% in the GUI's application data using |guidata(hObject,handles)|.\r\n\r\ndbtype 'tangoplayer.m' 437:443\r\n%% \"Play\" Button\r\n% To use the stored application data, you just have to access the relevant\r\n% fields in the |handles| structure.\r\n\r\ndbtype 'tangoplayer.m' 191:193\r\n%% \r\n% You can also retrieve, in the same way, the values for the start time and\r\n% the speed set by the sliders. I invite you to look at the source code to\r\n% see how the callback functions for those sliders work.\r\n\r\ndbtype 'tangoplayer.m' 201:204\r\n%% \r\n% The actual code that plays back the video is similar to the earlier\r\n% example except that it has additional lines to take care of some details\r\n% related to the GUI such as updating the current time display, adding a\r\n% context menu to the image, and checking for the button state, etc. The\r\n% context menu adds the ability to draw lines, rectangles, and circles on\r\n% the image as defined in another section of the file.\r\n\r\ndbtype 'tangoplayer.m' 214:225\r\n%% TangoPlayer in Action\r\n% Here is the app in action - the lines were added using the context menu.\r\n% It shows that I didn't keep my back straight in that particular frame.\r\n% Ouch - it is painful to watch your own video, but it is more important to\r\n% know the issues you need to fix.\r\n% \r\n% <<tangoplayer.png>>\r\n% \r\n%% Creating a Standalone App\r\n% Now that the app is working in MATLAB, I would like to share that with\r\n% other Tango friends of mine who may or may not have MATLAB. If you have\r\n% the <https:\/\/www.mathworks.com\/products\/compiler\/ MATLAB Compiler>, you\r\n% will find the Application Compiler under the Apps tab.\r\n% \r\n% <<appcompiler.png>>\r\n% \r\n% Open the Application Compiler and add |tangoplayer.m| as the main file\r\n% and the Application Compiler will automatically add |tangoplayer.fig| and\r\n% other dependencies in \"Files required for your application to run\". You\r\n% can also make other customizations such as adding icons and a splash\r\n% screen. Then all you need to do is to click \"Package\" to compile an\r\n% executable. That's it! Since I am running MATLAB on Windows, this\r\n% compiles a Windows app.\r\n% \r\n% <<compiler.png>>\r\n%  \r\n% Once completed, you find your installer in the \"for_redistribution\"\r\n% folder and that's what I would give to my friends. The app requires\r\n% MATLAB Runtime, and the installer automatically downloads it from the web\r\n% in the installation process.\r\n% \r\n% <<installer.png>>\r\n% \r\n%% Summary\r\n% Learning Tango takes many hours, but you can create a custom app in\r\n% MATLAB and share it as a standalone application in a mere tiny\r\n% fraction of that time!\r\n% \r\n% Have you used MATLAB for your hobbies before? What did you\r\n% create? Did you know that you can buy\r\n% <https:\/\/www.mathworks.com\/products\/matlab-home\/ MATLAB Home> to support\r\n% your MATLAB addiction?\r\n% Let us know what you've created\r\n% <https:\/\/blogs.mathworks.com\/loren\/?p=2089#respond here>.\r\n\r\n%%\r\n% \r\n% <<half_speed.gif>>\r\n% \r\n\r\n##### SOURCE END ##### 2ca0fcfd0ea948ce886db54cc0c4bb2b\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2016\/tangoplayer.png\" onError=\"this.style.display ='none';\" \/><\/div><!--introduction--><p>We love MATLAB and we also have many other interests, too. Today's guest blogger, <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/951521\">Toshi Takeuchi<\/a>, found an interesting way to combine his passion for MATLAB with one of his interests, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Argentine_tango#Dance\">Argentine Tango<\/a>!... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2016\/11\/24\/video-based-motion-analysis-with-matlab\/\">read more >><\/a><\/p>","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[24,33,27],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/2089"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/comments?post=2089"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/2089\/revisions"}],"predecessor-version":[{"id":2380,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/2089\/revisions\/2380"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=2089"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=2089"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=2089"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}