patternpythonMinor
Analyzing the color composition of a video
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
```
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
I find that this is about 16 times as fast as the code in the post:
Note also that
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.09920550498645753Note 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.