Basic usage ----------- The ``VidStab`` class can be used as a command line script or in your own custom python code. Using from command line ~~~~~~~~~~~~~~~~~~~~~~~ .. code:: bash # Using defaults python3 -m vidstab --input input_video.mov --output stable_video.avi .. code:: bash # Using a specific keypoint detector python3 -m vidstab -i input_video.mov -o stable_video.avi -k GFTT Using ``VidStab`` class ~~~~~~~~~~~~~~~~~~~~~~~ .. code:: python from vidstab import VidStab # Using defaults stabilizer = VidStab() stabilizer.stabilize(input_path='input_video.mov', output_path='stable_video.avi') # Using a specific keypoint detector stabilizer = VidStab(kp_method='ORB') stabilizer.stabilize(input_path='input_video.mp4', output_path='stable_video.avi') # Using a specific keypoint detector and customizing keypoint parameters stabilizer = VidStab(kp_method='FAST', threshold=42, nonmaxSuppression=False) stabilizer.stabilize(input_path='input_video.mov', output_path='stable_video.avi') Advanced usage -------------- Plotting frame to frame transformations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code:: python from vidstab import VidStab import matplotlib.pyplot as plt stabilizer = VidStab() stabilizer.stabilize(input_path='input_video.mov', output_path='stable_video.avi') stabilizer.plot_trajectory() plt.show() stabilizer.plot_transforms() plt.show() +--------------+------------+ | Trajectories | Transforms | +==============+============+ | |image2| | |image3| | +--------------+------------+ Using borders ~~~~~~~~~~~~~ .. code:: python from vidstab import VidStab stabilizer = VidStab() # black borders stabilizer.stabilize(input_path='input_video.mov', output_path='stable_video.avi', border_type='black') stabilizer.stabilize(input_path='input_video.mov', output_path='wide_stable_video.avi', border_type='black', border_size=100) # filled in borders stabilizer.stabilize(input_path='input_video.mov', output_path='ref_stable_video.avi', border_type='reflect') stabilizer.stabilize(input_path='input_video.mov', output_path='rep_stable_video.avi', border_type='replicate') .. raw:: html .. raw:: html .. raw:: html .. raw:: html .. raw:: html .. raw:: html .. raw:: html .. raw:: html .. raw:: html .. raw:: html
.. raw:: html

border_size=0 .. raw:: html

.. raw:: html
.. raw:: html

border_size=100 .. raw:: html

.. raw:: html
.. raw:: html

.. raw:: html

.. raw:: html
.. raw:: html

.. raw:: html

