{"id":4781,"date":"2024-12-28T12:00:24","date_gmt":"2024-12-28T20:00:24","guid":{"rendered":"https:\/\/www.cloudacm.com\/?p=4781"},"modified":"2024-12-27T07:27:30","modified_gmt":"2024-12-27T15:27:30","slug":"ffmpeg-and-imagemagick-motion-extraction","status":"publish","type":"post","link":"https:\/\/www.cloudacm.com\/?p=4781","title":{"rendered":"FFMpeg and ImageMagick Motion Extraction"},"content":{"rendered":"<p>Capturing changes in video frames was the basis of an earlier post, <a href=\"https:\/\/www.cloudacm.com\/?p=3423\">https:\/\/www.cloudacm.com\/?p=3423<\/a>. The intent was to trim out the content that had little or no changes between frames. This saved storage space so more content could be retained. I had stumbled upon this demonstration that took a different approach.<\/p>\n<p><iframe loading=\"lazy\" title=\"Motion Extraction\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/NSS6yAMZF78?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>This method puts emphasis on the changes between frames by highlighting the differences. The areas with no change becomes the background. It reminded me of an earlier demo that I had seen years before that used FFMPEG.<\/p>\n<p><iframe loading=\"lazy\" title=\"Demonstrating visual differences with ffmpeg&#039;s overlay and negate filters\" width=\"640\" height=\"480\" src=\"https:\/\/www.youtube.com\/embed\/SEXrierl2kQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>The process basically takes two different frames in a video and processes the changes in pixels. I had also seen demos of motion amplification, but that topic will not be covered here.<\/p>\n<p>This sample video was processed with FFMPEG based off of Dave Rice&#8217;s blog post, <a href=\"https:\/\/dericed.com\/2012\/display-video-difference-with-ffmpegs-overlay-filter\/\">https:\/\/dericed.com\/2012\/display-video-difference-with-ffmpegs-overlay-filter\/<\/a>. The script used is shown below the video.<\/p>\n<p><iframe loading=\"lazy\" title=\"Motion Extraction Demo 1\" src=\"https:\/\/player.vimeo.com\/video\/1042452828?dnt=1&amp;app_id=122963\" width=\"640\" height=\"180\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\"><\/iframe><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">#!\/bin\/bash\r\n# FFMPEG Native Motion Extraction Process\r\n# Source - https:\/\/dericed.com\/2012\/display-video-difference-with-ffmpegs-overlay-filter\/\r\n\r\nffmpeg -i 20220324_085905_01.MOV -ss 4 -to $(ffmpeg -i 20220324_085905_01.MOV 2&gt;&amp;1 | grep \"Duration\" | awk '{print $2}' | tr -d , | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 - 4 }') -c copy 20220324_085905_01_TrimLead.MOV\r\nsleep 3\r\nffmpeg -y -i 20220324_085905_01_TrimLead.MOV -i 20220324_085905_01.MOV -filter_complex '[1:v]format=yuva444p,lut=c3=128,negate[video2withAlpha],[0:v][video2withAlpha]overlay[out]' -map [out] 20220324_085905_01_Output.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01.MOV -i 20220324_085905_01_Output.MOV -filter_complex \"hstack,format=yuv420p\" -c:v libx264 -crf 18 20220324_085905_01_SideBySide.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01_SideBySide.MOV -vf scale=\"960:270\" MotionExtractionDemo-1.MOV\r\nexit<\/pre>\n<p>The following video is a modified FFMPEG process that was suggested on the Stackoverflow forum, <a href=\"https:\/\/stackoverflow.com\/questions\/25774996\/how-to-compare-show-the-difference-between-2-videos-in-ffmpeg\">https:\/\/stackoverflow.com\/questions\/25774996\/how-to-compare-show-the-difference-between-2-videos-in-ffmpeg<\/a>. The script for it is provided below the video.<\/p>\n<p><iframe loading=\"lazy\" title=\"Motion Extraction Demo 2\" src=\"https:\/\/player.vimeo.com\/video\/1042454422?dnt=1&amp;app_id=122963\" width=\"640\" height=\"180\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\"><\/iframe><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">#!\/bin\/bash\r\n# FFMPEG Native Motion Extraction Process\r\n# Source - https:\/\/stackoverflow.com\/questions\/25774996\/how-to-compare-show-the-difference-between-2-videos-in-ffmpeg\r\n\r\nffmpeg -i 20220324_085905_01.MOV -ss 4 -to $(ffmpeg -i 20220324_085905_01.MOV 2&gt;&amp;1 | grep \"Duration\" | awk '{print $2}' | tr -d , | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 - 4 }') -c copy 20220324_085905_01_TrimLead.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01_TrimLead.MOV -i 20220324_085905_01.MOV -filter_complex \"blend=all_mode=difference\" -c:v libx264 -crf 18 -c:a copy 20220324_085905_01_Output.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01.MOV -i 20220324_085905_01_Output.MOV -filter_complex \"hstack,format=yuv420p\" -c:v libx264 -crf 18 20220324_085905_01_SideBySide.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01_SideBySide.MOV -vf scale=\"960:270\" MotionExtractionDemo-2.MOV\r\nexit<\/pre>\n<p>This following video is a modification of previous which was provided from a prompt to OpenAI&#8217;s ChatGPT. The intent was to make the background black with highlights in white. The script follows the video below.<\/p>\n<p><iframe loading=\"lazy\" title=\"Motion Extraction Demo 3\" src=\"https:\/\/player.vimeo.com\/video\/1042460866?dnt=1&amp;app_id=122963\" width=\"640\" height=\"180\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\"><\/iframe><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">#!\/bin\/bash\r\n# FFMPEG Native Motion Extraction Process\r\n\r\nffmpeg -i 20220324_085905_01.MOV -ss 4 -to $(ffmpeg -i 20220324_085905_01.MOV 2&gt;&amp;1 | grep \"Duration\" | awk '{print $2}' | tr -d , | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 - 4 }') -c copy 20220324_085905_01_TrimLead.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01_TrimLead.MOV -i 20220324_085905_01.MOV -filter_complex \"blend=all_mode=difference,format=gray,lut=y=val*2\" -c:v libx264 -crf 18 -c:a copy 20220324_085905_01_Output.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01.MOV -i 20220324_085905_01_Output.MOV -filter_complex \"hstack,format=yuv420p\" -c:v libx264 -crf 18 20220324_085905_01_SideBySide.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01_SideBySide.MOV -vf scale=\"960:270\" MotionExtractionDemo-3.MOV\r\nexit<\/pre>\n<p>This last demo is a process that uses ImageMagick&#8217;s compare command, <a href=\"https:\/\/usage.imagemagick.org\/compare\/\">https:\/\/usage.imagemagick.org\/compare\/<\/a>. The process takes longer and isn&#8217;t as elegant as FFMPEG. However, the variety of adjustments to the results makes this something worth considering.<\/p>\n<p><iframe loading=\"lazy\" title=\"Motion Extraction Demo 4\" src=\"https:\/\/player.vimeo.com\/video\/1042465840?dnt=1&amp;app_id=122963\" width=\"640\" height=\"180\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\"><\/iframe><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">#!\/bin\/bash\r\n# Motion Extraction Process with ImageMagick\r\n\r\n# Set all the script variables\r\nsrcnme=20220324_085905_01\r\nsrctype=.MOV\r\nwrkdir=\/home\/MotionExtraction\/\r\n\r\nsrcdir=Images\r\nsrcimg=${wrkdir}${srcdir}\/\r\nsrcmov=${srcnme}${srctype}\r\nimgseq=${srcimg}${srcnme}_%04d.png\r\n\r\nprcamnt3=4SecLead\r\nprcimg3=${wrkdir}${prcamnt3}\/\r\noutputmov3=${srcnme}_${prcamnt3}${srctype}\r\n\r\nfactoramount3=6\r\nframecount=300\r\n\r\ncd $wrkdir\r\n\r\nmkdir $srcdir\r\nmkdir $prcamnt3\r\n\r\n# Extract images from video frames\r\nffmpeg -i ${srcmov} ${imgseq}\r\n\r\n# Process each image\r\ncd $prcimg3\r\nfilecount=1\r\n\r\nuntil [ $filecount -gt $((framecount - factoramount3)) ]\r\ndo\r\n  filepadding=`printf \"%04d\" $filecount`\r\n  ((leadfile=filecount+factoramount3))\r\n  leadpadding=`printf \"%04d\" $leadfile`\r\n  \r\n  convert ${srcimg}${srcnme}_${filepadding}.png ${srcimg}${srcnme}_${leadpadding}.png -compose difference -composite ${prcimg3}${srcnme}_${prcamnt3}_${filepadding}.png\r\n  ((filecount=filecount+1))\r\ndone\r\n\r\n# Build video from image frames\r\nls *.png &gt; imagelist1.txt\r\nsed \"s\/${srcnme}\/file \\'${srcnme}\/\" imagelist1.txt &gt; imagelist2.txt\r\nsed \"s\/png\/png\\'\/\" imagelist2.txt &gt; imagelist3.txt\r\nffmpeg -y -r 30 -f concat -safe 0 -i \"imagelist3.txt\" -c:v libx264 -vf \"fps=30,format=yuv420p\" ${outputmov3}\r\nrm *.txt\r\n\r\n# Create Side by Side comparison video\r\nffmpeg -i ${srcmov} -i ${outputmov3} -filter_complex \"hstack,format=yuv420p\" -c:v libx264 -crf 18 20220324_085905_01_SideBySide.MOV\r\nsleep 3\r\nffmpeg -i 20220324_085905_01_SideBySide.MOV -vf scale=\"960:270\" MotionExtractionDemo-4.MOV\r\nexit<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Capturing changes in video frames was the basis of an earlier post, https:\/\/www.cloudacm.com\/?p=3423. The intent was to trim out the content that had little or no changes between frames. This saved storage space so more content could be retained. I had stumbled upon this demonstration that took a different approach. This method puts emphasis on the changes between frames by highlighting the differences. The areas with no change becomes the background. It reminded me of an earlier demo that I&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.cloudacm.com\/?p=4781\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4781","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4781","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4781"}],"version-history":[{"count":5,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4781\/revisions"}],"predecessor-version":[{"id":4786,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4781\/revisions\/4786"}],"wp:attachment":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}