contrasts.py 5.83 KB
Newer Older
1
2
3
4
5
6
7
8
#!/usr/bin/env python
# -*- coding: utf-8 -*-


# TODO import as cv
import cv2
import numpy as np
from .helpers import luminance
9
from copy import deepcopy
10

11
12
13
14
# 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
15
16
# "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."
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
       """
31
    def __new__(cls, frames, input_array=None):
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
        """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
        """
50
51
52
53
54
55
56
        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
57
58
59
        obj._contrast = 2
        obj._frame_step = 10
        obj._bins = 256
60
61
62
63
64
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self._frames = getattr(obj, '_frames', None)
65
66
        self._contrast = getattr(obj, '_contrast', None)
        self._frame_step = getattr(obj, '_frame_step', None)
67
68
69
70
71
        self._bins = getattr(obj, '_bins', None)

    def __array_wrap__(self, out_arr, context=None):
        return np.ndarray.__array_wrap__(self, out_arr, context)

72

73
74
# 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__
75
class VHistStack(View):
76
    def __new__(cls, frames, input_array=None):
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
        """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
        """

98
99
        obj = View.__new__(cls, frames, input_array=input_array)
        obj._threshold = 60000
100
101
102
103
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
104
        View.__array_finalize__(self, obj)
105
106
        self._threshold = getattr(obj, '_threshold', None)

107
    # TODO jetzt ausschließlich mit self numpy rechnen statt mit contrast_points liste
108
109
110
111
112
113
114
115
116
117
118
119
120
    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

121
122
        contrast_points = []
        # pwd list sollte in Frames sein und hier nur durchlaufen werden
123
        for frm_nr in range(self._frames.start, self._frames.end, self._frame_step):
124
125
            pwd = self._frames.folder + self._frames.prefix + str(frm_nr) + '.png'

126
            img = cv2.imread(pwd)  # BGR
127

128
            # TODO Dictionary um Parameter auf Kontrast Funktion zu mappen
129

130
131
132
133
134
135
            # 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))
136
137
            else:
                img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV_FULL)
138
                hist_value = cv2.calcHist([img_hsv], [self._contrast], None, [16], [0, 256])
139
140
141
142
143

            for bin_index, point in enumerate(hist_value):
                if point > self._threshold:
                    contrast_points.append((frm_nr, bin_index, int(point)))

144
        contrast_points = np.asarray(contrast_points, np.uint8)
145
146
        shape = contrast_points.shape
        self.resize(shape, refcheck=False)
147
        self[:, :] = contrast_points
148
149

        return deepcopy(self)  # TODO does not create a new object