#!/usr/bin/env python # -*- coding: utf-8 -*- # TODO import as cv import cv2 import numpy as np from .helpers import luminance from copy import deepcopy # subclassing numpy ndarray # Vorgehen: https://docs.scipy.org/doc/numpy/user/basics.subclassing.html # resize Probleme https://sourceforge.net/p/numpy/mailman/message/12594801/ # 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 __init__ when you need to control initialization of a new instance." class View(np.ndarray): """Core class for the representation of colour contrasts in Movies View is the basis class for specific ways to represent colour contrasts. It does hold the definitions of contrasts itself. Objects of class View subclass the numpy array class and hence inherit numpy methods. However, it is not recommended to use functions which manipulate the array in terms of structure. In this case some of the additional functions which are implemented by this class and its subclasses might not lead to reasonable results. Attributes: TODO Docstring komplettieren und Verfahren überprüfen """ def __new__(cls, frames, input_array=None): """instantiates the view class instantiation complies with the recommendation for subclassing numpy.ndarray Parameters ---------- frames : itten.movie.Frames input_array : itten.contrasts.View # TODO wie schaffte np lower case object contrast : String # Modifizieren Channel Integer to String frame_step : Int savefig : Boolean Returns ------- Object : View Empty numpy.ndarray of type View """ obj = input_array if type(obj) == np.ndarray: obj = np.asarray(input_array, dtype=np.uint8).view(cls).copy() else: input_array = np.zeros((0), dtype=np.uint8) obj = np.asarray(input_array).view(cls).copy() obj._frames = frames obj._contrast = 2 obj._frame_step = 10 obj._bins = 256 return obj def __array_finalize__(self, obj): if obj is None: return self._frames = getattr(obj, '_frames', None) self._contrast = getattr(obj, '_contrast', None) self._frame_step = getattr(obj, '_frame_step', None) self._bins = getattr(obj, '_bins', None) def __array_wrap__(self, out_arr, context=None): return np.ndarray.__array_wrap__(self, out_arr, context) # subclassing subclass of numpy http://stackoverflow.com/questions/7342637/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 VHistStack(View): def __new__(cls, frames, input_array=None): """Represents a movie contrast in terms of stacked histograms For each defined frame a histogram is calculated and each bin that exceeds threshold is considered in the output array Parameters ---------- bins : Int Number of bins for the calculation of the histogram thrsh : Int Threshhold defining the number of pixels a bin needs to contain to be considered in the result Returns ------- Object : VHistStack VHistStack is a 2-dimensional numpy array which contains the frame number, the bin number and a quantifier which represents the relative weight of the bin in the frame """ obj = View.__new__(cls, frames, input_array=input_array) obj._threshold = 60000 return obj def __array_finalize__(self, obj): if obj is None: return View.__array_finalize__(self, obj) self._threshold = getattr(obj, '_threshold', None) # TODO jetzt ausschließlich mit self numpy rechnen statt mit contrast_points liste def populate(self, ctrst=2, frm_stp=10, bins=16, thrsh=60000, start=1, end=0): """doc (aus __new__ zusammentragen) """ # set class properties self._contrast = ctrst self._frame_step = frm_stp self._bins = bins self._threshold = thrsh # TODO dafür müssen erst getters und setters in movie.frames definiert werden # slef._frames.start = start # slef._frames.end = end contrast_points = [] # 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 = self._frames.folder + self._frames.prefix + str(frm_nr) + '.png' img = cv2.imread(pwd) # BGR # TODO Dictionary um Parameter auf Kontrast Funktion zu mappen # so wie hier für 2 das ist die Referznimplementierung # luminances gibt ein Bild mit den luminanz werten in der # 3. Dimension zurück if self._contrast == 2: luminances = luminance(img) hist_value, _ = np.histogram(luminances.flatten(), bins=self._bins, range=(0, 256)) else: img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV_FULL) hist_value = cv2.calcHist([img_hsv], [self._contrast], None, [16], [0, 256]) for bin_index, point in enumerate(hist_value): if point > self._threshold: contrast_points.append((frm_nr, bin_index, int(point))) contrast_points = np.asarray(contrast_points, np.uint8) shape = contrast_points.shape self.resize(shape, refcheck=False) self[:, :] = contrast_points return deepcopy(self) # TODO does not create a new object