remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / plugins / findobject / findobject.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
22
23 // This is mainly a test for object tracking
24
25 #include "affine.h"
26 #include "cicolors.h"
27 #include "clip.h"
28 #include "filexml.h"
29 #include "keyframe.h"
30 #include "language.h"
31 #include "findobject.h"
32 #include "findobjectwindow.h"
33 #include "mutex.h"
34 #include "overlayframe.h"
35 #include "surfscan.h"
36 #include "transportque.h"
37
38 // Needed with OpenCV version 2.4.8
39 #include "opencv2/legacy/legacy.hpp"
40 #include "opencv2/legacy/compat.hpp"
41
42 #include "opencv2/video/tracking.hpp"
43 #include "opencv2/video/background_segm.hpp"
44
45
46 #include <errno.h>
47 #include <unistd.h>
48
49 REGISTER_PLUGIN(FindObjectMain)
50
51
52
53 FindObjectConfig::FindObjectConfig()
54 {
55         global_range_w = 5;
56         global_range_h = 5;
57         draw_keypoints = 1;
58         draw_border = 1;
59         replace_object = 0;
60         draw_object_border = 1;
61         global_block_w = MIN_BLOCK;
62         global_block_h = MIN_BLOCK;
63         block_x = 50;
64         block_y = 50;
65         object_layer = 0;
66         replace_layer = 1;
67         scene_layer = 2;
68         algorithm = NO_ALGORITHM;
69         vmin = 10;
70         vmax = 256;
71         smin = 30;
72         blend = 100;
73 }
74
75 void FindObjectConfig::boundaries()
76 {
77         CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS);
78         CLAMP(global_range_h, MIN_RADIUS, MAX_RADIUS);
79         CLAMP(global_block_w, MIN_BLOCK, MAX_BLOCK);
80         CLAMP(global_block_h, MIN_BLOCK, MAX_BLOCK);
81         CLAMP(block_x, 0, 100);
82         CLAMP(block_y, 0, 100);
83         CLAMP(object_layer, MIN_LAYER, MAX_LAYER);
84         CLAMP(replace_layer, MIN_LAYER, MAX_LAYER);
85         CLAMP(scene_layer, MIN_LAYER, MAX_LAYER);
86         CLAMP(vmin, MIN_CAMSHIFT, MAX_CAMSHIFT);
87         CLAMP(vmax, MIN_CAMSHIFT, MAX_CAMSHIFT);
88         CLAMP(smin, MIN_CAMSHIFT, MAX_CAMSHIFT);
89         CLAMP(blend, MIN_BLEND, MAX_BLEND);
90 }
91
92 int FindObjectConfig::equivalent(FindObjectConfig &that)
93 {
94         int result =
95                 global_range_w == that.global_range_w &&
96                 global_range_h == that.global_range_h &&
97                 draw_keypoints == that.draw_keypoints &&
98                 draw_border == that.draw_border &&
99                 replace_object == that.replace_object &&
100                 draw_object_border == that.draw_object_border &&
101                 global_block_w == that.global_block_w &&
102                 global_block_h == that.global_block_h &&
103                 block_x == that.block_x &&
104                 block_y == that.block_y &&
105                 object_layer == that.object_layer &&
106                 replace_layer == that.replace_layer &&
107                 scene_layer == that.scene_layer &&
108                 algorithm == that.algorithm &&
109                 vmin == that.vmin &&
110                 vmax == that.vmax &&
111                 smin == that.smin &&
112                 blend == that.blend;
113         return result;
114 }
115
116 void FindObjectConfig::copy_from(FindObjectConfig &that)
117 {
118         global_range_w = that.global_range_w;
119         global_range_h = that.global_range_h;
120         draw_keypoints = that.draw_keypoints;
121         draw_border = that.draw_border;
122         replace_object = that.replace_object;
123         draw_object_border = that.draw_object_border;
124         global_block_w = that.global_block_w;
125         global_block_h = that.global_block_h;
126         block_x = that.block_x;
127         block_y = that.block_y;
128         object_layer = that.object_layer;
129         replace_layer = that.replace_layer;
130         scene_layer = that.scene_layer;
131         algorithm = that.algorithm;
132         vmin = that.vmin;
133         vmax = that.vmax;
134         smin = that.smin;
135         blend = that.blend;
136 }
137
138 void FindObjectConfig::interpolate(FindObjectConfig &prev,
139         FindObjectConfig &next,
140         int64_t prev_frame,
141         int64_t next_frame,
142         int64_t current_frame)
143 {
144         copy_from(prev);
145 }
146
147
148
149
150
151
152
153
154 FindObjectMain::FindObjectMain(PluginServer *server)
155  : PluginVClient(server)
156 {
157         bzero(&blob_param, sizeof(CvBlobTrackerAutoParam1));
158         blob_pTracker = 0;
159
160
161         object_image = 0;
162         prev_object = 0;
163         scene_image = 0;
164         object_image_w = 0;
165         object_image_h = 0;
166         scene_image_w = 0;
167         scene_image_h = 0;
168         storage = 0;
169         object_keypoints = 0;
170         object_descriptors = 0;
171         scene_keypoints = 0;
172         scene_descriptors = 0;
173         affine = 0;
174         temp = 0;
175         overlayer = 0;
176         init_border = 1;
177 }
178
179 FindObjectMain::~FindObjectMain()
180 {
181 // This releases all the arrays
182         if(storage) cvReleaseMemStorage(&storage);
183         if(object_image) cvReleaseImage(&object_image);
184         if(scene_image) cvReleaseImage(&scene_image);
185         if(prev_object) delete [] prev_object;
186         delete affine;
187         delete temp;
188         delete overlayer;
189
190     if(blob_param.pBT) cvReleaseBlobTracker(&blob_param.pBT);
191     if(blob_param.pBD) cvReleaseBlobDetector(&blob_param.pBD);
192     if(blob_param.pBTGen) cvReleaseBlobTrackGen(&blob_param.pBTGen);
193     if(blob_param.pBTA) cvReleaseBlobTrackAnalysis(&blob_param.pBTA);
194     if(blob_param.pFG) cvReleaseFGDetector(&blob_param.pFG);
195     if(blob_pTracker) cvReleaseBlobTrackerAuto(&blob_pTracker);
196
197 }
198
199 const char* FindObjectMain::plugin_title() { return _("Find Object"); }
200 int FindObjectMain::is_realtime() { return 1; }
201 int FindObjectMain::is_multichannel() { return 1; }
202
203
204 NEW_WINDOW_MACRO(FindObjectMain, FindObjectWindow)
205
206 LOAD_CONFIGURATION_MACRO(FindObjectMain, FindObjectConfig)
207
208
209
210 void FindObjectMain::update_gui()
211 {
212         if(thread)
213         {
214                 if(load_configuration())
215                 {
216                         thread->window->lock_window("FindObjectMain::update_gui");
217
218                         char string[BCTEXTLEN];
219
220                         ((FindObjectWindow*)thread->window)->global_range_w->update(config.global_range_w);
221                         ((FindObjectWindow*)thread->window)->global_range_h->update(config.global_range_h);
222                         ((FindObjectWindow*)thread->window)->global_block_w->update(config.global_block_w);
223                         ((FindObjectWindow*)thread->window)->global_block_h->update(config.global_block_h);
224                         ((FindObjectWindow*)thread->window)->block_x->update(config.block_x);
225                         ((FindObjectWindow*)thread->window)->block_y->update(config.block_y);
226                         ((FindObjectWindow*)thread->window)->block_x_text->update((float)config.block_x);
227                         ((FindObjectWindow*)thread->window)->block_y_text->update((float)config.block_y);
228
229                         ((FindObjectWindow*)thread->window)->draw_keypoints->update(config.draw_keypoints);
230                         ((FindObjectWindow*)thread->window)->draw_border->update(config.draw_border);
231                         ((FindObjectWindow*)thread->window)->replace_object->update(config.replace_object);
232                         ((FindObjectWindow*)thread->window)->draw_object_border->update(config.draw_object_border);
233
234
235                         ((FindObjectWindow*)thread->window)->object_layer->update(
236                                 (int64_t)config.object_layer);
237                         ((FindObjectWindow*)thread->window)->replace_layer->update(
238                                 (int64_t)config.replace_layer);
239                         ((FindObjectWindow*)thread->window)->scene_layer->update(
240                                 (int64_t)config.scene_layer);
241                         ((FindObjectWindow*)thread->window)->algorithm->set_text(
242                                 FindObjectAlgorithm::to_text(config.algorithm));
243
244                         ((FindObjectWindow*)thread->window)->vmin->update(
245                                 (int64_t)config.vmin);
246                         ((FindObjectWindow*)thread->window)->vmax->update(
247                                 (int64_t)config.vmax);
248                         ((FindObjectWindow*)thread->window)->smin->update(
249                                 (int64_t)config.smin);
250                         ((FindObjectWindow*)thread->window)->blend->update(
251                                 (int64_t)config.blend);
252
253                         ((FindObjectWindow*)thread->window)->flush();
254                         thread->window->unlock_window();
255                 }
256 // printf("FindObjectMain::update_gui %d %d %d %d\n",
257 // __LINE__,
258 // config.mode1,
259 // config.mode2,
260 // config.mode3);
261         }
262 }
263
264
265
266
267 void FindObjectMain::save_data(KeyFrame *keyframe)
268 {
269         FileXML output;
270
271 // cause data to be stored directly in text
272         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
273         output.tag.set_title("FINDOBJECT");
274
275         output.tag.set_property("GLOBAL_BLOCK_W", config.global_block_w);
276         output.tag.set_property("GLOBAL_BLOCK_H", config.global_block_h);
277         output.tag.set_property("BLOCK_X", config.block_x);
278         output.tag.set_property("BLOCK_Y", config.block_y);
279         output.tag.set_property("GLOBAL_RANGE_W", config.global_range_w);
280         output.tag.set_property("GLOBAL_RANGE_H", config.global_range_h);
281         output.tag.set_property("DRAW_KEYPOINTS", config.draw_keypoints);
282         output.tag.set_property("DRAW_BORDER", config.draw_border);
283         output.tag.set_property("REPLACE_OBJECT", config.replace_object);
284         output.tag.set_property("DRAW_OBJECT_BORDER", config.draw_object_border);
285         output.tag.set_property("OBJECT_LAYER", config.object_layer);
286         output.tag.set_property("REPLACE_LAYER", config.replace_layer);
287         output.tag.set_property("SCENE_LAYER", config.scene_layer);
288         output.tag.set_property("ALGORITHM", config.algorithm);
289         output.tag.set_property("VMIN", config.vmin);
290         output.tag.set_property("VMAX", config.vmax);
291         output.tag.set_property("SMIN", config.smin);
292         output.tag.set_property("BLEND", config.blend);
293         output.append_tag();
294         output.tag.set_title("/FINDOBJECT");
295         output.append_tag();
296         output.append_newline();
297         output.terminate_string();
298 }
299
300 void FindObjectMain::read_data(KeyFrame *keyframe)
301 {
302         FileXML input;
303
304         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
305
306         int result = 0;
307
308         while(!result)
309         {
310                 result = input.read_tag();
311
312                 if(!result)
313                 {
314                         if(input.tag.title_is("FINDOBJECT"))
315                         {
316                                 config.global_block_w = input.tag.get_property("GLOBAL_BLOCK_W", config.global_block_w);
317                                 config.global_block_h = input.tag.get_property("GLOBAL_BLOCK_H", config.global_block_h);
318                                 config.block_x = input.tag.get_property("BLOCK_X", config.block_x);
319                                 config.block_y = input.tag.get_property("BLOCK_Y", config.block_y);
320                                 config.global_range_w = input.tag.get_property("GLOBAL_RANGE_W", config.global_range_w);
321                                 config.global_range_h = input.tag.get_property("GLOBAL_RANGE_H", config.global_range_h);
322                                 config.draw_keypoints = input.tag.get_property("DRAW_KEYPOINTS", config.draw_keypoints);
323                                 config.draw_border = input.tag.get_property("DRAW_BORDER", config.draw_border);
324                                 config.replace_object = input.tag.get_property("REPLACE_OBJECT", config.replace_object);
325                                 config.draw_object_border = input.tag.get_property("DRAW_OBJECT_BORDER", config.draw_object_border);
326                                 config.object_layer = input.tag.get_property("OBJECT_LAYER", config.object_layer);
327                                 config.replace_layer = input.tag.get_property("REPLACE_LAYER", config.replace_layer);
328                                 config.scene_layer = input.tag.get_property("SCENE_LAYER", config.scene_layer);
329                                 config.algorithm = input.tag.get_property("ALGORITHM", config.algorithm);
330                                 config.vmin = input.tag.get_property("VMIN", config.vmin);
331                                 config.vmax = input.tag.get_property("VMAX", config.vmax);
332                                 config.smin = input.tag.get_property("SMIN", config.smin);
333                                 config.blend = input.tag.get_property("BLEND", config.blend);
334                         }
335                 }
336         }
337         config.boundaries();
338 }
339
340
341
342
343
344 void FindObjectMain::draw_pixel(VFrame *frame, int x, int y)
345 {
346         if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
347
348 #define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
349 { \
350         type **rows = (type**)frame->get_rows(); \
351         rows[y][x * components] = max - rows[y][x * components]; \
352         if(!do_yuv) \
353         { \
354                 rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
355                 rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
356         } \
357         else \
358         { \
359                 rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
360                 rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
361         } \
362         if(components == 4) \
363                 rows[y][x * components + 3] = max; \
364 }
365
366
367         switch(frame->get_color_model())
368         {
369                 case BC_RGB888:
370                         DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
371                         break;
372                 case BC_RGBA8888:
373                         DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
374                         break;
375                 case BC_RGB_FLOAT:
376                         DRAW_PIXEL(x, y, 3, 0, 1.0, float);
377                         break;
378                 case BC_RGBA_FLOAT:
379                         DRAW_PIXEL(x, y, 4, 0, 1.0, float);
380                         break;
381                 case BC_YUV888:
382                         DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
383                         break;
384                 case BC_YUVA8888:
385                         DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
386                         break;
387                 case BC_RGB161616:
388                         DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
389                         break;
390                 case BC_YUV161616:
391                         DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
392                         break;
393                 case BC_RGBA16161616:
394                         DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
395                         break;
396                 case BC_YUVA16161616:
397                         DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
398                         break;
399         }
400 }
401
402
403 void FindObjectMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
404 {
405         int w = labs(x2 - x1);
406         int h = labs(y2 - y1);
407 //printf("FindObjectMain::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
408
409         if(!w && !h)
410         {
411                 draw_pixel(frame, x1, y1);
412         }
413         else
414         if(w > h)
415         {
416 // Flip coordinates so x1 < x2
417                 if(x2 < x1)
418                 {
419                         y2 ^= y1;
420                         y1 ^= y2;
421                         y2 ^= y1;
422                         x1 ^= x2;
423                         x2 ^= x1;
424                         x1 ^= x2;
425                 }
426                 int numerator = y2 - y1;
427                 int denominator = x2 - x1;
428                 for(int i = x1; i <= x2; i++)
429                 {
430                         int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
431                         draw_pixel(frame, i, y);
432                 }
433         }
434         else
435         {
436 // Flip coordinates so y1 < y2
437                 if(y2 < y1)
438                 {
439                         y2 ^= y1;
440                         y1 ^= y2;
441                         y2 ^= y1;
442                         x1 ^= x2;
443                         x2 ^= x1;
444                         x1 ^= x2;
445                 }
446                 int numerator = x2 - x1;
447                 int denominator = y2 - y1;
448                 for(int i = y1; i <= y2; i++)
449                 {
450                         int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
451                         draw_pixel(frame, x, i);
452                 }
453         }
454 //printf("FindObjectMain::draw_line 2\n");
455 }
456
457 void FindObjectMain::draw_rect(VFrame *frame, int x1, int y1, int x2, int y2)
458 {
459         draw_line(frame, x1, y1, x2, y1);
460         draw_line(frame, x2, y1 + 1, x2, y2);
461         draw_line(frame, x2 - 1, y2, x1, y2);
462         draw_line(frame, x1, y2 - 1, x1, y1 + 1);
463 }
464
465
466
467 // Convert to greyscale & crop
468 void FindObjectMain::grey_crop(unsigned char *dst,
469         VFrame *src,
470         int x1,
471         int y1,
472         int x2,
473         int y2,
474         int dst_w,
475         int dst_h)
476 {
477 // Dimensions of dst frame
478         int w = x2 - x1;
479         int h = y2 - y1;
480
481         bzero(dst, dst_w * dst_h);
482
483 //printf("FindObjectMain::grey_crop %d %d %d\n", __LINE__, w, h);
484         for(int i = 0; i < h; i++)
485         {
486
487 #define RGB_TO_VALUE(r, g, b) \
488 ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
489
490
491 #define CONVERT(in_type, max, components, is_yuv) \
492 { \
493         in_type *input = ((in_type*)src->get_rows()[i + y1]) + x1 * components; \
494         unsigned char *output = dst + i * dst_w; \
495  \
496         for(int j = 0; j < w; j++) \
497         { \
498 /* Y channel only */ \
499                 if(is_yuv) \
500                 { \
501                         *output = *input; \
502                 } \
503 /* RGB */ \
504                 else \
505                 { \
506                         float r = (float)input[0] / max; \
507                         float g = (float)input[1] / max; \
508                         float b = (float)input[2] / max; \
509                         *output = RGB_TO_VALUE(r, g, b); \
510                 } \
511  \
512                 input += components; \
513                 output++; \
514         } \
515 }
516                 switch(src->get_color_model())
517                 {
518                         case BC_RGB888:
519                         {
520                                 CONVERT(unsigned char, 0xff, 3, 0)
521                                 break;
522                         }
523
524                         case BC_RGBA8888:
525                         {
526                                 CONVERT(unsigned char, 0xff, 4, 0)
527                                 break;
528                         }
529
530                         case BC_RGB_FLOAT:
531                         {
532                                 CONVERT(float, 1.0, 3, 0)
533                                 break;
534                         }
535
536                         case BC_RGBA_FLOAT:
537                         {
538                                 CONVERT(float, 1.0, 4, 0)
539                                 break;
540                         }
541
542                         case BC_YUV888:
543                         {
544                                 CONVERT(unsigned char, 0xff, 3, 1)
545                                 break;
546                         }
547
548                         case BC_YUVA8888:
549                         {
550                                 CONVERT(unsigned char, 0xff, 4, 1)
551                                 break;
552                         }
553                 }
554         }
555 }
556
557
558 void FindObjectMain::process_surf()
559 {
560
561         if(!object_image)
562         {
563 // Only does greyscale
564                 object_image = cvCreateImage(
565                         cvSize(object_image_w, object_image_h),
566                         8,
567                         1);
568         }
569
570         if(!scene_image)
571         {
572 // Only does greyscale
573                 scene_image = cvCreateImage(
574                         cvSize(scene_image_w, scene_image_h),
575                         8,
576                         1);
577         }
578
579 // Select only region with image size
580 // Does this do anything?
581         cvSetImageROI( object_image, cvRect( 0, 0, object_w, object_h ) );
582         cvSetImageROI( scene_image, cvRect( 0, 0, scene_w, scene_h ) );
583
584         if(!prev_object) prev_object = new unsigned char[object_image_w * object_image_h];
585         memcpy(prev_object, object_image->imageData, object_image_w * object_image_h);
586         grey_crop((unsigned char*)scene_image->imageData,
587                 get_input(scene_layer),
588                 scene_x1,
589                 scene_y1,
590                 scene_x2,
591                 scene_y2,
592                 scene_image_w,
593                 scene_image_h);
594
595
596         grey_crop((unsigned char*)object_image->imageData,
597                 get_input(object_layer),
598                 object_x1,
599                 object_y1,
600                 object_x2,
601                 object_y2,
602                 object_image_w,
603                 object_image_h);
604
605
606         if(!storage) storage = cvCreateMemStorage(0);
607         CvSURFParams params = cvSURFParams(500, 1);
608
609
610 //printf("FindObjectMain::process_surf %d\n", __LINE__);
611
612 // Only compute keypoints if the image changed
613         if(memcmp(prev_object, object_image->imageData, object_image_w * object_image_h))
614         {
615                 if(object_keypoints) cvClearSeq(object_keypoints);
616                 if(object_descriptors) cvClearSeq(object_descriptors);
617                 cvExtractSURF(object_image,
618                         0,
619                         &object_keypoints,
620                         &object_descriptors,
621                         storage,
622                         params,
623                         0);
624         }
625
626 //printf("FindObjectMain::process_surf %d object keypoints=%d\n", __LINE__, object_keypoints->total);
627 // Draw the keypoints
628 //              for(int i = 0; i < object_keypoints->total; i++)
629 //              {
630 //              CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( object_keypoints, i );
631 //                      int size = r1->size / 4;
632 //                      draw_rect(frame[object_layer],
633 //                              r1->pt.x + object_x1 - size,
634 //                              r1->pt.y + object_y1 - size,
635 //                              r1->pt.x + object_x1 + size,
636 //                              r1->pt.y + object_y1 + size);
637 //              }
638
639
640 //printf("FindObjectMain::process_surf %d\n", __LINE__);
641
642 // TODO: make the surf data persistent & check for image changes instead
643         if(scene_keypoints) cvClearSeq(scene_keypoints);
644         if(scene_descriptors) cvClearSeq(scene_descriptors);
645         cvExtractSURF(scene_image,
646                 0,
647                 &scene_keypoints,
648                 &scene_descriptors,
649                 storage,
650                 params,
651                 0);
652
653 // Draw the keypoints
654 //              for(int i = 0; i < scene_keypoints->total; i++)
655 //              {
656 //              CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( scene_keypoints, i );
657 //                      int size = r1->size / 4;
658 //                      draw_rect(frame[scene_layer],
659 //                              r1->pt.x + scene_x1 - size,
660 //                              r1->pt.y + scene_y1 - size,
661 //                              r1->pt.x + scene_x1 + size,
662 //                              r1->pt.y + scene_y1 + size);
663 //              }
664
665 // printf("FindObjectMain::process_surf %d %d %d scene keypoints=%d\n",
666 // __LINE__,
667 // scene_w,
668 // scene_h,
669 // scene_keypoints->total);
670
671         int *point_pairs = 0;
672         int total_pairs = 0;
673         CvPoint src_corners[4] =
674         {
675                 { 0, 0 },
676                 { object_w, 0 },
677                 { object_w, object_h },
678                 { 0, object_h }
679         };
680
681         CvPoint dst_corners[4] =
682         {
683                 { 0, 0 },
684                 { 0, 0 },
685                 { 0, 0 },
686                 { 0, 0 }
687         };
688
689 //printf("FindObjectMain::process_surf %d\n", __LINE__);
690         if(scene_keypoints->total &&
691                 object_keypoints->total &&
692                         locatePlanarObject(object_keypoints,
693                         object_descriptors,
694                         scene_keypoints,
695                         scene_descriptors,
696                         src_corners,
697                         dst_corners,
698                         &point_pairs,
699                         &total_pairs))
700         {
701
702
703
704
705
706 // Draw keypoints in the scene & object layer
707                 if(config.draw_keypoints)
708                 {
709 //printf("FindObjectMain::process_surf %d total pairs=%d\n", __LINE__, total_pairs);
710                         for(int i = 0; i < total_pairs; i++)
711                         {
712                         CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( object_keypoints, point_pairs[i * 2] );
713                         CvSURFPoint* r2 = (CvSURFPoint*)cvGetSeqElem( scene_keypoints, point_pairs[i * 2 + 1] );
714
715
716                                 int size = r2->size * 1.2 / 9 * 2;
717                                 draw_rect(get_input(scene_layer),
718                                         r2->pt.x + scene_x1 - size,
719                                         r2->pt.y + scene_y1 - size,
720                                         r2->pt.x + scene_x1 + size,
721                                         r2->pt.y + scene_y1 + size);
722                                 draw_rect(get_input(object_layer),
723                                         r1->pt.x + object_x1 - size,
724                                         r1->pt.y + object_y1 - size,
725                                         r1->pt.x + object_x1 + size,
726                                         r1->pt.y + object_y1 + size);
727                         }
728                 }
729
730
731 //printf("FindObjectMain::process_surf %d\n", __LINE__);
732 // Get object outline in the scene layer
733                 border_x1 = dst_corners[0].x + scene_x1;
734                 border_y1 = dst_corners[0].y + scene_y1;
735                 border_x2 = dst_corners[1].x + scene_x1;
736                 border_y2 = dst_corners[1].y + scene_y1;
737                 border_x3 = dst_corners[2].x + scene_x1;
738                 border_y3 = dst_corners[2].y + scene_y1;
739                 border_x4 = dst_corners[3].x + scene_x1;
740                 border_y4 = dst_corners[3].y + scene_y1;
741 //printf("FindObjectMain::process_surf %d\n", __LINE__);
742
743
744
745         }
746 //printf("FindObjectMain::process_surf %d\n", __LINE__);
747
748
749
750 // for(int i = 0; i < object_y2 - object_y1; i++)
751 // {
752 //      unsigned char *dst = get_input(object_layer)->get_rows()[i];
753 //      unsigned char *src = (unsigned char*)object_image->imageData + i * (object_x2 - object_x1);
754 //      for(int j = 0; j < object_x2 - object_x1; j++)
755 //      {
756 //              *dst++ = *src;
757 //              *dst++ = 0x80;
758 //              *dst++ = 0x80;
759 //              src++;
760 //      }
761 // }
762
763
764 // Frees the image structures
765         if(point_pairs) free(point_pairs);
766 }
767
768
769
770 void FindObjectMain::process_camshift()
771 {
772 // Some user defined parameters
773         int vmin = config.vmin;
774         int vmax = config.vmax;
775         int smin = config.smin;
776         float hranges[] = { 0, 180 };
777         const float* phranges = hranges;
778
779
780 // Create aligned, RGB images
781         if(!object_image)
782         {
783                 object_image = cvCreateImage(
784                         cvSize(object_image_w, object_image_h),
785                         8,
786                         3);
787         }
788
789         if(!scene_image)
790         {
791                 scene_image = cvCreateImage(
792                         cvSize(scene_image_w, scene_image_h),
793                         8,
794                         3);
795         }
796
797 // Temporary row pointers
798         unsigned char **object_rows = new unsigned char*[object_image_h];
799         unsigned char **scene_rows = new unsigned char*[scene_image_h];
800         for(int i = 0; i < object_image_h; i++)
801         {
802                 object_rows[i] = (unsigned char*)(object_image->imageData + i * object_image_w * 3);
803         }
804         for(int i = 0; i < scene_image_h; i++)
805         {
806                 scene_rows[i] = (unsigned char*)(scene_image->imageData + i * scene_image_w * 3);
807         }
808
809 // Transfer object & scene to RGB images for OpenCV
810         if(!prev_object) prev_object = new unsigned char[object_image_w * object_image_h * 3];
811 // Back up old object image
812         memcpy(prev_object, object_image->imageData, object_image_w * object_image_h * 3);
813
814         BC_CModels::transfer(object_rows,
815                 get_input(object_layer)->get_rows(),
816                 0,
817                 0,
818                 0,
819                 0,
820                 0,
821                 0,
822                 object_x1,
823                 object_y1,
824                 object_w,
825                 object_h,
826                 0,
827                 0,
828                 object_w,
829                 object_h,
830                 get_input(object_layer)->get_color_model(),
831                 BC_RGB888,
832                 0,
833                 0,
834                 0);
835         BC_CModels::transfer(scene_rows,
836                 get_input(scene_layer)->get_rows(),
837                 0,
838                 0,
839                 0,
840                 0,
841                 0,
842                 0,
843                 scene_x1,
844                 scene_y1,
845                 scene_w,
846                 scene_h,
847                 0,
848                 0,
849                 scene_w,
850                 scene_h,
851                 get_input(scene_layer)->get_color_model(),
852                 BC_RGB888,
853                 0,
854                 0,
855                 0);
856
857         delete [] object_rows;
858         delete [] scene_rows;
859
860 // from camshiftdemo.cpp
861 // Compute new object
862         if(memcmp(prev_object,
863                 object_image->imageData,
864                 object_image_w * object_image_h * 3) ||
865                 !hist.dims)
866         {
867                 Mat image(object_image);
868                 Mat hsv, hue, mask;
869                 cvtColor(image, hsv, CV_RGB2HSV);
870         int _vmin = vmin, _vmax = vmax;
871 //printf("FindObjectMain::process_camshift %d\n", __LINE__);
872
873         inRange(hsv,
874                         Scalar(0, smin, MIN(_vmin,_vmax)),
875                 Scalar(180, 256, MAX(_vmin, _vmax)),
876                         mask);
877         int ch[] = { 0, 0 };
878         hue.create(hsv.size(), hsv.depth());
879         mixChannels(&hsv, 1, &hue, 1, ch, 1);
880
881                 Rect selection = Rect(0, 0, object_w, object_h);
882                 trackWindow = selection;
883                 int hsize = 16;
884                 Mat roi(hue, selection), maskroi(mask, selection);
885                 calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
886                 normalize(hist, hist, 0, 255, CV_MINMAX);
887         }
888
889
890 // compute scene
891         Mat image(scene_image);
892         Mat hsv, hue, mask, backproj;
893         cvtColor(image, hsv, CV_RGB2HSV);
894     int _vmin = vmin, _vmax = vmax;
895
896     inRange(hsv,
897                 Scalar(0, smin, MIN(_vmin,_vmax)),
898         Scalar(180, 256, MAX(_vmin, _vmax)),
899                 mask);
900     int ch[] = {0, 0};
901     hue.create(hsv.size(), hsv.depth());
902     mixChannels(&hsv, 1, &hue, 1, ch, 1);
903
904 //printf("FindObjectMain::process_camshift %d %d %d\n", __LINE__, hist.dims, hist.size[1]);
905         RotatedRect trackBox = RotatedRect(
906                 Point2f((object_x1 + object_x2) / 2, (object_y1 + object_y2) / 2),
907                 Size2f(object_w, object_h),
908                 0);
909         trackWindow = Rect(0,
910                 0,
911         scene_w,
912                 scene_h);
913         if(hist.dims > 0)
914         {
915
916
917                 calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
918                 backproj &= mask;
919 //printf("FindObjectMain::process_camshift %d\n", __LINE__);
920 //              if(trackWindow.width <= 0 ||
921 //                      trackWindow.height <= 0)
922 //              {
923 //                      trackWindow.width = object_w;
924 //                      trackWindow.height = object_h;
925 //              }
926
927                 trackBox = CamShift(backproj,
928                         trackWindow,
929                 TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
930 //printf("FindObjectMain::process_camshift %d\n", __LINE__);
931
932
933 //      if( trackWindow.area() <= 1 )
934 //      {
935 //              int cols = backproj.cols;
936 //                      int rows = backproj.rows;
937 //                      int r = (MIN(cols, rows) + 5) / 6;
938 //              trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
939 //                                 trackWindow.x + r, trackWindow.y + r) &
940 //                        Rect(0, 0, cols, rows);
941 //      }
942         }
943 // printf("FindObjectMain::process_camshift %d %d %d %d %d\n",
944 // __LINE__,
945 // trackWindow.x,
946 // trackWindow.y,
947 // trackWindow.width,
948 // trackWindow.height);
949
950
951 // Draw mask over scene
952         if(config.draw_keypoints)
953         {
954                 for(int i = 0; i < scene_h; i++)
955                 {
956                         switch(get_input(scene_layer)->get_color_model())
957                         {
958                                 case BC_YUV888:
959                                 {
960                                         unsigned char *input = backproj.data + i * scene_image_w;
961                                         unsigned char *output = get_input(scene_layer)->get_rows()[i + scene_y1] + scene_x1 * 3;
962                                         for(int j = 0; j < scene_w; j++)
963                                         {
964                                                 output[0] = *input;
965                                                 output[1] = 0x80;
966                                                 output[2] = 0x80;
967                                                 output += 3;
968                                                 input++;
969                                         }
970                                         break;
971                                 }
972                         }
973                 }
974         }
975
976 // Get object outline in the scene layer
977 // printf("FindObjectMain::process_camshift %d %d %d %d %d %d\n",
978 // __LINE__,
979 // (int)trackBox.center.x,
980 // (int)trackBox.center.y,
981 // (int)trackBox.size.width,
982 // (int)trackBox.size.height,
983 // (int)trackBox.angle);
984         double angle = trackBox.angle * 2 * M_PI / 360;
985         double angle1 = atan2(-(double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle;
986         double angle2 = atan2(-(double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle;
987         double angle3 = atan2((double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle;
988         double angle4 = atan2((double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle;
989         double radius = sqrt(SQR(trackBox.size.height / 2) + SQR(trackBox.size.width / 2));
990         border_x1 = (int)(trackBox.center.x + cos(angle1) * radius) + scene_x1;
991         border_y1 = (int)(trackBox.center.y + sin(angle1) * radius) + scene_y1;
992         border_x2 = (int)(trackBox.center.x + cos(angle2) * radius) + scene_x1;
993         border_y2 = (int)(trackBox.center.y + sin(angle2) * radius) + scene_y1;
994         border_x3 = (int)(trackBox.center.x + cos(angle3) * radius) + scene_x1;
995         border_y3 = (int)(trackBox.center.y + sin(angle3) * radius) + scene_y1;
996         border_x4 = (int)(trackBox.center.x + cos(angle4) * radius) + scene_x1;
997         border_y4 = (int)(trackBox.center.y + sin(angle4) * radius) + scene_y1;
998
999 }
1000
1001
1002 #define APPLY_MASK(type, max, components, do_yuv) \
1003 { \
1004         type *output_row = (type*)get_input(scene_layer)->get_rows()[i]; \
1005         unsigned char *mask_row = mask_rows[i]; \
1006         int chroma_offset = (int)(max + 1) / 2; \
1007  \
1008         for(int j  = 0; j < scene_w; j++) \
1009         { \
1010                 if(components == 4) \
1011                 { \
1012                         output_row[j * 4 + 3] = output_row[j * 4 + 3] * mask_row[j] / 255; \
1013                 } \
1014                 else \
1015                 { \
1016                         output_row[j * 3] = output_row[j * 3] * mask_row[j] / 255; \
1017                         output_row[j * 3 + 1] = output_row[j * 3 + 1] * mask_row[j] / 255; \
1018                         output_row[j * 3 + 2] = output_row[j * 3 + 2] * mask_row[j] / 255; \
1019  \
1020                         if(do_yuv) \
1021                         { \
1022                                 output_row[j * 3 + 1] += chroma_offset * (255 - mask_row[j]) / 255; \
1023                                 output_row[j * 3 + 2] += chroma_offset * (255 - mask_row[j]) / 255; \
1024                         } \
1025                 } \
1026         } \
1027 }
1028
1029
1030
1031 // blobtrack_sample.cpp
1032 void FindObjectMain::process_blob()
1033 {
1034         if(!blob_initialized)
1035         {
1036                 blob_initialized = 1;
1037
1038                 blob_param.FGTrainFrames = 5;
1039
1040
1041 /* Create FG Detection module: */
1042                 blob_param.pFG = cvCreateFGDetectorBase(CV_BG_MODEL_FGD, NULL);
1043 /* Create Blob Entrance Detection module: */
1044         blob_param.pBD = cvCreateBlobDetectorCC();
1045 /* Create blob tracker module: */
1046         blob_param.pBT = cvCreateBlobTrackerCCMSPF();
1047 /* Create whole pipline: */
1048         blob_pTracker = cvCreateBlobTrackerAuto1(&blob_param);
1049
1050         }
1051
1052
1053 /* Process: */
1054         IplImage*   pMask = NULL;
1055
1056 // Create aligned, RGB images
1057         if(!scene_image)
1058         {
1059                 scene_image = cvCreateImage(
1060                         cvSize(scene_image_w, scene_image_h),
1061                         8,
1062                         3);
1063         }
1064
1065 // Temporary row pointers
1066         unsigned char **scene_rows = new unsigned char*[scene_image_h];
1067         for(int i = 0; i < scene_image_h; i++)
1068         {
1069                 scene_rows[i] = (unsigned char*)(scene_image->imageData + i * scene_image_w * 3);
1070         }
1071
1072         BC_CModels::transfer(scene_rows,
1073                 get_input(scene_layer)->get_rows(),
1074                 0,
1075                 0,
1076                 0,
1077                 0,
1078                 0,
1079                 0,
1080                 scene_x1,
1081                 scene_y1,
1082                 scene_w,
1083                 scene_h,
1084                 0,
1085                 0,
1086                 scene_w,
1087                 scene_h,
1088                 get_input(scene_layer)->get_color_model(),
1089                 BC_RGB888,
1090                 0,
1091                 0,
1092                 0);
1093
1094         delete [] scene_rows;
1095
1096     blob_pTracker->Process(scene_image, pMask);
1097 printf("FindObjectMain::process_blob %d %jd %d\n", __LINE__, get_source_position(), blob_pTracker->GetBlobNum());
1098
1099
1100 #if 0
1101         if(blob_pTracker->GetFGMask())
1102         {
1103                 IplImage* pFG = blob_pTracker->GetFGMask();
1104 printf("FindObjectMain::process_blob %d %ld\n", __LINE__, get_source_position());
1105
1106 // Temporary row pointers
1107                 unsigned char **mask_rows = new unsigned char*[scene_image_h];
1108                 for(int i = 0; i < scene_image_h; i++)
1109                 {
1110                         mask_rows[i] = (unsigned char*)(pFG->imageData + i * scene_image_w);
1111                 }
1112
1113                 for(int i = 0; i < scene_image_h; i++)
1114                 {
1115                         switch(get_input(scene_layer)->get_color_model())
1116                         {
1117                                 case BC_RGB888:
1118                                         APPLY_MASK(unsigned char, 0xff, 3, 0)
1119                                         break;
1120                                 case BC_RGB_FLOAT:
1121                                         APPLY_MASK(float, 1.0, 3, 0)
1122                                         break;
1123                                 case BC_YUV888:
1124                                         APPLY_MASK(unsigned char, 0xff, 3, 1)
1125                                         break;
1126                                 case BC_RGBA8888:
1127                                         APPLY_MASK(unsigned char, 0xff, 4, 0)
1128                                         break;
1129                                 case BC_RGBA_FLOAT:
1130                                         APPLY_MASK(float, 1.0, 4, 0)
1131                                         break;
1132                                 case BC_YUVA8888:
1133                                         APPLY_MASK(unsigned char, 0xff, 4, 1)
1134                                         break;
1135                         }
1136                 }
1137
1138                 delete [] mask_rows;
1139
1140
1141         }
1142 #endif
1143
1144
1145 }
1146
1147
1148
1149
1150
1151
1152
1153 int FindObjectMain::process_buffer(VFrame **frame,
1154         int64_t start_position,
1155         double frame_rate)
1156 {
1157         int prev_algorithm = config.algorithm;
1158         if(load_configuration())
1159         {
1160                 init_border = 1;
1161         }
1162
1163         w = frame[0]->get_w();
1164         h = frame[0]->get_h();
1165 //printf("FindObjectMain::process_buffer %d\n", __LINE__);
1166
1167
1168 // Get the layer containing the object.
1169         object_layer = config.object_layer;
1170 // Get the layer to search in.
1171         scene_layer = config.scene_layer;
1172 // Get the layer with the replacement object
1173         replace_layer = config.replace_layer;
1174
1175         object_layer = MIN(object_layer, PluginClient::get_total_buffers() - 1);
1176         scene_layer = MIN(scene_layer, PluginClient::get_total_buffers() - 1);
1177         replace_layer = MIN(replace_layer, PluginClient::get_total_buffers() - 1);
1178
1179 // printf("FindObjectMain::process_buffer %d %d %d %d %d %d\n",
1180 // __LINE__,
1181 // PluginClient::get_total_buffers(),
1182 // config.object_layer,
1183 // config.scene_layer,
1184 // object_layer,
1185 // scene_layer);
1186 //
1187 // Create cropped images
1188 // TODO: use oblique corners & affine transform
1189         object_w = (int)(config.global_block_w * w / 100);
1190         object_h = (int)(config.global_block_h * h / 100);
1191
1192         object_x1 = (int)(config.block_x * w / 100 - object_w / 2);
1193         object_y1 = (int)(config.block_y * h / 100 - object_h / 2);
1194         object_x2 = object_x1 + object_w;
1195         object_y2 = object_y1 + object_h;
1196         CLAMP(object_x1, 0, frame[0]->get_w() - 1);
1197         CLAMP(object_x2, 0, frame[0]->get_w() - 1);
1198         CLAMP(object_y1, 0, frame[0]->get_h() - 1);
1199         CLAMP(object_y2, 0, frame[0]->get_h() - 1);
1200         object_w = object_x2 - object_x1;
1201         object_h = object_y2 - object_y1;
1202
1203
1204         scene_w = (int)(config.global_range_w * w / 100);
1205         scene_h = (int)(config.global_range_h * h / 100);
1206         scene_x1 = (int)(config.block_x * w / 100 - scene_w / 2);
1207         scene_y1 = (int)(config.block_y * h / 100 - scene_h / 2);
1208         scene_x2 = scene_x1 + scene_w;
1209         scene_y2 = scene_y1 + scene_h;
1210         CLAMP(scene_x1, 0, frame[0]->get_w() - 1);
1211         CLAMP(scene_x2, 0, frame[0]->get_w() - 1);
1212         CLAMP(scene_y1, 0, frame[0]->get_h() - 1);
1213         CLAMP(scene_y2, 0, frame[0]->get_h() - 1);
1214         scene_w = scene_x2 - scene_x1;
1215         scene_h = scene_y2 - scene_y1;
1216
1217 // Get quantized sizes
1218         int object_image_w = object_w;
1219         int object_image_h = object_h;
1220         int scene_image_w = scene_w;
1221         int scene_image_h = scene_h;
1222         if(object_w % QUANTIZE) object_image_w += QUANTIZE - (object_w % QUANTIZE);
1223         if(object_h % QUANTIZE) object_image_h += QUANTIZE - (object_h % QUANTIZE);
1224         if(scene_w % QUANTIZE) scene_image_w += QUANTIZE - (scene_w % QUANTIZE);
1225         if(scene_h % QUANTIZE) scene_image_h += QUANTIZE - (scene_h % QUANTIZE);
1226
1227         if(object_image &&
1228                 (object_image_w != this->object_image_w ||
1229                 object_image_h != this->object_image_h ||
1230                 prev_algorithm != config.algorithm))
1231         {
1232                 cvReleaseImage(&object_image);
1233                 object_image = 0;
1234                 delete [] prev_object;
1235                 prev_object = 0;
1236         }
1237         this->object_image_w = object_image_w;
1238         this->object_image_h = object_image_h;
1239
1240         if(scene_image &&
1241                 (scene_image_w != this->scene_image_w ||
1242                 scene_image_h != this->scene_image_h ||
1243                 prev_algorithm != config.algorithm))
1244         {
1245                 cvReleaseImage(&scene_image);
1246                 scene_image = 0;
1247         }
1248         this->scene_image_w = scene_image_w;
1249         this->scene_image_h = scene_image_h;
1250
1251
1252
1253
1254 //printf("FindObjectMain::process_buffer %d object_w=%d object_h=%d object_image_w=%d object_image_h=%d\n", __LINE__, object_w, object_h, object_image_w, object_image_h);
1255 //printf("FindObjectMain::process_buffer %d scene_w=%d scene_h=%d scene_image_w=%d scene_image_h=%d\n", __LINE__, scene_w, scene_h, scene_image_w, scene_image_h);
1256 //printf("FindObjectMain::process_buffer %d total_layers=%d\n", __LINE__, get_total_buffers());
1257
1258 // Read in the input frames
1259         for(int i = 0; i < PluginClient::get_total_buffers(); i++)
1260         {
1261                 read_frame(frame[i],
1262                         i,
1263                         start_position,
1264                         frame_rate);
1265         }
1266
1267
1268 // Search for object
1269         if(config.algorithm != NO_ALGORITHM &&
1270                 (config.replace_object ||
1271                 config.draw_border ||
1272                 config.draw_keypoints))
1273         {
1274
1275
1276                 switch(config.algorithm)
1277                 {
1278 #if HAVE_OPENCV_SURF
1279                         case ALGORITHM_SURF:
1280                                 process_surf();
1281                                 break;
1282 #endif
1283
1284                         case ALGORITHM_CAMSHIFT:
1285                                 process_camshift();
1286                                 break;
1287
1288                         case ALGORITHM_BLOB:
1289                                 process_blob();
1290                                 break;
1291                 }
1292
1293
1294                 if(init_border)
1295                 {
1296                         border_x1_accum = border_x1;
1297                         border_y1_accum = border_y1;
1298                         border_x2_accum = border_x2;
1299                         border_y2_accum = border_y2;
1300                         border_x3_accum = border_x3;
1301                         border_y3_accum = border_y3;
1302                         border_x4_accum = border_x4;
1303                         border_y4_accum = border_y4;
1304                         init_border = 0;
1305                 }
1306                 else
1307                 {
1308                         border_x1_accum = (float)border_x1 * config.blend / 100 +
1309                                 border_x1_accum * (100 - config.blend) / 100;
1310                         border_y1_accum = (float)border_y1 * config.blend / 100 +
1311                                 border_y1_accum * (100 - config.blend) / 100;
1312                         border_x2_accum = (float)border_x2 * config.blend / 100 +
1313                                 border_x2_accum * (100 - config.blend) / 100;
1314                         border_y2_accum = (float)border_y2 * config.blend / 100 +
1315                                 border_y2_accum * (100 - config.blend) / 100;
1316                         border_x3_accum = (float)border_x3 * config.blend / 100 +
1317                                 border_x3_accum * (100 - config.blend) / 100;
1318                         border_y3_accum = (float)border_y3 * config.blend / 100 +
1319                                 border_y3_accum * (100 - config.blend) / 100;
1320                         border_x4_accum = (float)border_x4 * config.blend / 100 +
1321                                 border_x4_accum * (100 - config.blend) / 100;
1322                         border_y4_accum = (float)border_y4 * config.blend / 100 +
1323                                 border_y4_accum * (100 - config.blend) / 100;
1324                 }
1325
1326 // Replace object in the scene layer
1327                 if(config.replace_object)
1328                 {
1329
1330 // Some trickery to get the affine transform to alpha blend into the output
1331                         if(!affine) affine = new AffineEngine(get_project_smp() + 1,
1332                                 get_project_smp() + 1);
1333
1334 //printf("FindObjectMain::process_surf %d replace_layer=%d\n", __LINE__, replace_layer);
1335                         if(!temp)
1336                                 temp = new VFrame(w,
1337                                         h,
1338                                         get_input(scene_layer)->get_color_model());
1339                         if(!overlayer)
1340                                 overlayer = new OverlayFrame(get_project_smp() + 1);
1341
1342                         temp->clear_frame();
1343                         affine->process(temp,
1344                                 get_input(replace_layer),
1345                                 0,
1346                                 AffineEngine::PERSPECTIVE,
1347                                 border_x1_accum * 100 / w,
1348                                 border_y1_accum * 100 / h,
1349                                 border_x2_accum * 100 / w,
1350                                 border_y2_accum * 100 / h,
1351                                 border_x3_accum * 100 / w,
1352                                 border_y3_accum * 100 / h,
1353                                 border_x4_accum * 100 / w,
1354                                 border_y4_accum * 100 / h,
1355                                 1);
1356
1357                         overlayer->overlay(get_input(scene_layer),
1358                                 temp,
1359                                 0,
1360                                 0,
1361                                 w,
1362                                 h,
1363                                 0,
1364                                 0,
1365                                 w,
1366                                 h,
1367                                 1,        // 0 - 1
1368                                 TRANSFER_NORMAL,
1369                                 NEAREST_NEIGHBOR);
1370                 }
1371
1372
1373                 if(config.draw_border)
1374                 {
1375                         draw_line(get_input(scene_layer),
1376                                 border_x1_accum,
1377                                 border_y1_accum,
1378                                 border_x2_accum,
1379                                 border_y2_accum);
1380                         draw_line(get_input(scene_layer),
1381                                 border_x2_accum,
1382                                 border_y2_accum,
1383                                 border_x3_accum,
1384                                 border_y3_accum);
1385                         draw_line(get_input(scene_layer),
1386                                 border_x3_accum,
1387                                 border_y3_accum,
1388                                 border_x4_accum,
1389                                 border_y4_accum);
1390                         draw_line(get_input(scene_layer),
1391                                 border_x4_accum,
1392                                 border_y4_accum,
1393                                 border_x1_accum,
1394                                 border_y1_accum);
1395                 }
1396
1397         }
1398
1399 // Draw object outline in the object layer
1400         if(config.draw_object_border)
1401         {
1402                 draw_line(frame[object_layer], object_x1, object_y1, object_x2, object_y1);
1403                 draw_line(frame[object_layer], object_x2, object_y1, object_x2, object_y2);
1404                 draw_line(frame[object_layer], object_x2, object_y2, object_x1, object_y2);
1405                 draw_line(frame[object_layer], object_x1, object_y2, object_x1, object_y1);
1406
1407                 draw_line(frame[object_layer], scene_x1, scene_y1, scene_x2, scene_y1);
1408                 draw_line(frame[object_layer], scene_x2, scene_y1, scene_x2, scene_y2);
1409                 draw_line(frame[object_layer], scene_x2, scene_y2, scene_x1, scene_y2);
1410                 draw_line(frame[object_layer], scene_x1, scene_y2, scene_x1, scene_y1);
1411         }
1412
1413
1414
1415
1416         return 0;
1417 }
1418
1419