contrasts.py 5.62 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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, ctrst='lightDark',
                frm_stp=10, savefig=False):
        """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
        """
51
52
53
54
55
56
57
        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
58
59
60
        obj._contrast = ctrst
        obj._frame_step = frm_stp
        obj._savefig = savefig
61
62
63
64
65
        return obj

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

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

75

76
77
# 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__
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
class VHistStack(View):
    def __new__(cls, frames, input_array=None, ctrst='lightDark',
                frm_stp=10, bins=16, thrsh=60000, savefig=False):
        """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, ctrst=ctrst,
                           frm_stp=frm_stp, savefig=savefig)
        obj._bins = bins
        obj._threshold = thrsh
106
107
108
109
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
110
        View.__array_finalize__(self, obj)
111
112
113
        self._bins = getattr(obj, '_bins', None)
        self._threshold = getattr(obj, '_threshold', None)

114

115
    # TODO jetzt ausschließlich mit self numpy rechnen statt mit contrast_points liste
116
    def derive(self):
117
118
        contrast_points = []
        # pwd list sollte in Frames sein und hier nur durchlaufen werden
119
        for frm_nr in range(self._frames.start, self._frames.end, self._frame_step):
120
121
122
123
            pwd = self._frames.folder + self._frames.prefix + str(frm_nr) + '.png'

            img = cv2.imread(pwd)

124
            if self._contrast == 2:
125
126
127
128
129
130
131
                _img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                luminances = luminance(_img)
                hist_value, _ = np.histogram(luminances, bins=self._bins, range=(0, 255))

            else:

                img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV_FULL)
132
                hist_value = cv2.calcHist([img_hsv], [self._contrast], None, [16], [0, 256])
133
134
135
136
137

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

138
        contrast_points = np.asarray(contrast_points, np.uint8)
139
140
        shape = contrast_points.shape
        self.resize(shape, refcheck=False)
141
        self[:, :] = contrast_points
142
143

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