In [ ]:
from cvloop import cvloop
cvloop()
Videos can be loaded as simple as well, just provide a path (video taken from OpenCV):
In [ ]:
from cvloop import cvloop
cvloop('768x576.avi')
In [ ]:
from cvloop import cvloop
# Prints info about the image and skips thus the first frame.
# Otherwise it behaves like the default.
cvloop(print_info=True)
It is important to keep a reference to the cvloop return value. If it is the last statement in a notebook cell, this is done automatically (as you can see in almost all examples), since notebooks store the last return value in Out[]. However, if you want to do something after starting the loop, you will have to keep a reference yourself.
In [ ]:
# This will stop automatically before even reading the first frame.
from cvloop import cvloop
cvloop()
print('Oh no!')
In [ ]:
# While this will work.
from cvloop import cvloop
loop = cvloop()
print('Oh yeah!')
The cvloop.functions module provides premade functions ready to use. Most of them are just simple wrappers around OpenCV functions or filters. Below are some examples, for more take a look at the cvloop_functions notebook.
In [ ]:
from cvloop import cvloop, Inverter
# Inverts the image.
cvloop(function=Inverter())
In [ ]:
from cvloop import cvloop, BackgroundSubtractorMOG2
# Performs a background subtraction.
cvloop(function=BackgroundSubtractorMOG2())
It is possible to pass custom functions to the loop. The functions take an image as input and return an image as output:
def custom_function(image):
modified_image = ... # do something cool
return modified_image
The example performs background subtraction on the webcam stream (see OpenCV Documentation for details).
In [ ]:
import cv2
from cvloop import cvloop
# This is the same as cvloop.functions.cv_background_subtractor_mog2.
def mog2(frame):
return mog2.fgbg.apply(frame)
mog2.fgbg = cv2.createBackgroundSubtractorMOG2()
cvloop(function=mog2)
In [ ]:
from cvloop import cvloop, Inverter
cvloop(function=Inverter(), side_by_side=True)
In [ ]:
import cv2
from cvloop import cvloop
cvloop(convert_color=cv2.COLOR_BGR2GRAY)
In [ ]:
from cvloop import cvloop
cvloop(convert_color=-1)
In [ ]:
import cv2
from cvloop import cvloop
def conv(frame):
return cv2.cvtColor(frame, cv2.COLOR_BGR2XYZ)
cvloop(function=conv, convert_color=-1, side_by_side=True)
By default the plot function makes some guesses about how to show an image. If the image data consists of only two dimensions, gray scale is assumed, resulting in the usage of the grayscale color map. If the image data is three dimensional, it is assumed to be in RGB colors. (Note that unless overwritten, cvloop performs the conversion from OpenCVs standard BGR automatically!)
However, it is possible to provide custom colormaps, as will be demonstrated below. In general the colormaps should be designed such that matplotlib.pyplot.imshow can handle them – the colormaps reference is a good starting point. To apply a color map properly, the images are converted to grayscale first, using $\text{Gray} = .299 R + .587 G + .114 B$. If the image was already in grayscale, it is preserved.
In [ ]:
from cvloop import cvloop
cvloop(cmaps='Paired')
If a simple color map is provided, it is applied to all images.
In [ ]:
from cvloop import cvloop
cvloop(cmaps='Paired', side_by_side=True)
In [ ]:
from cvloop import cvloop
cvloop(cmaps=('terrain', 'Paired'), side_by_side=True)
In [ ]:
from cvloop import cvloop
cvloop(cmaps=(None, 'Paired'), side_by_side=True)
In [ ]:
from cvloop import cvloop
cvloop(cmaps=(None, None), side_by_side=True)
In [ ]:
import cv2
from cvloop import cvloop
capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640.)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480.)
cvloop(source=capture, function=lambda frame: 255 - frame)
In [ ]:
# releasing the resource (only rarely needed)
capture.release()
It is also possible to provide your own "video source". The only thing you have to do is implement a read method which can be invoked without arguments and returns two values, ret and frame, where ret is False if no frame is given (frame == None). Note however that ret == False interrupts the video process.
Also it is important to notice that if you don't have a get method which allows to get the properties cv2.CAP_PROP_FRAME_WIDTH and cv2.CAP_PROP_FRAME_HEIGHT, the first frame will be skipped to determine those dimensions. This might change in future version to avoid losing frames.
In [ ]:
import time
import numpy as np
from cvloop import cvloop
def map_to_image(vals, minval, maxval):
return ((vals - np.min(vals)) * (maxval - 1) / (np.max(vals) - np.min(vals)) + minval).astype(np.int)
class MySource:
def __init__(self, dim=(50, 25)):
self.shift = 0
self.W, self.H = dim
self.image = np.ones((self.W, self.H))
self.stop = 100
def read(self):
time.sleep(1/30)
self.stop -= 1
self.image = np.ones((self.W, self.H))
self.shift = (self.shift + .1) % (np.pi * 2)
x = np.arange(0, 2*np.pi, 0.001) + self.shift
y = np.sin(x)
self.image[map_to_image(x, 0, self.W), map_to_image(y, 0, self.H)] = 0
return self.stop >= 0, self.image.T
custom_source = MySource()
cvloop(source=custom_source, cmaps='terrain')
This feature is still experimental!
It is possible to add annotations to the processed image.
Annotations can either be rectangles (RECT) or circles (CIRC).
To use annotations, provide a list of annotations following this format:
[x, y, frame, options]
Where x and y are the center coordinates of the annotation and frame is the frame number for the annotation to be shown. options is an optional parameter. It is a dictionary with any of the following properties:
shape: Either CIRC or RECT. Determines the shape of the annotation. Defaults to RECT.color: Either a scalar value (gray scale) or an RGB tuple (r, g, b). All values must be between 0 and 1. Determines the color of the annotation. Defaults to (1, 0, 0) (bright red).line: The line width of the annotation. Defaults to 2.size: The size of the annotation. For circles (CIRC) this should be a scalar value for the radius (default: 30). For rectangles (RECT) this should be a tuple (width, height) (default: (40, 30)).
In [ ]:
from cvloop import cvloop
annotations = []
# Show all annotations from frames 10 to 79
for i in range(10, 80):
# Red rectangle moving from left to right
annotations.append([i * 5 + 40, 50, i])
# Gray circle
annotations.append([250, 140, i, {'shape': 'CIRC', 'color': .8}])
# Violett rectangle with all rectangle properties set:
annotations.append([300, 250, i, {
'shape': 'RECT',
'color': (0.3, 0.2, 0.8),
'line': 4,
'size': (30, 80)
}])
# Orange circle with all circle properties set:
annotations.append([450, 300, i, {
'shape': 'CIRC',
'color': (1, 0.5, 0.1),
'line': 1,
'size': 40
}])
cvloop('768x576.avi', annotations=annotations)