e519c94f010ff25d5d08c7302091d7fc0902cd6b
[experiments/opencv_trail_effect.git] / Trail.hpp
1 #ifndef TRAIL_HPP
2 #define TRAIL_HPP
3
4 #include <opencv2/opencv.hpp>
5 #include "Frame.hpp"
6
7 typedef std::list<Frame *> trail_t;
8
9 class Trail {
10 private:
11         virtual void iterate(cv::Mat& frame, void (*action)(cv::Mat&, Frame *, int, int)) = 0;
12
13         cv::Mat *background = NULL;
14         bool redraw_current_frame;
15         bool persistent;
16
17         void (*drawStrategy)(cv::Mat&, Frame *, int, int);
18
19         static void frameCopy(cv::Mat& destination, Frame *frame, int frame_index, int trail_size)
20         {
21                 (void) frame_index;
22                 (void) trail_size;
23                 frame->copyTo(destination);
24         }
25
26         static void frameAccumulate(cv::Mat& destination, Frame *frame, int frame_index, int trail_size)
27         {
28                 (void) frame_index;
29                 (void) trail_size;
30                 cv::accumulate(frame->getData(), destination, frame->getMask());
31         }
32
33         static void frameFadeCopy(cv::Mat& destination, Frame *frame, int frame_index, int trail_size)
34         {
35                 double weight = ((double) frame_index) / trail_size;
36                 cv::Mat weighted_frame;
37
38                 frame->getData().convertTo(weighted_frame, destination.type(), weight);
39                 weighted_frame.copyTo(destination, frame->getMask());
40         }
41
42         static void frameFadeAccumulate(cv::Mat& destination, Frame *frame, int frame_index, int trail_size)
43         {
44                 double weight = ((double) frame_index) / trail_size;
45                 cv::accumulateWeighted(frame->getData(), destination, weight, frame->getMask());
46         }
47
48         static void frameAverage(cv::Mat& destination, Frame *frame, int frame_index, int trail_size)
49         {
50                 (void) frame_index;
51                 double weight = 1. / trail_size;
52                 cv::accumulateWeighted(frame->getData(), destination, weight, frame->getMask());
53         }
54
55 protected:
56         trail_t trail;
57
58 public:
59         Trail(int trail_length, cv::Size frame_size)
60         {
61                 redraw_current_frame = false;
62                 drawStrategy = frameCopy;
63                 persistent = false;
64
65                 if (trail_length < 0) {
66                         persistent = true;
67                         background = new cv::Mat(frame_size, CV_8UC3);
68                 }
69
70                 if (trail_length < 1)
71                         trail_length = 1;
72
73                 for (int i = 0; i < trail_length; i++)
74                         trail.push_back(new Frame(frame_size));
75         }
76
77         virtual ~Trail()
78         {
79                 trail_t::iterator trail_it;
80                 for (trail_it = trail.begin(); trail_it != trail.end(); trail_it++) {
81                         delete(*trail_it);
82                 }
83                 trail.clear();
84                 delete background;
85         }
86
87         void setBackground(cv::Mat trail_background)
88         {
89                 delete background;
90                 background = new cv::Mat(trail_background);
91         }
92
93         int setDrawingMethod(std::string drawing_method)
94         {
95                 if (drawing_method == "copy") {
96                         drawStrategy = frameCopy;
97                 } else if (drawing_method == "accumulate") {
98                         drawStrategy = frameAccumulate;
99                 } else if (drawing_method == "fadecopy") {
100                         drawStrategy = frameFadeCopy;
101                 } else if (drawing_method == "fadeaccumulate") {
102                         drawStrategy = frameFadeAccumulate;
103                 } else if (drawing_method == "average") {
104                         drawStrategy = frameAverage;
105                 } else {
106                         return -1;
107                 }
108                 return 0;
109         }
110
111         void setRedrawCurrentFrame(bool do_redraw_current_frame)
112         {
113                 redraw_current_frame = do_redraw_current_frame;
114         }
115
116         void update(Frame *frame)
117         {
118                 Frame *front = trail.front();
119                 trail.pop_front();
120                 delete front;
121
122                 trail.push_back(frame);
123         }
124
125         void draw(cv::Mat& destination)
126         {
127                 cv::Mat float_destination;
128
129                 if (background)
130                         background->convertTo(float_destination, CV_32FC3);
131                 else
132                         destination.convertTo(float_destination, CV_32FC3);
133
134                 iterate(float_destination, drawStrategy);
135                 float_destination.convertTo(destination, destination.type());
136
137                 if (redraw_current_frame) {
138                         Frame *current_frame = trail.back();
139                         current_frame->getData().copyTo(destination, current_frame->getMask());
140                 }
141
142                 /* remember the current trail in the background image */
143                 if (persistent)
144                         float_destination.convertTo(*background, background->type());
145         }
146 };
147
148 class ForwardTrail: public Trail {
149         void iterate(cv::Mat& destination, void (*action)(cv::Mat&, Frame *, int, int))
150         {
151                 int index = 0;
152                 trail_t::iterator trail_it;
153                 for (trail_it = trail.begin(); trail_it != trail.end(); trail_it++) {
154                         action(destination, *trail_it, ++index, trail.size());
155                 }
156         }
157
158 public:
159         ForwardTrail(int trail_lenght, cv::Size frame_size) : Trail(trail_lenght, frame_size)
160         {
161         }
162 };
163
164 class ReverseTrail: public Trail {
165         void iterate(cv::Mat& destination, void (*action)(cv::Mat&, Frame *, int, int))
166         {
167                 int index = 0;
168                 trail_t::reverse_iterator trail_it;
169                 for (trail_it = trail.rbegin(); trail_it != trail.rend(); trail_it++) {
170                         action(destination, *trail_it, ++index, trail.size());
171                 }
172         }
173
174 public:
175         ReverseTrail(int trail_lenght, cv::Size frame_size) : Trail(trail_lenght, frame_size)
176         {
177         }
178 };
179
180 #endif // TRAIL_HPP