Video Frames Average

Let there be a still video. My goal is to extract frames from the video and generate an average image from those frames. This operation will produce a smoothing effect.

In [1]:
import cv2
import os

import numpy as np
import PIL
from PIL import Image

vid_input.mp4 is the video file. It was taken in low light situation with a smartphone in order to increase the noise.

In [2]:
video = cv2.VideoCapture('vid_input.mp4')

try:
    # creating a folder named data
    if not os.path.exists('data'):
        os.makedirs('frames')
        
# if not created then raise error
except OSError:
    print ('Error: Creating directory of data')
    
# frame
currentframe = 0

while(True):
    
    # reading from video
    ret, frame = video.read()
  
    if ret:
        # if video is still left continue creating images
        name = './frames/frame' + str(currentframe) + '.jpg'
        # print ('Creating...' + name)
  
        # writing the extracted images
        cv2.imwrite(name, frame)
  
        # increasing counter so that it will
        # show how many frames are created
        currentframe += 1
    else:
        break
  
# Release all space and windows once done
video.release()
cv2.destroyAllWindows()
In [3]:
# Change working directory to frames folder
os.chdir('frames')
In [4]:
# Access all PNG files in directory
all_files = os.listdir(os.getcwd())
images_list = [filename for filename in all_files if filename[-4:] == ".jpg"]

N = len(images_list)
print("Loaded {} images".format(N))
Loaded 103 images
In [5]:
# all images must be the same size
w, h = Image.open(images_list[0]).size

print("Image size: {}x{}".format(w, h))

# Create a numpy array of floats to store the average
smooth = np.zeros((h, w, 3), np.float)

# Build up average pixel intensities, casting each image as an array of floats
for frame in images_list:
    frame_arr = np.array(Image.open(frame), dtype = np.float)
    smooth += frame_arr / N

# Round values in array and cast as 8-bit integer
smooth = np.array(np.round(smooth), dtype = np.uint8)

output = Image.fromarray(smooth, mode = "RGB")
output.save("../Average.png")
Image size: 1920x1080

Comparison

  • first frame of a video (very noisy)
  • average of frames (smoothed image)
In [6]:
# %matplotlib notebook
# import matplotlib.pyplot as plt
# imgplot = plt.imshow(output)

from IPython.display import Image
Image(filename='frame0.jpg')
Out[6]:
In [7]:
Image(filename='../Average.png')
Out[7]:

by Wojciech Wiertarka

http://wiertareczka.ddns.net/