HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Analyzing the color composition of a video

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thecoloranalyzingvideocomposition

Problem

Here is a snippet of code from a project I have been working on that can be found here. I am looking for suggestions on how I can improve my code to make it cleaner and maybe improve performance.

```
from PIL import Image, ImageDraw
import subprocess as sp
import numpy
from pathlib import Path
import argparse
import AverageColor

def usage():
print("USAGE: videoparser.py --file {FILENAME} -f --FRAME {NUMBER OF FRAMES TO SKIP")

def get_resolution(path):
out = sp.check_output(["ffprobe", "-v", "error", "-of", "flat=s=_",
"-select_streams", "v:0", "-show_entries", "stream=height,width", path])

lines = out.split("\n")
vidwidth = lines[0].split('=')[1]
vidheight = lines[1].split('=')[1]
return vidwidth, vidheight

# Get the arguments from the command line and assign them to variables
parser = argparse.ArgumentParser(description="Analyze the change in colors of videos over time")
parser.add_argument('-f', "--frames", dest="FRAMESKIPCOUNT", default=24)
parser.add_argument('--file', dest="FILENAME", required=True)
args = vars(parser.parse_args())

FRAME_SKIP_COUNT = args['FRAMESKIPCOUNT']
FILENAME = args['FILENAME']
if args['FRAMESKIPCOUNT']:
FRAME_SKIP_COUNT = int(args['FRAMESKIPCOUNT'])

# Make sure the file is valid
my_file = Path(FILENAME)
if not my_file.is_file():
raise FileNotFoundError('File was not found', args['FILENAME'])

# Run the command to start the FFMPEG library
FFMPEG_BIN = "ffmpeg.exe"

command = [FFMPEG_BIN,
'-i', FILENAME,
'-f', 'image2pipe',
'-pix_fmt', 'rgb24',
'-vcodec', 'rawvideo', '-']

pipe = sp.Popen(command, stdout=sp.PIPE, bufsize=10 ** 8, shell=True) # Open pipe to start receiving pixel data
i = 0 # i is for processing every 'FRAME_SKIP_COUNT'th element
pos = 0 # to hold the position to draw the next line
width, height = get_resolution(FILENAME)
# Declare a blank image and prepare it for drawing
finalImage = Image.new("RGB", (20000, height))
finalImageDraw = Imag

Solution

Here's an alternative implementation of averagecolorfromfile:

import scipy.ndimage

def averagecolorfromfile2(file):
    "Return mean color of the pixels in the image loaded from file."
    return scipy.ndimage.imread(file).mean(axis=(0, 1)).round().astype('uint8')


I find that this is about 16 times as fast as the code in the post:

>>> data = np.random.randint(0, 256, size=(1000, 1000, 3), dtype='uint8')
>>> filename = 'cr153189.png'
>>> PIL.Image.fromarray(data).save(filename)
>>> from timeit import timeit
>>> timeit(lambda:averagecolorfromfile(filename), number=1)
1.599527531012427
>>> timeit(lambda:averagecolorfromfile2(filename), number=1)
0.09920550498645753


Note also that averagecolorfromfile returns a truncated result (that is, rounded towards zero). But for most purposes it would be more accurate to round to the nearest integer, as in averagecolorfromfile2:

>>> averagecolorfromfile(filename)
(127, 127, 127)
>>> averagecolorfromfile2(filename)
array([127, 128, 128], dtype=uint8)

Code Snippets

import scipy.ndimage

def averagecolorfromfile2(file):
    "Return mean color of the pixels in the image loaded from file."
    return scipy.ndimage.imread(file).mean(axis=(0, 1)).round().astype('uint8')
>>> data = np.random.randint(0, 256, size=(1000, 1000, 3), dtype='uint8')
>>> filename = 'cr153189.png'
>>> PIL.Image.fromarray(data).save(filename)
>>> from timeit import timeit
>>> timeit(lambda:averagecolorfromfile(filename), number=1)
1.599527531012427
>>> timeit(lambda:averagecolorfromfile2(filename), number=1)
0.09920550498645753
>>> averagecolorfromfile(filename)
(127, 127, 127)
>>> averagecolorfromfile2(filename)
array([127, 128, 128], dtype=uint8)

Context

StackExchange Code Review Q#153189, answer score: 2

Revisions (0)

No revisions yet.