Commit aa232eca authored by Niels-Oliver Walkowski's avatar Niels-Oliver Walkowski
Browse files

refac(pkg): correct all flake8 errors

parent 11342779
...@@ -5,11 +5,12 @@ from skimage import color ...@@ -5,11 +5,12 @@ from skimage import color
# TODO create generic class # TODO create generic class
class Contrast(object): class Contrast(object):
"""Base class for color contrasts""" """Base class for color contrasts"""
def __init__(self, img): def __init__(self, img):
self._img = img self._img = img
class Monochromatic(Contrast): class Monochromatic(Contrast):
"""docstring for Monochromatic""" """docstring for Monochromatic"""
...@@ -25,10 +26,12 @@ class Monochromatic(Contrast): ...@@ -25,10 +26,12 @@ class Monochromatic(Contrast):
The array has the same dimensions as the image. However the third The array has the same dimensions as the image. However the third
does only have the size 1 which contains the luminance value does only have the size 1 which contains the luminance value
""" """
# Luminance Faktoren nach http://introcs.cs.princeton.edu/python/31datatype/luminance.py.html # Luminance Faktoren nach
# http://introcs.cs.princeton.edu/python/31datatype/luminance.py.html
luminance_factors = np.array([.114, .587, .299]) luminance_factors = np.array([.114, .587, .299])
# Erzeugung eines eindimensionalen Arrays für die effizientere Berechnung # Erzeugung eines eindimensionalen Arrays für die effizientere
# Berechnung
self._img = np.multiply(self._img, luminance_factors) self._img = np.multiply(self._img, luminance_factors)
# addiert alle Werte auf einer bestimmten Achse # addiert alle Werte auf einer bestimmten Achse
...@@ -68,30 +71,31 @@ class Monochromatic(Contrast): ...@@ -68,30 +71,31 @@ class Monochromatic(Contrast):
def colf_val_point(self): def colf_val_point(self):
"""calculates the most colourful value point in an image """calculates the most colourful value point in an image
used to identify tinting or toning images with its specific colourful used to identify tinting or toning images with its specific colourful
areas in very light or darker value regions areas in very light or darker value regions
""" """
# as long as opencv is used, convert RGB to RGB # as long as opencv is used, convert RGB to RGB
imgrgb = self._img[:, :, ::-1] imgrgb = self._img[:, :, ::-1]
assert(np.array_equal(self._img, imgrgb[:, :, ::-1])), "opencv scikit-image conversion wrong" assert(np.array_equal(self._img,
imgrgb[:, :, ::-1])), "opencv scikit-image conversion wrong"
imglab = color.rgb2lab(imgrgb) imglab = color.rgb2lab(imgrgb)
imglch = color.lab2lch(imglab) imglch = color.lab2lch(imglab)
value = Monochromatic(self._img, method='value') value = Monochromatic(self._img, method='value')
value = value.value() value = value.value()
imgcv = imglch[:,:,1].astype(np.uint8) imgcv = imglch[:, :, 1].astype(np.uint8)
imgcv = np.dstack((imgcv, value)) imgcv = np.dstack((imgcv, value))
perc90 = np.percentile(imgcv[:,:,0], 90) perc90 = np.percentile(imgcv[:, :, 0], 90)
indices_colful = np.where(imgcv[:,:, 0] > perc90) indices_colful = np.where(imgcv[:, :, 0] > perc90)
colful_values = imgcv[indices_colful][:, 1] colful_values = imgcv[indices_colful][:, 1]
colful_value_max = np.median(colful_values) colful_value_max = np.median(colful_values)
return np.array([[[colful_value_max]]]) return np.array([[[colful_value_max]]])
class Saturation(Contrast): class Saturation(Contrast):
"""docstring for Saturation""" """docstring for Saturation"""
...@@ -114,7 +118,7 @@ class Saturation(Contrast): ...@@ -114,7 +118,7 @@ class Saturation(Contrast):
imglab = color.rgb2lab(self._img) imglab = color.rgb2lab(self._img)
imglch = color.lab2lch(imglab) imglch = color.lab2lch(imglab)
# TODO geht garnicht, weil nicht angemessen gerundet wird # TODO geht garnicht, weil nicht angemessen gerundet wird
# und skimage auch davor warnt # und skimage auch davor warnt
imglch = imglch.astype(np.uint16) imglch = imglch.astype(np.uint16)
...@@ -144,7 +148,7 @@ class Hue(Contrast): ...@@ -144,7 +148,7 @@ class Hue(Contrast):
def labHcl(self) -> np.uint16: def labHcl(self) -> np.uint16:
"""calculates the Hue value by using the CIE LabHCL colorspace""" """calculates the Hue value by using the CIE LabHCL colorspace"""
imglab = color.rgb2lab(self._img[:,:,::-1]) imglab = color.rgb2lab(self._img[:, :, ::-1])
imglch = color.lab2lch(imglab) imglch = color.lab2lch(imglab)
hues = imglch[:, :, 2] hues = imglch[:, :, 2]
......
...@@ -3,48 +3,48 @@ ...@@ -3,48 +3,48 @@
import numpy as np import numpy as np
import pandas as pd import pandas as pd
import math # import math
# def lab2hc(labpixel, out='both'): # def lab2hc(labpixel, out='both'):
# """returns hue and colorfulness of a pixel # """returns hue and colorfulness of a pixel
# #
# the image pixel has to have CIE Lab colors. # the image pixel has to have CIE Lab colors.
# the conversion follows Fairchild's 2013 conversion equations # the conversion follows Fairchild's 2013 conversion equations
# #
# labpixel : pixel from image using CIE Lab color model # labpixel : pixel from image using CIE Lab color model
# out : 'h' (hue), 'c' (colorfulness) or 'both' (tuple containing hue # out : 'h' (hue), 'c' (colorfulness) or 'both' (tuple containing hue
# and colorfulness : default) # and colorfulness : default)
# """ # """
# #
# def get_hue(a, b): # def get_hue(a, b):
# hue = math.degrees(math.atan(b/a)) # hue = math.degrees(math.atan(b/a))
# return hue # return hue
# #
# def get_colorfulness(a, b): # def get_colorfulness(a, b):
# colorfulness = (a**2 + b**2)**(1/2) # colorfulness = (a**2 + b**2)**(1/2)
# return colorfulness # return colorfulness
# #
# a = labpixel[1] # a = labpixel[1]
# b = labpixel[2] # b = labpixel[2]
# #
# hc = {} # hc = {}
# #
# if not(out == 'c'): # if not(out == 'c'):
# hc['h'] = get_hue(a, b) # hc['h'] = get_hue(a, b)
# elif not(out == 'h'): # elif not(out == 'h'):
# hc['c'] = get_colorfulness(a, b) # hc['c'] = get_colorfulness(a, b)
# #
# return hc # return hc
# TODO fps muss noch implementiert werden # TODO fps muss noch implementiert werden
def time2framenr(time, fps=4): def time2framenr(time, fps=4):
"""counts the frame index for a given timestamp """counts the frame index for a given timestamp
time : timestamp needs to have the form [HH:]MM:SS time : timestamp needs to have the form [HH:]MM:SS
fps : frequency with which frames were taken from the movie fps : frequency with which frames were taken from the movie
""" """
timestmp = time.split(':') timestmp = time.split(':')
in_sec = 0 in_sec = 0
...@@ -54,16 +54,17 @@ def time2framenr(time, fps=4): ...@@ -54,16 +54,17 @@ def time2framenr(time, fps=4):
in_sec += int(timestmp[-2]) * 60 in_sec += int(timestmp[-2]) * 60
in_sec += int(timestmp[-1]) in_sec += int(timestmp[-1])
return in_sec * fps return in_sec * fps
def frame2time(val, fps=4): def frame2time(val, fps=4):
"""transforms framenumbers into timecodes """transforms framenumbers into timecodes
Arguments: Arguments:
val {int} -- number of frame in the movie val {int} -- number of frame in the movie
fps {int} -- time interval by which frames were extracted from the movie fps {int} -- time interval by which frames were extracted from the
movie
Returns: Returns:
np.datetime64 -- timecode of the frame in the movie np.datetime64 -- timecode of the frame in the movie
""" """
...@@ -72,13 +73,15 @@ def frame2time(val, fps=4): ...@@ -72,13 +73,15 @@ def frame2time(val, fps=4):
tstmp = pd.Timedelta(val, unit='s') tstmp = pd.Timedelta(val, unit='s')
return tstmp return tstmp
def luminance(img): def luminance(img):
"""Creates an array of luminance value for each pixel of an image """Creates an array of luminance value for each pixel of an image
The array has the same dimensions as the image. However the third The array has the same dimensions as the image. However the third
does only have the size 1 which contains the luminance value does only have the size 1 which contains the luminance value
""" """
# Luminance Faktoren nach http://introcs.cs.princeton.edu/python/31datatype/luminance.py.html # Luminance Faktoren nach
# http://introcs.cs.princeton.edu/python/31datatype/luminance.py.html
luminance_factors = np.array([.299, .587, .114]) luminance_factors = np.array([.299, .587, .114])
# Erzeugung eines eindimensionalen Arrays für die effizientere Berechnung # Erzeugung eines eindimensionalen Arrays für die effizientere Berechnung
......
...@@ -4,30 +4,32 @@ ...@@ -4,30 +4,32 @@
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from pathlib import Path # TODO wie kann ich third-party module nach außen verstecken from pathlib import Path
import pickle import pickle
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
# TODO Ist der import aus dem selben Pakte so korrekt?
from . import views from . import views
from . import visuals from . import visuals
from . import helpers from . import helpers
# zum Problem mit privaten und öffentlichen Eigenschaften http://www.python-course.eu/python3_properties.php und 'Fluent Python' relativ weit vorne # zum Problem mit privaten und öffentlichen Eigenschaften
# http://www.python-course.eu/python3_properties.php und 'Fluent Python'
# relativ weit vorne.
# numpy gibt beim Versuch zB. size zu schreiben auch ein AttributeError() aus. # numpy gibt beim Versuch zB. size zu schreiben auch ein AttributeError() aus.
class Movie(object): class Movie(object):
"""main class to interact with the colorspace of movieframes""" """main class to interact with the colorspace of movieframes"""
def __init__(self, prefix, folder='./', fps=4): def __init__(self, prefix, folder='./', fps=4):
"""creates an video object holding the frames of the video """creates an video object holding the frames of the video
Arguments: Arguments:
object {self} -- the video object itself object {self} -- the video object itself
prefix {str} -- part of the frames filenames representing the movie prefix {str} -- part of the frames filenames representing the movie
Keyword Arguments: Keyword Arguments:
folder {str} -- folder containing the frames (default: {'./'}) folder {str} -- folder containing the frames (default: {'./'})
fps {int} -- number of frames per second that were extracted from the movie (default: {4}) # before this were 1 fps {int} -- number of frames per second that were extracted from
the movie (default: {4}) # before this were 1
""" """
self._frames = Frames(folder, prefix) self._frames = Frames(folder, prefix)
...@@ -49,18 +51,20 @@ class Movie(object): ...@@ -49,18 +51,20 @@ class Movie(object):
""" """
# transform time to frames if type is time # transform time to frames if type is time
if type is 'time': if type == 'time':
start = helpers.time2framenr(start, self.fps) start = helpers.time2framenr(start, self.fps)
end = helpers.time2framenr(end, self.fps) end = helpers.time2framenr(end, self.fps)
elif type is 'frame': elif type == 'frame':
start = int(start) * mltp start = int(start) * mltp
end = int(end) * mltp end = int(end) * mltp
# funktioniert nur in zsh # funktioniert nur in zsh
# glob = self._frames.folder + self._frames.prefix + '{' + '{0:05d}'.format(start) + '..' + '{0:05d}'.format(end) + '}' + '.png' # glob = self._frames.folder + self._frames.prefix + '{' + '{0:05d}'.
# format(start) + '..' + '{0:05d}'.format(end) + '}' + '.png'
glob_lst = [] glob_lst = []
for frm in range(start, end+1): for frm in range(start, end+1):
glob_lst.append(self._frames.folder + self._frames.prefix + '{0:05d}'.format(frm) + '.png') glob_lst.append(self._frames.folder + self._frames.prefix +
'{0:05d}'.format(frm) + '.png')
cmd = viewer + ' ' + ' '.join(glob_lst) cmd = viewer + ' ' + ' '.join(glob_lst)
Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True) Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True)
...@@ -138,13 +142,13 @@ class Movie(object): ...@@ -138,13 +142,13 @@ class Movie(object):
end: Int which defines the end frame for the description (0 defines end: Int which defines the end frame for the description (0 defines
the unknown end frame) the unknown end frame)
stp: the frequency in frame number by which frames are used to calculate stp: the frequency in frame number by which frames are used to
the contrast calculate the contrast
Returns Returns
------- -------
TODO: a pandas DataFrame containing the frame number, timestamp, bin and TODO: a pandas DataFrame containing the frame number, timestamp, bin
number of pixels contained in the bin and number of pixels contained in the bin
""" """
# set movie start and end postion for the visualization # set movie start and end postion for the visualization
...@@ -157,7 +161,7 @@ class Movie(object): ...@@ -157,7 +161,7 @@ class Movie(object):
data = views.MultivariateSequence(self._frames,) data = views.MultivariateSequence(self._frames,)
data.populate(ctrst=ctrst, method=meth, frm_stp=stp) data.populate(ctrst=ctrst, method=meth, frm_stp=stp)
data = pd.DataFrame(data, columns=['frame', 'bin', 'pixels'], data = pd.DataFrame(data, columns=['frame', 'bin', 'pixels'],
dtype=np.int64) dtype=np.int64)
data['time'] = data['frame'].apply(helpers.frame2time, fps=4) data['time'] = data['frame'].apply(helpers.frame2time, fps=4)
return data return data
...@@ -234,7 +238,8 @@ class Movie(object): ...@@ -234,7 +238,8 @@ class Movie(object):
vis = visuals.MultivariatePlot(multivariate) vis = visuals.MultivariatePlot(multivariate)
vis.plot(multivariate) vis.plot(multivariate)
header = prefix[:-1] + ' MultivariatePlot for ' + ctrst + ' - ' + desc header = prefix[:-1] + ' MultivariatePlot for ' + ctrst + ' - '
header += desc
filename = prefix + 'multivariateplot_' + ctrst + '_' + desc filename = prefix + 'multivariateplot_' + ctrst + '_' + desc
vis.saveplt(fname=filename, title=header) vis.saveplt(fname=filename, title=header)
...@@ -251,7 +256,8 @@ class Movie(object): ...@@ -251,7 +256,8 @@ class Movie(object):
vis = visuals.UnivariatePlot(univariate) vis = visuals.UnivariatePlot(univariate)
# summarizing methods of univariate class # summarizing methods of univariate class
summarizations = ['seqmean', 'seqmad'] # TODO Varianz funktioniert so nicht # TODO Varianz funktioniert so nicht
summarizations = ['seqmean', 'seqmad']
for feature in summarizations: for feature in summarizations:
# compute summarizations for given univariate value # compute summarizations for given univariate value
...@@ -275,8 +281,10 @@ class Movie(object): ...@@ -275,8 +281,10 @@ class Movie(object):
vis.plot(univariate) vis.plot(univariate)
# save univariate plot # save univariate plot
header = prefix[:-1] + ' UnivariatePlot for ' + ctrst + ' - ' + desc header = prefix[:-1] + ' UnivariatePlot for ' + ctrst + ' - '
filename = self._frames.prefix + 'univariateplot_' + ctrst + '_' + desc header += desc
filename = self._frames.prefix + 'univariateplot_' + ctrst + '_'
filename += desc
vis.saveplt(fname=filename, title=header) vis.saveplt(fname=filename, title=header)
with open(prefix[:-1] + '_summary.pickle', 'wb') as f: with open(prefix[:-1] + '_summary.pickle', 'wb') as f:
...@@ -332,9 +340,10 @@ class Frames(object): ...@@ -332,9 +340,10 @@ class Frames(object):
def get_frame_list(self): def get_frame_list(self):
"""returns the list of paths for all frame files in the current folder """returns the list of paths for all frame files in the current folder
Returns: Returns:
list -- returns the list of paths for all frame files in the current folder list -- returns the list of paths for all frame files in the
current folder
""" """
frm_path = Path(self.folder) frm_path = Path(self.folder)
return list(sorted(frm_path.glob('*.png'))) return list(sorted(frm_path.glob('*.png')))
......
...@@ -5,11 +5,11 @@ ...@@ -5,11 +5,11 @@
# TODO import as cv # TODO import as cv
import cv2 import cv2
import numpy as np import numpy as np
import peakutils # import peakutils
from .helpers import luminance # from .helpers import luminance
from copy import deepcopy from copy import deepcopy
from . import contrasts from . import contrasts
from . import movie # from . import movie
# subclassing numpy ndarray # subclassing numpy ndarray
# Vorgehen: https://docs.scipy.org/doc/numpy/user/basics.subclassing.html # Vorgehen: https://docs.scipy.org/doc/numpy/user/basics.subclassing.html
...@@ -17,6 +17,8 @@ from . import movie ...@@ -17,6 +17,8 @@ from . import movie
# andere ownership Probleme könne angeblich mit out= gelöst werden # andere ownership Probleme könne angeblich mit out= gelöst werden
# "Use __new__ when you need to control the creation of a new instance. # "Use __new__ when you need to control the creation of a new instance.
# Use __init__ when you need to control initialization of a new instance." # Use __init__ when you need to control initialization of a new instance."
class View(np.ndarray): class View(np.ndarray):
"""Core class for the representation of colour contrasts in Movies """Core class for the representation of colour contrasts in Movies
...@@ -41,7 +43,8 @@ class View(np.ndarray): ...@@ -41,7 +43,8 @@ class View(np.ndarray):
Parameters Parameters
---------- ----------
frames : itten.movie.Frames frames : itten.movie.Frames
input_array : itten.contrasts.View # TODO wie schaffte np lower case object input_array : itten.contrasts.View # TODO wie schaffte np lower
case object
contrast : String # Modifizieren Channel Integer to String contrast : String # Modifizieren Channel Integer to String
frame_step : Int frame_step : Int
savefig : Boolean savefig : Boolean
...@@ -64,7 +67,8 @@ class View(np.ndarray): ...@@ -64,7 +67,8 @@ class View(np.ndarray):
return obj return obj
def __array_finalize__(self, obj): def __array_finalize__(self, obj):
if obj is None: return if obj is None:
return
self._frames = getattr(obj, '_frames', None) self._frames = getattr(obj, '_frames', None)
self._contrast = getattr(obj, '_contrast', None) self._contrast = getattr(obj, '_contrast', None)
self._frame_step = getattr(obj, '_frame_step', None) self._frame_step = getattr(obj, '_frame_step', None)
...@@ -106,8 +110,12 @@ class View(np.ndarray): ...@@ -106,8 +110,12 @@ class View(np.ndarray):
frm_nrs = np.subtract(frm_nrs, self._frame_step) frm_nrs = np.subtract(frm_nrs, self._frame_step)
return frm_nrs.flatten() return frm_nrs.flatten()
# subclassing subclass of numpy http://stackoverflow.com/questions/7342637/how-to-subclass-a-subclass-of-numpy-ndarray # subclassing subclass of numpyhttp://stackoverflow.com/questions/7342637/
# TODO es gibt noch das Problem, dass numpy nach mehreren Berechnungen von drive eine max recursion Warnung ausgiebt, warum? Brauche ich __del__ # how-to-subclass-a-subclass-of-numpy-ndarray
# TODO es gibt noch das Problem, dass numpy nach mehreren Berechnungen von
# drive eine max recursion Warnung ausgiebt, warum? Brauche ich __del__
class MultivariateSequence(View): class MultivariateSequence(View):
def __new__(cls, frames, input_array=None): def __new__(cls, frames, input_array=None):
"""Represents a movie contrast in terms of stacked histograms """Represents a movie contrast in terms of stacked histograms
...@@ -117,12 +125,12 @@ class MultivariateSequence(View): ...@@ -117,12 +125,12 @@ class MultivariateSequence(View):
Parameters Parameters
---------- ----------
TODO threshold : the minimum number of pixels that need to appear in TODO threshold : the minimum number of pixels that need to appear
in a certain bin so that the bin will be included in the output in a certain bin so that the bin will be included in the output
data. (Needs to be modifiable in relation to the total number of data. (Needs to be modifiable in relation to the total number
pixels in the frame, that means on the frame size 240p60 etc.) of pixels in the frame, that means on the frame size 240p60
Oder Threshold ganz raus, weil das eigentlich eine Sache der etc.) Oder Threshold ganz raus, weil das eigentlich eine Sache
Visualisierung ist auszusortieren. der Visualisierung ist auszusortieren.
Returns Returns
------- -------
...@@ -137,11 +145,13 @@ class MultivariateSequence(View): ...@@ -137,11 +145,13 @@ class MultivariateSequence(View):
return obj return obj
def __array_finalize__(self, obj): def __array_finalize__(self, obj):
if obj is None: return if obj is None:
return
View.__array_finalize__(self, obj) View.__array_finalize__(self, obj)
self._threshold = getattr(obj, '_threshold', None) self._threshold = getattr(obj, '_threshold', None)
def populate(self, ctrst='monochromatic', method='luminance', frm_stp=10, bins=16, thrsh=6000, start=1, end=0): def populate(self, ctrst='monochromatic', method='luminance', frm_stp=10,
bins=16, thrsh=6000, start=1, end=0):
"""doc (aus __new__ zusammentragen) """doc (aus __new__ zusammentragen)
""" """
...@@ -151,23 +161,27 @@ class MultivariateSequence(View): ...@@ -151,23 +161,27 @@ class MultivariateSequence(View):
self._frame_step = frm_stp self._frame_step = frm_stp
self._bins = bins self._bins = bins
self._threshold = thrsh self._threshold = thrsh
# TODO dafür müssen erst getters und setters in movie.frames definiert werden # TODO dafür müssen erst getters und setters in movie.frames definiert
# werden
# self._frames.start = start # self._frames.start = start
# self._frames.end = end # self._frames.end = end
contrast_points = np.empty((0, 3), dtype=np.uint32) contrast_points = np.empty((0, 3), dtype=np.uint32)
# pwd list sollte in Frames sein und hier nur durchlaufen werden # pwd list sollte in Frames sein und hier nur durchlaufen werden
for frm_nr in range(self._frames.start, self._frames.end, self._frame_step): for frm_nr in range(self._frames.start, self._frames.end,
self._frame_step):
# FIX for legacy numbering scheme of files 1 instead of 0001 # FIX for legacy numbering scheme of files 1 instead of 0001
# TODO remove this ridiculous fix and the whole pwd building which # TODO remove this ridiculous fix and the whole pwd building which
# now solved by having implemented sorted(Path()…) in Frames # now solved by having implemented sorted(Path()…) in Frames
pwd = "" pwd = ""
if '_0' in str(self._frames.frames[0]): if '_0' in str(self._frames.frames[0]):
pwd = self._frames.folder + self._frames.prefix + '{0:05d}'.format(frm_nr) + '.png' pwd = self._frames.folder + self._frames.prefix
pwd += '{0:05d}'.format(frm_nr) + '.png'
else: else:
pwd = self._frames.folder + self._frames.prefix + str(frm_nr) + '.png' pwd = self._frames.folder + self._frames.prefix + str(frm_nr)
pwd += '.png'