dynamic keyframes, textbox rework, andrea ffmpeg.opts, perpetual chkpt undo, lv2...
[goodguy/history.git] / cinelerra-5.1 / plugins / gaborobj / gaborobj.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  * 
19  */
20
21 #include "clip.h"
22 #include "filexml.h"
23 #include "gaborobj.h"
24 #include "gaborobjwindow.h"
25 #include "language.h"
26 #include "mutex.h"
27
28 REGISTER_PLUGIN(GaborObj)
29
30
31 GaborObjConfig::GaborObjConfig()
32 {
33 }
34
35 int GaborObjConfig::equivalent(GaborObjConfig &that)
36 {
37         return 1;
38 }
39
40 void GaborObjConfig::copy_from(GaborObjConfig &that)
41 {
42 }
43
44 void GaborObjConfig::interpolate( GaborObjConfig &prev, GaborObjConfig &next, 
45         long prev_frame, long next_frame, long current_frame)
46 {
47         copy_from(next);
48 }
49
50 void GaborObjConfig::limits()
51 {
52 }
53
54
55 GaborObj::GaborObj(PluginServer *server)
56  : PluginVClient(server)
57 {
58         int steps = 16;
59         Size ksize(31, 31);
60         for( int i=0; i<steps; ++i ) {
61                 double theta = i * M_PI/steps;
62                 Mat kern = getGaborKernel(ksize, 4.0, theta, 10.0, 0.5, 0, CV_32F);
63                 float sum = 0;
64                 for( int k=0; k<kern.rows; ++k ) {
65                         float *kp = kern.ptr<float>(k);
66                         for( int j=0; j<kern.cols; ++j ) sum += *kp++;
67                 }
68                 kern /= 1.5*sum;
69                 filters.push_back(kern);
70         }
71         gabor_engine = 0;
72         remap_lock = new ::Mutex("GaborObj::remap_lock");
73 }
74
75 GaborObj::~GaborObj()
76 {
77         delete gabor_engine;
78         delete remap_lock;
79 }
80
81 const char* GaborObj::plugin_title() { return N_("GaborObj"); }
82 int GaborObj::is_realtime() { return 1; }
83
84 NEW_WINDOW_MACRO(GaborObj, GaborObjWindow);
85 LOAD_CONFIGURATION_MACRO(GaborObj, GaborObjConfig)
86
87 void GaborObj::save_data(KeyFrame *keyframe)
88 {
89         FileXML output;
90
91 // cause data to be stored directly in text
92         output.set_shared_output(keyframe->xbuf);
93         output.tag.set_title("GABOROBJ");
94         output.append_tag();
95         output.append_newline();
96         output.tag.set_title("/GABOROBJ");
97         output.append_tag();
98         output.append_newline();
99         output.terminate_string();
100 }
101
102 void GaborObj::read_data(KeyFrame *keyframe)
103 {
104         FileXML input;
105         input.set_shared_input(keyframe->xbuf);
106
107         int result = 0;
108         while( !(result = input.read_tag()) ) {
109                 if( input.tag.title_is("GABOROBJ") ) {
110                         config.limits();
111                 }
112                 else if( input.tag.title_is("/GABOROBJ") )
113                         result = 1;
114         }
115 }
116
117 void GaborObj::update_gui()
118 {
119         if( !thread ) return;
120         if( !load_configuration() ) return;
121         thread->window->lock_window("GaborObj::update_gui");
122         GaborObjWindow *window = (GaborObjWindow*)thread->window;
123         window->unlock_window();
124 }
125
126 void GaborObj::to_mat(Mat &mat, int mcols, int mrows,
127         VFrame *inp, int ix,int iy, int mcolor_model)
128 {
129         int mcomp = BC_CModels::components(mcolor_model);
130         int mbpp = BC_CModels::calculate_pixelsize(mcolor_model);
131         int psz = mbpp / mcomp;
132         int mdepth = psz < 2 ? CV_8U : psz < 4 ? CV_16U : CV_32F;
133         if( mat.dims != 2 || mat.depth() != mdepth || mat.channels() != mcomp ||
134             mat.cols != mcols || mat.rows != mrows ) {
135                 mat.release();
136         }
137         if( mat.empty() ) {
138                 int type = CV_MAKETYPE(mdepth, mcomp);
139                 mat.create(mrows, mcols, type);
140         }
141         uint8_t *mat_rows[mrows];
142         for( int y=0; y<mrows; ++y ) mat_rows[y] = mat.ptr(y);
143         uint8_t **inp_rows = inp->get_rows();
144         int ibpl = inp->get_bytes_per_line(), mbpl = mcols * mbpp;
145         int icolor_model = inp->get_color_model();
146         BC_CModels::transfer(mat_rows, mcolor_model, 0,0, mcols,mrows, mbpl,
147                 inp_rows, icolor_model, ix,iy, mcols,mrows, ibpl, 0);
148 //      VFrame vfrm(mat_rows[0], -1, mcols,mrows, mcolor_model, mat_rows[1]-mat_rows[0]);
149 //      static int vfrm_no = 0; char vfn[64]; sprintf(vfn,"/tmp/idat/%06d.png", vfrm_no++);
150 //      vfrm.write_png(vfn);
151 }
152
153 void GaborObj::from_mat(VFrame *out, int ox, int oy, int ow, int oh, Mat &mat, int mcolor_model)
154 {
155         int mbpp = BC_CModels::calculate_pixelsize(mcolor_model);
156         int mrows = mat.rows, mcols = mat.cols;
157         uint8_t *mat_rows[mrows];
158         for( int y=0; y<mrows; ++y ) mat_rows[y] = mat.ptr(y);
159         uint8_t **out_rows = out->get_rows();
160         int obpl = out->get_bytes_per_line(), mbpl = mcols * mbpp;
161         int ocolor_model = out->get_color_model();
162         BC_CModels::transfer(out_rows, ocolor_model, ox,oy, ow,oh, obpl,
163                 mat_rows, mcolor_model, 0,0, mcols,mrows, mbpl,  0);
164 //      static int vfrm_no = 0; char vfn[64]; sprintf(vfn,"/tmp/odat/%06d.png", vfrm_no++);
165 //      out->write_png(vfn);
166 }
167
168
169 int GaborObj::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
170 {
171
172         //int need_reconfigure =
173         load_configuration();
174         input = get_input(0);
175         output = get_output(0);
176         width = input->get_w();
177         height = input->get_h();
178         color_model = input->get_color_model();
179
180 // load next image
181         VFrame *iframe = new_temp(width,height, color_model);
182         read_frame(iframe, 0, start_position, frame_rate, 0);
183         input = iframe;
184         to_mat(next_img, width,height, iframe, 0,0, color_model);
185         if( !gabor_engine )
186                 gabor_engine = new GaborObjFilterEngine(this, PluginClient::smp + 1);
187
188         output->clear_frame();
189         gabor_engine->process_packages();
190         return 0;
191 }
192
193
194 GaborObjFilterPackage::GaborObjFilterPackage()
195  : LoadPackage()
196 {
197 }
198
199 GaborObjFilterUnit::GaborObjFilterUnit(GaborObjFilterEngine *engine, GaborObj *plugin)
200  : LoadClient(engine)
201 {
202         this->plugin = plugin;
203 }
204
205 GaborObjFilterUnit::~GaborObjFilterUnit()
206 {
207 }
208
209 void GaborObjFilterUnit::process_package(LoadPackage *package)
210 {
211         GaborObjFilterPackage *pkg = (GaborObjFilterPackage*)package;
212         process_filter(pkg);
213 }
214
215 void GaborObjFilterUnit::process_filter(GaborObjFilterPackage *pkg)
216 {
217         int color_model = plugin->color_model;
218         int w = plugin->output->get_w(), h = plugin->output->get_h();
219         int ddepth = CV_8UC3;
220
221         switch( color_model ) {
222         case BC_RGB888:     ddepth = CV_8UC3;   break;
223         case BC_RGBA8888:   ddepth = CV_8UC4;   break;
224         case BC_RGB_FLOAT:  ddepth = CV_32FC3;  break;
225         case BC_RGBA_FLOAT: ddepth = CV_32FC4;  break;
226         case BC_YUV888:     ddepth = CV_8UC3;   break;
227         case BC_YUVA8888:   ddepth = CV_8UC4;   break;
228         }
229
230         Mat &src = plugin->next_img, dst;
231         Mat &kern = plugin->filters[pkg->i];
232         filter2D(src, dst, ddepth, kern);
233
234 #define GABOR_OBJ_REMAP(type, components) { \
235         type **out_rows = (type**)plugin->output->get_rows(); \
236  \
237         for( int y=0; y<h; ++y ) { \
238                 type *out_row = out_rows[y]; \
239                 type *dst_row = (type *)dst.ptr<type>(y); \
240                 for( int x=0; x<w; ++x ) { \
241                         for( int i=0; i<components; ++i ) { \
242                                 *out_row = bmax(*out_row, *dst_row); \
243                                 ++out_row;  ++dst_row; \
244                         } \
245                 } \
246         } \
247 }
248 // technically, this is needed... but it really can slow it down.
249 //      plugin->remap_lock->lock("GaborObjFilterUnit::process_filter");
250         switch( color_model ) {
251         case BC_RGB888:     GABOR_OBJ_REMAP(unsigned char, 3);  break;
252         case BC_RGBA8888:   GABOR_OBJ_REMAP(unsigned char, 4);  break;
253         case BC_RGB_FLOAT:  GABOR_OBJ_REMAP(float, 3);          break;
254         case BC_RGBA_FLOAT: GABOR_OBJ_REMAP(float, 4);          break;
255         case BC_YUV888:     GABOR_OBJ_REMAP(unsigned char, 3);  break;
256         case BC_YUVA8888:   GABOR_OBJ_REMAP(unsigned char, 4);  break;
257         }
258 //      plugin->remap_lock->unlock();
259 }
260
261
262 GaborObjFilterEngine::GaborObjFilterEngine(GaborObj *plugin, int cpus)
263  : LoadServer(cpus+1, plugin->filters.size())
264 {
265         this->plugin = plugin;
266 }
267
268 GaborObjFilterEngine::~GaborObjFilterEngine()
269 {
270 }
271
272 void GaborObjFilterEngine::init_packages()
273 {
274         int n = LoadServer::get_total_packages();
275         for( int i=0; i<n; ++i ) {
276                 GaborObjFilterPackage *pkg = (GaborObjFilterPackage*)LoadServer::get_package(i);
277                 pkg->i = i;
278         }
279 }
280
281 LoadClient* GaborObjFilterEngine::new_client()
282 {
283         return new GaborObjFilterUnit(this, plugin);
284 }
285
286 LoadPackage* GaborObjFilterEngine::new_package()
287 {
288         return new GaborObjFilterPackage();
289 }
290