x265 update 2.7, findobj upgrade, fix svg init, fix for dragchkbox buttonpress, add...
[goodguy/history.git] / cinelerra-5.1 / plugins / findobj / findobj.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "affine.h"
22 #include "bccolors.h"
23 #include "clip.h"
24 #include "filexml.h"
25 #include "language.h"
26 #include "findobj.h"
27 #include "findobjwindow.h"
28 #include "mutex.h"
29 #include "overlayframe.h"
30 #include "plugin.h"
31 #include "pluginserver.h"
32 #include "track.h"
33
34 #include <errno.h>
35 #include <exception>
36 #include <unistd.h>
37
38 REGISTER_PLUGIN(FindObjMain)
39
40 FindObjConfig::FindObjConfig()
41 {
42         reset();
43 }
44
45 void FindObjConfig::reset()
46 {
47         algorithm = NO_ALGORITHM;
48         use_flann = 1;
49         draw_keypoints = 0;
50         draw_scene_border = 0;
51         replace_object = 0;
52         draw_object_border = 0;
53         draw_replace_border = 0;
54         object_x = 50;  object_y = 50;
55         object_w = 100; object_h = 100;
56         drag_object = 0;
57         scene_x = 50;   scene_y = 50;
58         scene_w = 100;  scene_h = 100;
59         drag_replace = 0;
60         replace_x = 50;   replace_y = 50;
61         replace_w = 100;  replace_h = 100;
62         replace_dx = 0;   replace_dy = 0;
63         drag_scene = 0;
64         scene_layer = 0;
65         object_layer = 1;
66         replace_layer = 2;
67         blend = 100;
68 }
69
70 void FindObjConfig::boundaries()
71 {
72         bclamp(object_x, 0, 100);  bclamp(object_y, 0, 100);
73         bclamp(object_w, 0, 100);  bclamp(object_h, 0, 100);
74         bclamp(scene_x, 0, 100);   bclamp(scene_y, 0, 100);
75         bclamp(scene_w, 0, 100);   bclamp(scene_h, 0, 100);
76         bclamp(object_layer, MIN_LAYER, MAX_LAYER);
77         bclamp(replace_layer, MIN_LAYER, MAX_LAYER);
78         bclamp(scene_layer, MIN_LAYER, MAX_LAYER);
79         bclamp(blend, MIN_BLEND, MAX_BLEND);
80 }
81
82 int FindObjConfig::equivalent(FindObjConfig &that)
83 {
84         int result =
85                 algorithm == that.algorithm &&
86                 use_flann == that.use_flann &&
87                 draw_keypoints == that.draw_keypoints &&
88                 draw_scene_border == that.draw_scene_border &&
89                 replace_object == that.replace_object &&
90                 draw_object_border == that.draw_object_border &&
91                 draw_replace_border == that.draw_replace_border &&
92                 object_x == that.object_x && object_y == that.object_y &&
93                 object_w == that.object_w && object_h == that.object_h &&
94                 drag_object == that.drag_object &&
95                 scene_x == that.scene_x && scene_y == that.scene_y &&
96                 scene_w == that.scene_w && scene_h == that.scene_h &&
97                 drag_scene == that.drag_scene &&
98                 replace_x == that.replace_x && replace_y == that.replace_y &&
99                 replace_w == that.replace_w && replace_h == that.replace_h &&
100                 replace_dx == that.replace_dx && replace_dy == that.replace_dy &&
101                 drag_replace == that.drag_replace &&
102                 object_layer == that.object_layer &&
103                 replace_layer == that.replace_layer &&
104                 scene_layer == that.scene_layer &&
105                 blend == that.blend;
106         return result;
107 }
108
109 void FindObjConfig::copy_from(FindObjConfig &that)
110 {
111         algorithm = that.algorithm;
112         use_flann = that.use_flann;
113         draw_keypoints = that.draw_keypoints;
114         draw_scene_border = that.draw_scene_border;
115         replace_object = that.replace_object;
116         draw_object_border = that.draw_object_border;
117         draw_replace_border = that.draw_replace_border;
118         object_x = that.object_x;  object_y = that.object_y;
119         object_w = that.object_w;  object_h = that.object_h;
120         drag_object = that.drag_object;
121         scene_x = that.scene_x;    scene_y = that.scene_y;
122         scene_w = that.scene_w;    scene_h = that.scene_h;
123         drag_scene = that.drag_scene;
124         replace_x = that.replace_x;   replace_y = that.replace_y;
125         replace_w = that.replace_w;   replace_h = that.replace_h;
126         replace_dx = that.replace_dx; replace_dy = that.replace_dy;
127         drag_replace = that.drag_replace;
128         object_layer = that.object_layer;
129         replace_layer = that.replace_layer;
130         scene_layer = that.scene_layer;
131         blend = that.blend;
132 }
133
134 void FindObjConfig::interpolate(FindObjConfig &prev, FindObjConfig &next,
135         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
136 {
137         copy_from(prev);
138 }
139
140
141 FindObjMain::FindObjMain(PluginServer *server)
142  : PluginVClient(server)
143 {
144         affine = 0;
145         overlayer = 0;
146
147         cvmodel = BC_RGB888;
148         w = h = 0;
149         object = scene = replace = 0;
150         object_x = object_y = 0;
151         object_w = object_h = 0;
152         scene_x = scene_y = 0;
153         scene_w = scene_h = 0;
154         object_layer = 0;
155         scene_layer = 1;
156         replace_layer = 2;
157
158         border_x1 = 0;  border_y1 = 0;
159         border_x2 = 0;  border_y2 = 0;
160         border_x3 = 0;  border_y3 = 0;
161         border_x4 = 0;  border_y4 = 0;
162
163         obj_x1 = 0;     obj_y1 = 0;
164         obj_x2 = 0;     obj_y2 = 0;
165         obj_x3 = 0;     obj_y3 = 0;
166         obj_x4 = 0;     obj_y4 = 0;
167
168         init_border = 1;
169 }
170
171 FindObjMain::~FindObjMain()
172 {
173         delete affine;
174         delete overlayer;
175 }
176
177 const char* FindObjMain::plugin_title() { return N_("FindObj"); }
178 int FindObjMain::is_realtime() { return 1; }
179 int FindObjMain::is_multichannel() { return 1; }
180
181 NEW_WINDOW_MACRO(FindObjMain, FindObjWindow)
182 LOAD_CONFIGURATION_MACRO(FindObjMain, FindObjConfig)
183
184 void FindObjMain::update_gui()
185 {
186         if( !thread ) return;
187         if( !load_configuration() ) return;
188         FindObjWindow *window = (FindObjWindow*)thread->window;
189         window->lock_window("FindObjMain::update_gui");
190         window->update_gui();
191         window->flush();
192         window->unlock_window();
193 }
194
195 void FindObjMain::save_data(KeyFrame *keyframe)
196 {
197         FileXML output;
198
199 // cause data to be stored directly in text
200         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
201         output.tag.set_title("FINDOBJ");
202         output.tag.set_property("ALGORITHM", config.algorithm);
203         output.tag.set_property("USE_FLANN", config.use_flann);
204         output.tag.set_property("DRAG_OBJECT", config.drag_object);
205         output.tag.set_property("OBJECT_X", config.object_x);
206         output.tag.set_property("OBJECT_Y", config.object_y);
207         output.tag.set_property("OBJECT_W", config.object_w);
208         output.tag.set_property("OBJECT_H", config.object_h);
209         output.tag.set_property("DRAG_SCENE", config.drag_scene);
210         output.tag.set_property("SCENE_X", config.scene_x);
211         output.tag.set_property("SCENE_Y", config.scene_y);
212         output.tag.set_property("SCENE_W", config.scene_w);
213         output.tag.set_property("SCENE_H", config.scene_h);
214         output.tag.set_property("DRAG_REPLACE", config.drag_replace);
215         output.tag.set_property("REPLACE_X", config.replace_x);
216         output.tag.set_property("REPLACE_Y", config.replace_y);
217         output.tag.set_property("REPLACE_W", config.replace_w);
218         output.tag.set_property("REPLACE_H", config.replace_h);
219         output.tag.set_property("REPLACE_DX", config.replace_dx);
220         output.tag.set_property("REPLACE_DY", config.replace_dy);
221         output.tag.set_property("DRAW_KEYPOINTS", config.draw_keypoints);
222         output.tag.set_property("DRAW_SCENE_BORDER", config.draw_scene_border);
223         output.tag.set_property("REPLACE_OBJECT", config.replace_object);
224         output.tag.set_property("DRAW_OBJECT_BORDER", config.draw_object_border);
225         output.tag.set_property("DRAW_REPLACE_BORDER", config.draw_replace_border);
226         output.tag.set_property("OBJECT_LAYER", config.object_layer);
227         output.tag.set_property("REPLACE_LAYER", config.replace_layer);
228         output.tag.set_property("SCENE_LAYER", config.scene_layer);
229         output.tag.set_property("BLEND", config.blend);
230         output.append_tag();
231         output.tag.set_title("/FINDOBJ");
232         output.append_tag();
233         output.append_newline();
234         output.terminate_string();
235 }
236
237 void FindObjMain::read_data(KeyFrame *keyframe)
238 {
239         FileXML input;
240
241         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
242
243         int result = 0;
244
245         while( !(result = input.read_tag()) ) {
246                 if( input.tag.title_is("FINDOBJ") ) {
247                         config.algorithm = input.tag.get_property("ALGORITHM", config.algorithm);
248                         config.use_flann = input.tag.get_property("USE_FLANN", config.use_flann);
249                         config.object_x = input.tag.get_property("OBJECT_X", config.object_x);
250                         config.object_y = input.tag.get_property("OBJECT_Y", config.object_y);
251                         config.object_w = input.tag.get_property("OBJECT_W", config.object_w);
252                         config.object_h = input.tag.get_property("OBJECT_H", config.object_h);
253                         config.drag_object = input.tag.get_property("DRAG_OBJECT", config.drag_object);
254                         config.scene_x = input.tag.get_property("SCENE_X", config.scene_x);
255                         config.scene_y = input.tag.get_property("SCENE_Y", config.scene_y);
256                         config.scene_w = input.tag.get_property("SCENE_W", config.scene_w);
257                         config.scene_h = input.tag.get_property("SCENE_H", config.scene_h);
258                         config.drag_scene = input.tag.get_property("DRAG_SCENE", config.drag_scene);
259                         config.replace_x = input.tag.get_property("REPLACE_X", config.replace_x);
260                         config.replace_y = input.tag.get_property("REPLACE_Y", config.replace_y);
261                         config.replace_w = input.tag.get_property("REPLACE_W", config.replace_w);
262                         config.replace_h = input.tag.get_property("REPLACE_H", config.replace_h);
263                         config.replace_dx = input.tag.get_property("REPLACE_DX", config.replace_dx);
264                         config.replace_dy = input.tag.get_property("REPLACE_DY", config.replace_dy);
265                         config.drag_replace = input.tag.get_property("DRAG_REPLACE", config.drag_replace);
266                         config.draw_keypoints = input.tag.get_property("DRAW_KEYPOINTS", config.draw_keypoints);
267                         config.draw_scene_border = input.tag.get_property("DRAW_SCENE_BORDER", config.draw_scene_border);
268                         config.replace_object = input.tag.get_property("REPLACE_OBJECT", config.replace_object);
269                         config.draw_object_border = input.tag.get_property("DRAW_OBJECT_BORDER", config.draw_object_border);
270                         config.draw_replace_border = input.tag.get_property("DRAW_REPLACE_BORDER", config.draw_replace_border);
271                         config.object_layer = input.tag.get_property("OBJECT_LAYER", config.object_layer);
272                         config.replace_layer = input.tag.get_property("REPLACE_LAYER", config.replace_layer);
273                         config.scene_layer = input.tag.get_property("SCENE_LAYER", config.scene_layer);
274                         config.blend = input.tag.get_property("BLEND", config.blend);
275                 }
276         }
277
278         config.boundaries();
279 }
280
281 void FindObjMain::draw_line(VFrame *vframe, int x1, int y1, int x2, int y2)
282 {
283         vframe->draw_line(x1, y1, x2, y2);
284 }
285
286 void FindObjMain::draw_rect(VFrame *vframe, int x1, int y1, int x2, int y2)
287 {
288         --x2;  --y2;
289         draw_line(vframe, x1, y1, x2, y1);
290         draw_line(vframe, x2, y1, x2, y2);
291         draw_line(vframe, x2, y2, x1, y2);
292         draw_line(vframe, x1, y2, x1, y1);
293 }
294
295 void FindObjMain::draw_circle(VFrame *vframe, int x, int y, int r)
296 {
297         int x1 = x-r, x2 = x+r;
298         int y1 = y-r, y2 = y+r;
299         vframe->draw_smooth(x1,y, x1,y1, x,y1);
300         vframe->draw_smooth(x,y1, x2,y1, x2,y);
301         vframe->draw_smooth(x2,y, x2,y2, x,y2);
302         vframe->draw_smooth(x,y2, x1,y2, x1,y);
303 }
304
305 void FindObjMain::filter_matches(ptV &p1, ptV &p2, double ratio)
306 {
307         DMatches::iterator it;
308         for( it=pairs.begin(); it!=pairs.end(); ++it ) { 
309                 DMatchV &m = *it;
310                 if( m.size() == 2 && m[0].distance < m[1].distance*ratio ) {
311                         p1.push_back(obj_keypts[m[0].queryIdx].pt);
312                         p2.push_back(scn_keypts[m[0].trainIdx].pt);
313                 }
314         }
315 }
316
317 void FindObjMain::to_mat(Mat &mat, int mcols, int mrows,
318         VFrame *inp, int ix,int iy, BC_CModel mcolor_model)
319 {
320         int mcomp = BC_CModels::components(mcolor_model);
321         int mbpp = BC_CModels::calculate_pixelsize(mcolor_model);
322         int psz = mbpp / mcomp;
323         int mdepth = psz < 2 ? CV_8U : CV_16U;
324         if( mat.dims != 2 || mat.depth() != mdepth || mat.channels() != mcomp ||
325             mat.cols != mcols || mat.rows != mrows ) {
326                 mat.release();
327         }
328         if( mat.empty() ) {
329                 int type = CV_MAKETYPE(mdepth, mcomp);
330                 mat.create(mrows, mcols, type);
331         }
332         uint8_t *mat_rows[mrows];
333         for( int y=0; y<mrows; ++y ) mat_rows[y] = mat.ptr(y);
334         uint8_t **inp_rows = inp->get_rows();
335         int ibpl = inp->get_bytes_per_line(), obpl = mcols * mbpp;
336         int icolor_model = inp->get_color_model();
337         BC_CModels::transfer(mat_rows, mcolor_model, 0,0, mcols,mrows, obpl,
338                 inp_rows, icolor_model, ix,iy, mcols,mrows, ibpl, 0);
339 //      VFrame vfrm(mat_rows[0], -1, mcols,mrows, mcolor_model, mat_rows[1]-mat_rows[0]);
340 //      static int vfrm_no = 0; char vfn[64]; sprintf(vfn,"/tmp/dat/%06d.png", vfrm_no++);
341 //      vfrm.write_png(vfn);
342 }
343
344 void FindObjMain::detect(Mat &mat, KeyPointV &keypts,Mat &descrs)
345 {
346         keypts.clear();
347         descrs.release();
348         try {
349                 detector->detectAndCompute(mat, noArray(), keypts, descrs);
350         } catch(std::exception e) { printf(_("detector exception: %s\n"), e.what()); }
351 }
352
353 void FindObjMain::match()
354 {
355         pairs.clear();
356         try {
357                 matcher->knnMatch(obj_descrs, scn_descrs, pairs, 2);
358         } catch(std::exception e) { printf(_("match execption: %s\n"), e.what()); }
359 }
360
361 Ptr<DescriptorMatcher> FindObjMain::flann_kdtree_matcher()
362 { // trees=5
363         const Ptr<flann::IndexParams>& indexParams =
364                 makePtr<flann::KDTreeIndexParams>(5);
365         const Ptr<flann::SearchParams>& searchParams =
366                 makePtr<flann::SearchParams>();
367         return makePtr<FlannBasedMatcher>(indexParams, searchParams);
368 }
369 Ptr<DescriptorMatcher> FindObjMain::flann_lshidx_matcher()
370 { // table_number = 6#12, key_size = 12#20, multi_probe_level = 1#2
371         const Ptr<flann::IndexParams>& indexParams =
372                 makePtr<flann::LshIndexParams>(6, 12, 1);
373         const Ptr<flann::SearchParams>& searchParams =
374                 makePtr<flann::SearchParams>();
375         return makePtr<FlannBasedMatcher>(indexParams, searchParams);
376 }
377 Ptr<DescriptorMatcher> FindObjMain::bf_matcher_norm_l2()
378 {
379         return BFMatcher::create(NORM_L2);
380 }
381 Ptr<DescriptorMatcher> FindObjMain::bf_matcher_norm_hamming()
382 {
383         return BFMatcher::create(NORM_HAMMING);
384 }
385
386 #ifdef _SIFT
387 void FindObjMain::set_sift()
388 {
389         cvmodel = BC_GREY8;
390         detector = SIFT::create();
391         matcher = config.use_flann ?
392                 flann_kdtree_matcher() : bf_matcher_norm_l2();
393 }
394 #endif
395 #ifdef _SURF
396 void FindObjMain::set_surf()
397 {
398         cvmodel = BC_GREY8;
399         detector = SURF::create(800);
400         matcher = config.use_flann ?
401                 flann_kdtree_matcher() : bf_matcher_norm_l2();
402 }
403 #endif
404 #ifdef _ORB
405 void FindObjMain::set_orb()
406 {
407         cvmodel = BC_GREY8;
408         detector = ORB::create();
409         matcher = config.use_flann ?
410                 flann_lshidx_matcher() : bf_matcher_norm_hamming();
411 }
412 #endif
413 #ifdef _AKAZE
414 void FindObjMain::set_akaze()
415 {
416         cvmodel = BC_GREY8;
417         detector = AKAZE::create();
418         matcher = config.use_flann ?
419                 flann_lshidx_matcher() : bf_matcher_norm_hamming();
420 }
421 #endif
422 #ifdef _BRISK
423 void FindObjMain::set_brisk()
424 {
425         cvmodel = BC_GREY8;
426         detector = BRISK::create();
427         matcher = config.use_flann ?
428                 flann_lshidx_matcher() : bf_matcher_norm_hamming();
429 }
430 #endif
431
432 void FindObjMain::process_match()
433 {
434         if( config.algorithm == NO_ALGORITHM ) return;
435         if( !config.replace_object &&
436             !config.draw_scene_border &&
437             !config.draw_keypoints ) return;
438
439         if( detector.empty() ) {
440                 switch( config.algorithm ) {
441 #ifdef _SIFT
442                 case ALGORITHM_SIFT:   set_sift();   break;
443 #endif
444 #ifdef _SURF
445                 case ALGORITHM_SURF:   set_surf();   break;
446 #endif
447 #ifdef _ORB
448                 case ALGORITHM_ORB:    set_orb();    break;
449 #endif
450 #ifdef _AKAZE
451                 case ALGORITHM_AKAZE:  set_akaze();  break;
452 #endif
453 #ifdef _BRISK
454                 case ALGORITHM_BRISK:  set_brisk();  break;
455 #endif
456                 }
457                 obj_keypts.clear();  obj_descrs.release();
458                 to_mat(object_mat, object_w,object_h, object, object_x,object_y, cvmodel);
459                 detect(object_mat, obj_keypts, obj_descrs);
460 //printf("detect obj %d features\n", (int)obj_keypts.size());
461         }
462
463         to_mat(scene_mat, scene_w,scene_h, scene, scene_x,scene_y, cvmodel);
464         detect(scene_mat, scn_keypts, scn_descrs);
465 //printf("detect scn %d features\n", (int)scn_keypts.size());
466         match();
467         ptV p1, p2;
468         filter_matches(p1, p2);
469         if( p1.size() < 4 ) return;
470         Mat H = findHomography(p1, p2, RANSAC, 5.0);
471         if( !H.dims || !H.rows || !H.cols ) {
472 //printf("fail, size p1=%d,p2=%d\n",(int)p1.size(),(int)p2.size());
473                 return;
474         }
475
476         ptV src, dst;
477         float obj_x1 = 0, obj_x2 = object_w;
478         float obj_y1 = 0, obj_y2 = object_h;
479         src.push_back(Point2f(obj_x1,obj_y1));
480         src.push_back(Point2f(obj_x2,obj_y1));
481         src.push_back(Point2f(obj_x2,obj_y2));
482         src.push_back(Point2f(obj_x1,obj_y2));
483         perspectiveTransform(src, dst, H);
484
485         float dx = scene_x + replace_dx;
486         float dy = scene_y + replace_dy;
487         border_x1 = dst[0].x + dx;  border_y1 = dst[0].y + dy;
488         border_x2 = dst[1].x + dx;  border_y2 = dst[1].y + dy;
489         border_x3 = dst[2].x + dx;  border_y3 = dst[2].y + dy;
490         border_x4 = dst[3].x + dx;  border_y4 = dst[3].y + dy;
491 //printf("src %f,%f  %f,%f  %f,%f  %f,%f\n",
492 // src[0].x,src[0].y, src[1].x,src[1].y, src[2].x,src[2].y, src[3].x,src[3].y);
493 //printf("dst %f,%f  %f,%f  %f,%f  %f,%f\n",
494 // dst[0].x,dst[0].y, dst[1].x,dst[1].y, dst[2].x,dst[2].y, dst[3].x,dst[3].y);
495 }
496
497 int FindObjMain::process_buffer(VFrame **frame, int64_t start_position, double frame_rate)
498 {
499         int prev_algorithm = config.algorithm;
500         int prev_use_flann = config.use_flann;
501
502         if( load_configuration() )
503                 init_border = 1;
504
505         if( prev_algorithm != config.algorithm ||
506             prev_use_flann != config.use_flann ) {
507                 detector.release();
508                 matcher.release();
509         }
510
511         object_layer = config.object_layer;
512         scene_layer = config.scene_layer;
513         replace_layer = config.replace_layer;
514         Track *track = server->plugin->track;
515         w = track->track_w;
516         h = track->track_h;
517
518         int max_layer = PluginClient::get_total_buffers() - 1;
519         object_layer = bclip(config.object_layer, 0, max_layer);
520         scene_layer = bclip(config.scene_layer, 0, max_layer);
521         replace_layer = bclip(config.replace_layer, 0, max_layer);
522
523         int cfg_w = (int)(w * config.object_w / 100.);
524         int cfg_h = (int)(h * config.object_h / 100.);
525         int cfg_x1 = (int)(w * config.object_x / 100. - cfg_w / 2);
526         int cfg_y1 = (int)(h * config.object_y / 100. - cfg_h / 2);
527         int cfg_x2 = cfg_x1 + cfg_w;
528         int cfg_y2 = cfg_y1 + cfg_h;
529         bclamp(cfg_x1, 0, w);  object_x = cfg_x1;
530         bclamp(cfg_y1, 0, h);  object_y = cfg_y1;
531         bclamp(cfg_x2, 0, w);  object_w = cfg_x2 - cfg_x1;
532         bclamp(cfg_y2, 0, h);  object_h = cfg_y2 - cfg_y1;
533
534         cfg_w = (int)(w * config.scene_w / 100.);
535         cfg_h = (int)(h * config.scene_h / 100.);
536         cfg_x1 = (int)(w * config.scene_x / 100. - cfg_w / 2);
537         cfg_y1 = (int)(h * config.scene_y / 100. - cfg_h / 2);
538         cfg_x2 = cfg_x1 + cfg_w;
539         cfg_y2 = cfg_y1 + cfg_h;
540         bclamp(cfg_x1, 0, w);  scene_x = cfg_x1;
541         bclamp(cfg_y1, 0, h);  scene_y = cfg_y1;
542         bclamp(cfg_x2, 0, w);  scene_w = cfg_x2 - cfg_x1;
543         bclamp(cfg_y2, 0, h);  scene_h = cfg_y2 - cfg_y1;
544
545         cfg_w = (int)(w * config.replace_w / 100.);
546         cfg_h = (int)(h * config.replace_h / 100.);
547         cfg_x1 = (int)(w * config.replace_x / 100. - cfg_w / 2);
548         cfg_y1 = (int)(h * config.replace_y / 100. - cfg_h / 2);
549         cfg_x2 = cfg_x1 + cfg_w;
550         cfg_y2 = cfg_y1 + cfg_h;
551         bclamp(cfg_x1, 0, w);  replace_x = cfg_x1;
552         bclamp(cfg_y1, 0, h);  replace_y = cfg_y1;
553         bclamp(cfg_x2, 0, w);  replace_w = cfg_x2 - cfg_x1;
554         bclamp(cfg_y2, 0, h);  replace_h = cfg_y2 - cfg_y1;
555
556         int cfg_dx = (int)(w * config.replace_dx / 100.);
557         int cfg_dy = (int)(h * config.replace_dy / 100.);
558         bclamp(cfg_dx, -h, h);  replace_dx = cfg_dx;
559         bclamp(cfg_dy, -w, w);  replace_dy = cfg_dy;
560
561 // Read in the input frames
562         for( int i = 0; i < PluginClient::get_total_buffers(); i++ ) {
563                 read_frame(frame[i], i, start_position, frame_rate, 0);
564         }
565
566         object = frame[object_layer];
567         scene = frame[scene_layer];
568         replace = frame[replace_layer];
569
570         border_x1 = obj_x1;  border_y1 = obj_y1;
571         border_x2 = obj_x2;  border_y2 = obj_y2;
572         border_x3 = obj_x3;  border_y3 = obj_y3;
573         border_x4 = obj_x4;  border_y4 = obj_y4;
574
575         if( scene_w > 0 && scene_h > 0 && object_w > 0 && object_h > 0 ) {
576                 process_match();
577         }
578
579         double w0 = init_border ? (init_border=0, 1.) : config.blend/100., w1 = 1. - w0;
580         obj_x1 = border_x1*w0 + obj_x1*w1;  obj_y1 = border_y1*w0 + obj_y1*w1;
581         obj_x2 = border_x2*w0 + obj_x2*w1;  obj_y2 = border_y2*w0 + obj_y2*w1;
582         obj_x3 = border_x3*w0 + obj_x3*w1;  obj_y3 = border_y3*w0 + obj_y3*w1;
583         obj_x4 = border_x4*w0 + obj_x4*w1;  obj_y4 = border_y4*w0 + obj_y4*w1;
584
585 // Replace object in the scene layer
586         if( config.replace_object ) {
587                 int cpus1 = get_project_smp() + 1;
588                 if( !affine )
589                         affine = new AffineEngine(cpus1, cpus1);
590                 if( !overlayer )
591                         overlayer = new OverlayFrame(cpus1);
592                 VFrame *temp = new_temp(w, h, scene->get_color_model());
593                 temp->clear_frame();
594                 affine->set_in_viewport(replace_x, replace_y, replace_w, replace_h);
595                 int x1 = obj_x1, x2 = obj_x2, x3 = obj_x3, x4 = obj_x4;
596                 int y1 = obj_y1, y2 = obj_y2, y3 = obj_y3, y4 = obj_y4;
597                 bclamp(x1, 0, w);  bclamp(x2, 0, w);  bclamp(x3, 0, w);  bclamp(x4, 0, w);
598                 bclamp(y1, 0, h);  bclamp(y2, 0, h);  bclamp(y3, 0, h);  bclamp(y4, 0, h);
599                 affine->set_matrix(
600                         replace_x, replace_y, replace_x+replace_w, replace_y+replace_h,
601                         x1,y1, x2,y2, x3,y3, x4,y4);
602                 affine->process(temp, replace, 0,
603                         AffineEngine::TRANSFORM, 0,0, 100,0, 100,100, 0,100, 1);
604                 overlayer->overlay(scene, temp,  0,0, w,h,  0,0, w,h,
605                         1, TRANSFER_NORMAL, NEAREST_NEIGHBOR);
606
607         }
608
609         if( config.draw_scene_border ) {
610                 int wh = (w+h)>>8, ss = 1; while( wh>>=1 ) ss<<=1;
611                 scene->set_pixel_color(WHITE);  scene->set_stiple(ss*2);
612                 draw_rect(scene, scene_x, scene_y, scene_x+scene_w, scene_y+scene_h);
613         }
614         if( config.draw_object_border ) {
615                 int wh = (w+h)>>8, ss = 1; while( wh>>=1 ) ss<<=1;
616                 scene->set_pixel_color(YELLOW);  scene->set_stiple(ss*3);
617                 draw_rect(scene, object_x, object_y, object_x+object_w, object_y+object_h);
618         }
619         if( config.draw_replace_border ) {
620                 int wh = (w+h)>>8, ss = 1; while( wh>>=1 ) ss<<=1;
621                 scene->set_pixel_color(GREEN);  scene->set_stiple(ss*3);
622                 draw_rect(scene, replace_x, replace_y, replace_x+replace_w, replace_y+replace_h);
623         }
624         if( config.draw_keypoints ) {
625                 scene->set_pixel_color(RED);  scene->set_stiple(0);
626                 for( int i=0,n=scn_keypts.size(); i<n; ++i ) {
627                         Point2f &pt = scn_keypts[i].pt;
628                         int r = scn_keypts[i].size * 1.2/9 * 2;
629                         int x = pt.x + scene_x, y = pt.y + scene_y;
630                         draw_circle(scene, x, y, r);
631                 }
632         }
633
634         if( gui_open() ) {
635                 if( config.drag_scene ) {
636                         scene->set_pixel_color(WHITE);
637                         DragCheckBox::draw_boundary(scene, scene_x, scene_y, scene_w, scene_h);
638                 }
639                 if( config.drag_object ) {
640                         scene->set_pixel_color(YELLOW);
641                         DragCheckBox::draw_boundary(scene, object_x, object_y, object_w, object_h);
642                 }
643                 if( config.drag_replace ) {
644                         scene->set_pixel_color(GREEN);
645                         DragCheckBox::draw_boundary(scene, replace_x, replace_y, replace_w, replace_h);
646                 }
647         }
648
649         scene->set_pixel_color(BLACK);
650         scene->set_stiple(0);
651         return 0;
652 }
653