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

refac(pkg): correct all flake8 errors

parent 11342779
...@@ -5,6 +5,7 @@ from skimage import color ...@@ -5,6 +5,7 @@ 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):
...@@ -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
...@@ -75,18 +78,19 @@ class Monochromatic(Contrast): ...@@ -75,18 +78,19 @@ class Monochromatic(Contrast):
# 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)
...@@ -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,7 +3,7 @@ ...@@ -3,7 +3,7 @@
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'):
...@@ -62,7 +62,8 @@ def frame2time(val, fps=4): ...@@ -62,7 +62,8 @@ def frame2time(val, fps=4):
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,17 +4,18 @@ ...@@ -4,17 +4,18 @@
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"""
...@@ -27,7 +28,8 @@ class Movie(object): ...@@ -27,7 +28,8 @@ class Movie(object):
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
...@@ -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:
...@@ -334,7 +342,8 @@ class Frames(object): ...@@ -334,7 +342,8 @@ class Frames(object):
"""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'
img = cv2.imread(pwd) # BGR img = cv2.imread(pwd) # BGR
...@@ -183,10 +197,12 @@ class MultivariateSequence(View): ...@@ -183,10 +197,12 @@ class MultivariateSequence(View):
for bin_index, point in enumerate(hist_value): for bin_index, point in enumerate(hist_value):
if int(point) > self._threshold: if int(point) > self._threshold:
entry = np.array([[frm_nr, bin_index, point]], dtype=np.uint32) entry = np.array([[frm_nr, bin_index, point]],
dtype=np.uint32)
contrast_points = np.vstack((contrast_points, entry)) contrast_points = np.vstack((contrast_points, entry))
# irgendwie prüfen, ob ich contrast_points insgesamt durch self ersetzen kann # irgendwie prüfen, ob ich contrast_points insgesamt durch self
# ersetzen kann
contrast_points = np.asarray(contrast_points, np.uint32) contrast_points = np.asarray(contrast_points, np.uint32)
shape = contrast_points.shape shape = contrast_points.shape
self.resize(shape, refcheck=False) self.resize(shape, refcheck=False)
...@@ -196,150 +212,6 @@ class MultivariateSequence(View): ...@@ -196,150 +212,6 @@ class MultivariateSequence(View):
return deepcopy(self) # TODO does not create a new object return deepcopy(self) # TODO does not create a new object
class BivariateSequence(View):
def __new__(cls, frames, input_array=None):
"""Represents a movie contrast in terms minbound maxbound values
For each defined frame a histogram is calculated and each bin that
exceeds threshold is considered in the output array
Parameters
----------
Returns
-------
Object : BivariateSequence
"""
obj = View.__new__(cls, frames, input_array=input_array)
return obj
def __array_finalize__(self, obj):
if obj is None: return
View.__array_finalize__(self, obj)
# das kann ich jetzt auch mit quantilen machen
def populate(self, variant='peak', ctrst='monochromatic',
method='luminance', frm_stp=10, bins=256):
"""Creates a scatterplot for the dynamic of contrast across movie frames
variant: peak or bin (one of max/min peak; uper/lower mean)
threshold: for the peak variant TODO
smooth: smooth plot TODO
"""
# set class properties
self._variant = variant
self._contrast = ctrst
self._method = method
self._frame_step = frm_stp
self._bins = bins
# TODO um start und end in der Methode zu parametrisieren müssen erst
# getters und setters in movie.frames definiert werden
# self._frames.start = start
# self._frames.end = end
contrast_points = np.empty((0, 2), dtype=np.uint32)
# sofern kein oder nur ein Peak gefunden wird, man könnte dann auch
# noch einen Durchlauf mit geringeren thres und min_dist versuceh
lastmin = 0
lastmax = 256
# 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):
pwd = ""
if '_0' in str(self._frames.frames[0]):
pwd = self._frames.folder + self._frames.prefix + '{0:05d}'.format(frm_nr) + '.png'
else:
pwd = self._frames.folder + self._frames.prefix + str(frm_nr) + '.png'
img = cv2.imread(pwd)
# BREAK: Funktioniert nicht
if method == 'bin':
hist_values = cv2.calcHist([img_hsv], [self._channel], None,
[256], [0, 256])
hist_mins = hist_values[0:127].flatten().tolist()
hist_maxs = hist_values[128:256].flatten().tolist()
# Für jeden Frame wird jeder Kontrastwert mit der Anzahl der
# Pixel für diesen Kontrastwert multipliziert
# So wird der gesamte Kontrastwert des Frames sowie errechnet
bin_total = 0
total_value = 0
for bin_id, points in enumerate(hist_mins):
bin_total = (bin_id + 1) * points
total_value += bin_total
sum_mins = int(sum(hist_mins))
sum_maxs = int(sum(hist_maxs))
if int(total_value) == 0:
total_value = [(bin_nr, value) for bin_nr, value in
enumerate(hist_maxs) if
int(value) > 0][0][0]
mins.append(total_value)
else:
mins.append(int(total_value / sum_mins))
bin_total = 0
total_value = 0
for bin_id, points in enumerate(hist_maxs):
bin_total = (bin_id + 1) * points
total_value += bin_total
# if there are no values in hist_max take highes bin with value
# from hist_mins
if int(total_value) == 0:
total_value = [(bin_nr, value) for bin_nr, value in
enumerate(hist_mins) if
int(value) > 0][-1][0]
maxs.append(total_value)
else:
maxs.append(int(total_value / sum(hist_maxs)) + 127)
# peak variant
else:
ctrst_cls = self._get_ctrst_cls_name(self._contrast)
ctrst_img = ctrst_cls(img).ctrst
hist_value, _ = np.histogram(ctrst_img.flatten(),
bins=self._bins, range=(0, 256))
peaks = peakutils.indexes(hist_value.flatten(), thres=0.2,
min_dist=15)
# Abfangen von von nur 1 oder keinem Peak
if len(peaks) > 1:
lastmin = peaks[0]
lastmax = peaks[-1]
contrast_points = np.vstack((contrast_points,
[lastmin, lastmax]))
elif len(peaks) == 1:
# je nachdem ob der neue peak dem alten min oder max wert
# näher liegt wird er dem einen oder Anderen zugeschlagen
if (lastmax - peaks[0]) <