Processing video frames with SciPy / NumPy¶
How to enable this feature¶
Please see this page for the pre-requisites and pip
install options needed to enable this feature.
Example with explanation¶
In this section we define a GaussianSmootherBGRA
Python class that implements a custom image processing capability.
Namely, GaussianSmootherBGRA
:
- gets a video frame whose data is formatted in the BGRA colour space,
- smoothes this video frame with a Gaussian kernel,
- and finally passes it further down the video processing pipeline.
The GaussianSmootherBGRA
class achieves this by implementing the observer and observable interfaces simultaneously.
To this end, it extends the IObservableObserver
class exposed by GIFT-Grab:
from pygiftgrab import IObservableObserver
import scipy.ndimage as ndimage
class GaussianSmootherBGRA(IObservableObserver):
def __init__(self):
super(GaussianSmootherBGRA, self).__init__()
def update(self, frame):
data_np = frame.data(True)
ndimage.gaussian_filter(input=data_np,
sigma=(5, 15, 0),
order=0, output=data_np)
The update()
method above implements the corresponding method of GIFT-Grab’s observer.
This is a crucial component needed for creating custom image processing capabilities using GIFT-Grab.
In this particular case, in the update()
method implementation we obtain a reference to the actual data of the video frame in the form of a NumPy array by calling the data method.
We then apply Gaussian filtering in-place on this NumPy array using the corresponding method of SciPy.
A GaussianSmootherBGRA
instance can be attached to an observable video source.
This causes that video source object to pass each new video frame to the GaussianSmootherBGRA
instance.
The GaussianSmootherBGRA
instance in return processes that video frame according to the update()
method above.
It then passes it to any observer object attached to itself.
As a concrete example, consider attaching a GaussianSmootherBGRA
object to the file_reader
created in the Reading video files section.
There is a subtlety, though: we need to initialise this file_reader
using the BGRA colour space instead of I420 as in the Reading video files example:
file_reader = sfac.create_file_reader(
'/tmp/myinput.mp4', ColourSpace.BGRA )
Note that we use ColourSpace.BGRA
instead of ColourSpace.I420
, which is the only difference to the corresponding line in the Reading video files section.
This is because our GaussianSmootherBGRA
class expects the video frames to be encoded in the BGRA colour space.
Let’s create an instance of our class and attach it to the file_reader
:
gauss = GaussianSmootherBGRA()
file_reader.attach( gauss )
Now the file_reader
has started feeding video frames to gauss
.
To save the Gaussian-smoothed frames to a file, we can attach the file_writer
defined in the Encoding video streams in real time section to gauss
:
gauss.attach( file_writer )
At this point gauss
has started feeding the Gaussian-smoothed video frames to the file_writer
.
In other words, each video frame read from our video file is Gaussian-smoothed and subsequently encoded to a new video file.
This pipeline keeps operating until we detach the observers from the observables:
file_reader.detach( gauss )
gauss.detach( file_writer )
Full source code¶
Below is the full source code of the example explained above.
Please note that depending on the resolution of the video file used and the computational power of your platform, this application might end up processing less frames than are available during its runtime.
In other words, the resulting /tmp/myoutput.mp4
file might be shorter than 20 sec.
#!/usr/bin/env python2
from pygiftgrab import IObservableObserver
import scipy.ndimage as ndimage
from pygiftgrab import VideoSourceFactory
from pygiftgrab import ColourSpace
from time import sleep
from pygiftgrab import VideoTargetFactory
from pygiftgrab import Codec
class GaussianSmootherBGRA(IObservableObserver):
def __init__(self):
super(GaussianSmootherBGRA, self).__init__()
def update(self, frame):
data_np = frame.data(True)
ndimage.gaussian_filter(input=data_np,
sigma=(5, 15, 0),
order=0, output=data_np)
if __name__ == '__main__':
sfac = VideoSourceFactory.get_instance()
file_reader = sfac.create_file_reader(
'/tmp/myinput.mp4', ColourSpace.BGRA )
gauss = GaussianSmootherBGRA()
tfac = VideoTargetFactory.get_instance()
frame_rate = file_reader.get_frame_rate()
file_writer = tfac.create_file_writer(
Codec.HEVC, '/tmp/myoutput.mp4', frame_rate )
file_reader.attach( gauss )
gauss.attach( file_writer )
sleep( 20 ) # operate pipeline for 20 sec
file_reader.detach( gauss )
gauss.detach( file_writer )