What will we cover in this tutorial?
Compare the difference of using weighted average and normal average over the last frames streaming from your webcam using OpenCV in Python.
The effect can be seen in the video below and code used to create that is provided below.
The code
The code is straight forward and not optimized. The average is calculated by using a deque from the collection library from Python to create a circular buffer.
The two classes of AverageBuffer and WeightedAverageBuffer share the same code for the constructor and apply, but have each their implementation of get_frame which calculates the average and weighted average, respectively.
Please notice, that the code is not written for efficiency and the AverageBuffer has some easy wins in performance if calculated more efficiently.
An important point to see here, is that the frames are saved as float32 in the buffers. This is necessary when we do the actual calculations on the frames later, where we multiply them by a factor, say 4.
Example. The frames are uint8, which are integers 0 to 255. Say we multiply the frame by 4, and the value is 128. This will give 128*4 = 512, which as an uint8 is 0. Hence, we get an undesirable effect. Therefore we convert them to float32 to avoid this.
import cv2 import numpy as np from collections import deque class AverageBuffer: def __init__(self, maxlen): self.buffer = deque(maxlen=maxlen) self.shape = None def apply(self, frame): self.shape = frame.shape self.buffer.append(frame) def get_frame(self): mean_frame = np.zeros(self.shape, dtype='float32') for item in self.buffer: mean_frame += item mean_frame /= len(self.buffer) return mean_frame.astype('uint8') class WeightedAverageBuffer(AverageBuffer): def get_frame(self): mean_frame = np.zeros(self.shape, dtype='float32') i = 0 for item in self.buffer: i += 4 mean_frame += item*i mean_frame /= (i*(i + 1))/8.0 return mean_frame.astype('uint8') # Setup camera cap = cv2.VideoCapture(0) # Set a smaller resolution cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) average_buffer = AverageBuffer(30) weighted_buffer = WeightedAverageBuffer(30) while True: # Capture frame-by-frame _, frame = cap.read() frame = cv2.flip(frame, 1) frame = cv2.resize(frame, (320, 240)) frame_f32 = frame.astype('float32') average_buffer.apply(frame_f32) weighted_buffer.apply(frame_f32) cv2.imshow('WebCam', frame) cv2.imshow("Average", average_buffer.get_frame()) cv2.imshow("Weighted average", weighted_buffer.get_frame()) if cv2.waitKey(1) == ord('q'): break # When everything done, release the capture cap.release() cv2.destroyAllWindows()