movie.py 7.05 KB
Newer Older
1
#!/ur/bin/env python
2
3
4
5
6
# -*- coding: utf-8 -*-

from pathlib import Path  # TODO wie kann ich third-party module nach außen verstecken

# TODO Ist der import aus dem selben Pakte so korrekt?
7
from . import views
8
9
10
from . import visuals
import numpy as np

11

12
13
# 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.
14
15
16
class Movie(object):
    """main class to interact with the colorspace of movieframes"""
    def __init__(self, prefix, folder='./'):  # TODO platform independent
17
18
        self._frames = Frames(folder, prefix)
        self.fsize = self._frames.frm_cnt
19

20
    # TODO Warum ist die hier?
21
22
    def light_dark(self):
        """compute the light/dark contrast of the movie """
23
        light_dark_ctrst = views.LightDark(self._frames)
24
        return light_dark_ctrst.hist_vstack()
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
    def describe(self, desc=False, start=1, end=0, stp=5):
        """Calculates each feature provided by Itten for the movie instance

        Summary values will be returned in a python dictionary. Contrast
        sequences will not be returned due to save memory. The method which
        will be used to compute each contrast is the contrast class' default
        method. Instead the will be plotted using Itten Sequence Plots. More
        precisely MultivariatePlot and UnivariatePlot will be stored on disk
        for each contrast type.  The filename follows the Pattern prefix +
        contrast.

        Parameters
        ----------
        start: Int which defines the start frame for the description
        end: Int which defines the end frame for the description (0 defines
             the unknown end frame)

        Returns
        -------
        Dictionary: Dictionary which contains summarizing statistics The
                    Dictionary keys carry the names of the type of
                    summarization. For each contrast it contains: min, max,
                    mean, median, 25, 75, standard deviation, variance. And for
                    each of this values the same set of values are computed.
        ToDo
        ----
        - outsource summary/feature loop to function which can be accessed
          by the view class
        - pickle view data
        """
        # set properties of the current function call
        self._frames.start = start
        self._frames.end = end
        prefix = self._frames.prefix
        if not(desc):
            desc = 'Frame ' + str(start) + ' bis ' + str(end)

        # Summary Dictionary
        title = prefix[:-1]
        summary = {title: {}}

        # available contrasts
        contrasts = ['saturation', 'light_dark']

        # compute all available statistics for each contrast
        for ctrst in contrasts:

            summary[title][ctrst] = {}

            # compute multivariatee contrast representation
            multivariate = views.MultivariateSequence(self._frames)
            multivariate.populate(ctrst=ctrst, frm_stp=stp)

            # TODO: pickle instance instead of just deleating it!

            # plot multivariate view
            vis = visuals.MultivariatePlot(multivariate)
            vis.plot(multivariate)

            header = prefix[:-1] + ' MultivariatePlot for ' + ctrst + ' - ' + desc
            filename = prefix + 'multivariateplot_' + ctrst + '_' + desc
            vis.saveplt(fname=filename, title=header)

            # compute summarizations for current contrast
            univariate = views.UnivariateSequence(self._frames)

            # TODO Workaround, becaus frm_stp is not part of Frames classbut
            # view class so when I instantiate vis below it defaults to the
            # __init__ value 10 and not the value set by the call of describe.
            # This leads to a matplotlib error
            univariate._frame_step = stp

            # instantiate plot for all univariate summarizations
            vis = visuals.UnivariatePlot(univariate)

            # summarizing methods of univariate class
            summarizations = ['seqmean', 'seqmad', 'seqvar']  # TODO Varianz funktioniert so nicht

            for feature in summarizations:
                # compute summarizations for given univariate value
                getattr(univariate, feature)(ctrst=ctrst, frm_stp=stp)

                # TODO Pickle current instance state

                # describe current feature by summarizing statistics
                summary[title][ctrst][feature[3:]] = {
                        'minv': int(univariate.min()),
                        'maxv': int(univariate.max()),
                        'mean': int(univariate.mean()),
                        'median': int(np.median(univariate)),
                        'perc25': int(np.percentile(univariate, 25)),
                        'perc75': int(np.percentile(univariate, 75)),
                        'std': int(univariate.std()),
                        'var': int(univariate.var())
                        }

                # plot current summarization current univariate contrast plot
                vis.plot(univariate)

            # save univariate plot
            header = prefix[:-1] + ' UnivariatePlot for ' + ctrst + ' - ' + desc
            filename = self._frames.prefix + 'univariateplot_' + ctrst + '_' + desc
            vis.saveplt(fname=filename, title=header)

        return summary

132
133

class Frames(object):
134
    # TODO getters und setters für start und end setzen
135
    # TODO frm_stp sollte definitiv Teil der Frames Klasse werden
136
137
138
139
140
141
142
    """Parses movie frames properties"""
    def __init__(self, folder, prefix, start=1, end=0):
        self.folder = folder
        self.prefix = prefix
        self.frames = self.get_frame_list()
        self.frm_length = self.count_total_frames()
        self.start = start
143
144
145
        self.end = end
        self.frm_cnt = 0

146
147
148
149
    # TODO start als property erzeugt bisher eine Endlosschleife wei
    # count_frames sart und end brauchen und so gegenseitig sart und end nicht
    # gesetzt wird

150
151
152
153
154
155
156
157
    @property
    def end(self):
        return self.__end

    @end.setter
    def end(self, nr):
        if nr == 0:
            self.__end = self.frm_length
158
            self.frm_cnt = self.count_frames()
159
160
        elif nr > self.frm_length:
            self.__end = self.frm_length - 1
161
            self.frm_cnt = self.count_frames()
162
163
        elif nr < self.start:
            self.__end = self.start + 1
164
            self.frm_cnt = self.count_frames()
165
166
        else:
            self.__end = nr
167
            self.frm_cnt = self.count_frames()
168
169
170
171
172
173
174
175
176

    @property
    def frm_cnt(self):
        return self.__frm_cnt

    @frm_cnt.setter
    def frm_cnt(self, nr):
        count = self.count_frames()
        self.__frm_cnt = count
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

    def get_frame_list(self):
        frm_path = Path(self.folder)
        return list(frm_path.glob('*.png'))

    def count_total_frames(self):
        return len(self.frames)

    def count_frames(self):
        return self.end - (self.start - 1)

    def _get_end_frame(self, end):
        if end == 0:
            return self.frm_length
        else:
            return end