.. raw:: html
+---------------------------+-----------------------------+ | ``border_type='reflect'`` | ``border_type='replicate'`` | +===========================+=============================+ | |image4| | |image5| | +---------------------------+-----------------------------+ `Video `__\ *used with permission from*\ `HappyLiving `__ Using Frame Layering ~~~~~~~~~~~~~~~~~~~~ .. code:: python from vidstab import VidStab, layer_overlay, layer_blend # init vid stabilizer stabilizer = VidStab() # use vidstab.layer_overlay for generating a trail effect stabilizer.stabilize(input_path=INPUT_VIDEO_PATH, output_path='trail_stable_video.avi', border_type='black', border_size=100, layer_func=layer_overlay) # create custom overlay function # here we use vidstab.layer_blend with custom alpha # layer_blend will generate a fading trail effect with some motion blur def layer_custom(foreground, background): return layer_blend(foreground, background, foreground_alpha=.8) # use custom overlay function stabilizer.stabilize(input_path=INPUT_VIDEO_PATH, output_path='blend_stable_video.avi', border_type='black', border_size=100, layer_func=layer_custom) +--------------------------------------+------------------------------------+ | ``layer_func=vidstab.layer_overlay`` | ``layer_func=vidstab.layer_blend`` | +======================================+====================================+ | |image6| | |image7| | +--------------------------------------+------------------------------------+ `Video `__\ *used with permission from*\ `HappyLiving `__ Automatic border sizing ~~~~~~~~~~~~~~~~~~~~~~~ .. code:: python from vidstab import VidStab, layer_overlay stabilizer = VidStab() stabilizer.stabilize(input_path=INPUT_VIDEO_PATH, output_path='auto_border_stable_video.avi', border_size='auto', # frame layering to show performance of auto sizing layer_func=layer_overlay) |image8| Stabilizing a frame at a time ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The method ``VidStab.stabilize_frame()`` can accept ``numpy`` arrays to allow stabilization processing a frame at a time. This can allow pre/post processing for each frame to be stabilized; see examples below. Simplest form ^^^^^^^^^^^^^ .. code:: python from vidstab.VidStab import VidStab stabilizer = VidStab() vidcap = cv2.VideoCapture('input_video.mov') while True: grabbed_frame, frame = vidcap.read() if frame is not None: # Perform any pre-processing of frame before stabilization here pass # Pass frame to stabilizer even if frame is None # stabilized_frame will be an all black frame until iteration 30 stabilized_frame = stabilizer.stabilize_frame(input_frame=frame, smoothing_window=30) if stabilized_frame is None: # There are no more frames available to stabilize break # Perform any post-processing of stabilized frame here pass Example with object tracking ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code:: python import os import cv2 from vidstab import VidStab, layer_overlay, download_ostrich_video # Download test video to stabilize if not os.path.isfile("ostrich.mp4"): download_ostrich_video("ostrich.mp4") # Initialize object tracker, stabilizer, and video reader object_tracker = cv2.TrackerCSRT_create() stabilizer = VidStab() vidcap = cv2.VideoCapture("ostrich.mp4") # Initialize bounding box for drawing rectangle around tracked object object_bounding_box = None while True: grabbed_frame, frame = vidcap.read() # Pass frame to stabilizer even if frame is None stabilized_frame = stabilizer.stabilize_frame(input_frame=frame, border_size=50) # If stabilized_frame is None then there are no frames left to process if stabilized_frame is None: break # Draw rectangle around tracked object if tracking has started if object_bounding_box is not None: success, object_bounding_box = object_tracker.update(stabilized_frame) if success: (x, y, w, h) = [int(v) for v in object_bounding_box] cv2.rectangle(stabilized_frame, (x, y), (x + w, y + h), (0, 255, 0), 2) # Display stabilized output cv2.imshow('Frame', stabilized_frame) key = cv2.waitKey(5) # Select ROI for tracking and begin object tracking # Non-zero frame indicates stabilization process is warmed up if stabilized_frame.sum() > 0 and object_bounding_box is None: object_bounding_box = cv2.selectROI("Frame", stabilized_frame, fromCenter=False, showCrosshair=True) object_tracker.init(stabilized_frame, object_bounding_box) elif key == 27: break vidcap.release() cv2.destroyAllWindows() |image10| Working with live video ~~~~~~~~~~~~~~~~~~~~~~~ The ``VidStab`` class can also process live video streams. The underlying video reader is ``cv2.VideoCapture``\ (`documentation `__). The relevant snippet from the documentation for stabilizing live video is: *Its argument can be either the device index or the name of a video file. Device index is just the number to specify which camera. Normally one camera will be connected (as in my case). So I simply pass 0 (or -1). You can select the second camera by passing 1 and so on.* The ``input_path`` argument of the ``VidStab.stabilize`` method can accept integers that will be passed directly to ``cv2.VideoCapture`` as a device index. You can also pass a device index to the ``--input`` argument for command line usage. One notable difference between live feeds and video files is that webcam footage does not have a definite end point. The options for ending a live video stabilization are to set the max length using the ``max_frames`` argument or to manually stop the process by pressing the Esc key or the Q key. If ``max_frames`` is not provided then no progress bar can be displayed for live video stabilization processes. Example ^^^^^^^ .. code:: python from vidstab import VidStab stabilizer = VidStab() stabilizer.stabilize(input_path=0, output_path='stable_webcam.avi', max_frames=1000, playback=True) |image9| Transform file writing & reading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Generating and saving transforms to file ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code:: python import numpy as np from vidstab import VidStab, download_ostrich_video # Download video if needed download_ostrich_video(INPUT_VIDEO_PATH) # Generate transforms and save to TRANSFORMATIONS_PATH as csv (no headers) stabilizer = VidStab() stabilizer.gen_transforms(INPUT_VIDEO_PATH) np.savetxt(TRANSFORMATIONS_PATH, stabilizer.transforms, delimiter=',') File at ``TRANSFORMATIONS_PATH`` is of the form shown below. The 3 columns represent delta x, delta y, and delta angle respectively. :: -9.249733913760086068e+01,2.953221378387767970e+01,-2.875918912994855636e-02 -8.801434576214279559e+01,2.741942225927152776e+01,-2.715232319470826938e-02 Reading and using transforms from file ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Below example reads a file of transforms and applies to an arbitrary video. The transform file is of the form shown in `above section <#generating-and-saving-transforms-to-file>`__. .. code:: python import numpy as np from vidstab import VidStab # Read in csv transform data, of form (delta x, delta y, delta angle): transforms = np.loadtxt(TRANSFORMATIONS_PATH, delimiter=',') # Create stabilizer and supply numpy array of transforms stabilizer = VidStab() stabilizer.transforms = transforms # Apply stabilizing transforms to INPUT_VIDEO_PATH and save to OUTPUT_VIDEO_PATH stabilizer.apply_transforms(INPUT_VIDEO_PATH, OUTPUT_VIDEO_PATH) .. |image0| image:: https://s3.amazonaws.com/python-vidstab/readme/input_ostrich.gif .. |image1| image:: https://s3.amazonaws.com/python-vidstab/readme/stable_ostrich.gif .. |image2| image:: https://s3.amazonaws.com/python-vidstab/readme/trajectory_plot.png .. |image3| image:: https://s3.amazonaws.com/python-vidstab/readme/transforms_plot.png .. |image4| image:: https://s3.amazonaws.com/python-vidstab/readme/reflect_stable_ostrich.gif .. |image5| image:: https://s3.amazonaws.com/python-vidstab/readme/replicate_stable_ostrich.gif .. |image6| image:: https://s3.amazonaws.com/python-vidstab/readme/trail_stable_ostrich.gif .. |image7| image:: https://s3.amazonaws.com/python-vidstab/readme/blend_stable_ostrich.gif .. |image8| image:: https://s3.amazonaws.com/python-vidstab/readme/auto_border_stable_ostrich.gif .. |image9| image:: https://s3.amazonaws.com/python-vidstab/readme/webcam_stable.gif .. |image10| image:: https://s3.amazonaws.com/python-vidstab/readme/obj_tracking_vidstab_1.gif