/* * CINELERRA * Copyright (C) 1997-2012 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // This is mainly a test for object tracking #include "affine.h" #include "cicolors.h" #include "clip.h" #include "filexml.h" #include "keyframe.h" #include "language.h" #include "findobject.h" #include "findobjectwindow.h" #include "mutex.h" #include "overlayframe.h" #include "surfscan.h" #include "transportque.h" // Needed with OpenCV version 2.4.8 #include "opencv2/legacy/legacy.hpp" #include "opencv2/legacy/compat.hpp" #include "opencv2/video/tracking.hpp" #include "opencv2/video/background_segm.hpp" #include #include REGISTER_PLUGIN(FindObjectMain) FindObjectConfig::FindObjectConfig() { global_range_w = 5; global_range_h = 5; draw_keypoints = 1; draw_border = 1; replace_object = 0; draw_object_border = 1; global_block_w = MIN_BLOCK; global_block_h = MIN_BLOCK; block_x = 50; block_y = 50; object_layer = 0; replace_layer = 1; scene_layer = 2; algorithm = NO_ALGORITHM; vmin = 10; vmax = 256; smin = 30; blend = 100; } void FindObjectConfig::boundaries() { CLAMP(global_range_w, MIN_RADIUS, MAX_RADIUS); CLAMP(global_range_h, MIN_RADIUS, MAX_RADIUS); CLAMP(global_block_w, MIN_BLOCK, MAX_BLOCK); CLAMP(global_block_h, MIN_BLOCK, MAX_BLOCK); CLAMP(block_x, 0, 100); CLAMP(block_y, 0, 100); CLAMP(object_layer, MIN_LAYER, MAX_LAYER); CLAMP(replace_layer, MIN_LAYER, MAX_LAYER); CLAMP(scene_layer, MIN_LAYER, MAX_LAYER); CLAMP(vmin, MIN_CAMSHIFT, MAX_CAMSHIFT); CLAMP(vmax, MIN_CAMSHIFT, MAX_CAMSHIFT); CLAMP(smin, MIN_CAMSHIFT, MAX_CAMSHIFT); CLAMP(blend, MIN_BLEND, MAX_BLEND); } int FindObjectConfig::equivalent(FindObjectConfig &that) { int result = global_range_w == that.global_range_w && global_range_h == that.global_range_h && draw_keypoints == that.draw_keypoints && draw_border == that.draw_border && replace_object == that.replace_object && draw_object_border == that.draw_object_border && global_block_w == that.global_block_w && global_block_h == that.global_block_h && block_x == that.block_x && block_y == that.block_y && object_layer == that.object_layer && replace_layer == that.replace_layer && scene_layer == that.scene_layer && algorithm == that.algorithm && vmin == that.vmin && vmax == that.vmax && smin == that.smin && blend == that.blend; return result; } void FindObjectConfig::copy_from(FindObjectConfig &that) { global_range_w = that.global_range_w; global_range_h = that.global_range_h; draw_keypoints = that.draw_keypoints; draw_border = that.draw_border; replace_object = that.replace_object; draw_object_border = that.draw_object_border; global_block_w = that.global_block_w; global_block_h = that.global_block_h; block_x = that.block_x; block_y = that.block_y; object_layer = that.object_layer; replace_layer = that.replace_layer; scene_layer = that.scene_layer; algorithm = that.algorithm; vmin = that.vmin; vmax = that.vmax; smin = that.smin; blend = that.blend; } void FindObjectConfig::interpolate(FindObjectConfig &prev, FindObjectConfig &next, int64_t prev_frame, int64_t next_frame, int64_t current_frame) { copy_from(prev); } FindObjectMain::FindObjectMain(PluginServer *server) : PluginVClient(server) { bzero(&blob_param, sizeof(CvBlobTrackerAutoParam1)); blob_pTracker = 0; object_image = 0; prev_object = 0; scene_image = 0; object_image_w = 0; object_image_h = 0; scene_image_w = 0; scene_image_h = 0; storage = 0; object_keypoints = 0; object_descriptors = 0; scene_keypoints = 0; scene_descriptors = 0; affine = 0; temp = 0; overlayer = 0; init_border = 1; } FindObjectMain::~FindObjectMain() { // This releases all the arrays if(storage) cvReleaseMemStorage(&storage); if(object_image) cvReleaseImage(&object_image); if(scene_image) cvReleaseImage(&scene_image); if(prev_object) delete [] prev_object; delete affine; delete temp; delete overlayer; if(blob_param.pBT) cvReleaseBlobTracker(&blob_param.pBT); if(blob_param.pBD) cvReleaseBlobDetector(&blob_param.pBD); if(blob_param.pBTGen) cvReleaseBlobTrackGen(&blob_param.pBTGen); if(blob_param.pBTA) cvReleaseBlobTrackAnalysis(&blob_param.pBTA); if(blob_param.pFG) cvReleaseFGDetector(&blob_param.pFG); if(blob_pTracker) cvReleaseBlobTrackerAuto(&blob_pTracker); } const char* FindObjectMain::plugin_title() { return _("Find Object"); } int FindObjectMain::is_realtime() { return 1; } int FindObjectMain::is_multichannel() { return 1; } NEW_WINDOW_MACRO(FindObjectMain, FindObjectWindow) LOAD_CONFIGURATION_MACRO(FindObjectMain, FindObjectConfig) void FindObjectMain::update_gui() { if(thread) { if(load_configuration()) { thread->window->lock_window("FindObjectMain::update_gui"); char string[BCTEXTLEN]; ((FindObjectWindow*)thread->window)->global_range_w->update(config.global_range_w); ((FindObjectWindow*)thread->window)->global_range_h->update(config.global_range_h); ((FindObjectWindow*)thread->window)->global_block_w->update(config.global_block_w); ((FindObjectWindow*)thread->window)->global_block_h->update(config.global_block_h); ((FindObjectWindow*)thread->window)->block_x->update(config.block_x); ((FindObjectWindow*)thread->window)->block_y->update(config.block_y); ((FindObjectWindow*)thread->window)->block_x_text->update((float)config.block_x); ((FindObjectWindow*)thread->window)->block_y_text->update((float)config.block_y); ((FindObjectWindow*)thread->window)->draw_keypoints->update(config.draw_keypoints); ((FindObjectWindow*)thread->window)->draw_border->update(config.draw_border); ((FindObjectWindow*)thread->window)->replace_object->update(config.replace_object); ((FindObjectWindow*)thread->window)->draw_object_border->update(config.draw_object_border); ((FindObjectWindow*)thread->window)->object_layer->update( (int64_t)config.object_layer); ((FindObjectWindow*)thread->window)->replace_layer->update( (int64_t)config.replace_layer); ((FindObjectWindow*)thread->window)->scene_layer->update( (int64_t)config.scene_layer); ((FindObjectWindow*)thread->window)->algorithm->set_text( FindObjectAlgorithm::to_text(config.algorithm)); ((FindObjectWindow*)thread->window)->vmin->update( (int64_t)config.vmin); ((FindObjectWindow*)thread->window)->vmax->update( (int64_t)config.vmax); ((FindObjectWindow*)thread->window)->smin->update( (int64_t)config.smin); ((FindObjectWindow*)thread->window)->blend->update( (int64_t)config.blend); ((FindObjectWindow*)thread->window)->flush(); thread->window->unlock_window(); } // printf("FindObjectMain::update_gui %d %d %d %d\n", // __LINE__, // config.mode1, // config.mode2, // config.mode3); } } void FindObjectMain::save_data(KeyFrame *keyframe) { FileXML output; // cause data to be stored directly in text output.set_shared_output(keyframe->get_data(), MESSAGESIZE); output.tag.set_title("FINDOBJECT"); output.tag.set_property("GLOBAL_BLOCK_W", config.global_block_w); output.tag.set_property("GLOBAL_BLOCK_H", config.global_block_h); output.tag.set_property("BLOCK_X", config.block_x); output.tag.set_property("BLOCK_Y", config.block_y); output.tag.set_property("GLOBAL_RANGE_W", config.global_range_w); output.tag.set_property("GLOBAL_RANGE_H", config.global_range_h); output.tag.set_property("DRAW_KEYPOINTS", config.draw_keypoints); output.tag.set_property("DRAW_BORDER", config.draw_border); output.tag.set_property("REPLACE_OBJECT", config.replace_object); output.tag.set_property("DRAW_OBJECT_BORDER", config.draw_object_border); output.tag.set_property("OBJECT_LAYER", config.object_layer); output.tag.set_property("REPLACE_LAYER", config.replace_layer); output.tag.set_property("SCENE_LAYER", config.scene_layer); output.tag.set_property("ALGORITHM", config.algorithm); output.tag.set_property("VMIN", config.vmin); output.tag.set_property("VMAX", config.vmax); output.tag.set_property("SMIN", config.smin); output.tag.set_property("BLEND", config.blend); output.append_tag(); output.tag.set_title("/FINDOBJECT"); output.append_tag(); output.append_newline(); output.terminate_string(); } void FindObjectMain::read_data(KeyFrame *keyframe) { FileXML input; input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data())); int result = 0; while(!result) { result = input.read_tag(); if(!result) { if(input.tag.title_is("FINDOBJECT")) { config.global_block_w = input.tag.get_property("GLOBAL_BLOCK_W", config.global_block_w); config.global_block_h = input.tag.get_property("GLOBAL_BLOCK_H", config.global_block_h); config.block_x = input.tag.get_property("BLOCK_X", config.block_x); config.block_y = input.tag.get_property("BLOCK_Y", config.block_y); config.global_range_w = input.tag.get_property("GLOBAL_RANGE_W", config.global_range_w); config.global_range_h = input.tag.get_property("GLOBAL_RANGE_H", config.global_range_h); config.draw_keypoints = input.tag.get_property("DRAW_KEYPOINTS", config.draw_keypoints); config.draw_border = input.tag.get_property("DRAW_BORDER", config.draw_border); config.replace_object = input.tag.get_property("REPLACE_OBJECT", config.replace_object); config.draw_object_border = input.tag.get_property("DRAW_OBJECT_BORDER", config.draw_object_border); config.object_layer = input.tag.get_property("OBJECT_LAYER", config.object_layer); config.replace_layer = input.tag.get_property("REPLACE_LAYER", config.replace_layer); config.scene_layer = input.tag.get_property("SCENE_LAYER", config.scene_layer); config.algorithm = input.tag.get_property("ALGORITHM", config.algorithm); config.vmin = input.tag.get_property("VMIN", config.vmin); config.vmax = input.tag.get_property("VMAX", config.vmax); config.smin = input.tag.get_property("SMIN", config.smin); config.blend = input.tag.get_property("BLEND", config.blend); } } } config.boundaries(); } void FindObjectMain::draw_pixel(VFrame *frame, int x, int y) { if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return; #define DRAW_PIXEL(x, y, components, do_yuv, max, type) \ { \ type **rows = (type**)frame->get_rows(); \ rows[y][x * components] = max - rows[y][x * components]; \ if(!do_yuv) \ { \ rows[y][x * components + 1] = max - rows[y][x * components + 1]; \ rows[y][x * components + 2] = max - rows[y][x * components + 2]; \ } \ else \ { \ rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \ rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \ } \ if(components == 4) \ rows[y][x * components + 3] = max; \ } switch(frame->get_color_model()) { case BC_RGB888: DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char); break; case BC_RGBA8888: DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char); break; case BC_RGB_FLOAT: DRAW_PIXEL(x, y, 3, 0, 1.0, float); break; case BC_RGBA_FLOAT: DRAW_PIXEL(x, y, 4, 0, 1.0, float); break; case BC_YUV888: DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char); break; case BC_YUVA8888: DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char); break; case BC_RGB161616: DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t); break; case BC_YUV161616: DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t); break; case BC_RGBA16161616: DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t); break; case BC_YUVA16161616: DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t); break; } } void FindObjectMain::draw_line(VFrame *frame, int x1, int y1, int x2, int y2) { int w = labs(x2 - x1); int h = labs(y2 - y1); //printf("FindObjectMain::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2); if(!w && !h) { draw_pixel(frame, x1, y1); } else if(w > h) { // Flip coordinates so x1 < x2 if(x2 < x1) { y2 ^= y1; y1 ^= y2; y2 ^= y1; x1 ^= x2; x2 ^= x1; x1 ^= x2; } int numerator = y2 - y1; int denominator = x2 - x1; for(int i = x1; i <= x2; i++) { int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator; draw_pixel(frame, i, y); } } else { // Flip coordinates so y1 < y2 if(y2 < y1) { y2 ^= y1; y1 ^= y2; y2 ^= y1; x1 ^= x2; x2 ^= x1; x1 ^= x2; } int numerator = x2 - x1; int denominator = y2 - y1; for(int i = y1; i <= y2; i++) { int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator; draw_pixel(frame, x, i); } } //printf("FindObjectMain::draw_line 2\n"); } void FindObjectMain::draw_rect(VFrame *frame, int x1, int y1, int x2, int y2) { draw_line(frame, x1, y1, x2, y1); draw_line(frame, x2, y1 + 1, x2, y2); draw_line(frame, x2 - 1, y2, x1, y2); draw_line(frame, x1, y2 - 1, x1, y1 + 1); } // Convert to greyscale & crop void FindObjectMain::grey_crop(unsigned char *dst, VFrame *src, int x1, int y1, int x2, int y2, int dst_w, int dst_h) { // Dimensions of dst frame int w = x2 - x1; int h = y2 - y1; bzero(dst, dst_w * dst_h); //printf("FindObjectMain::grey_crop %d %d %d\n", __LINE__, w, h); for(int i = 0; i < h; i++) { #define RGB_TO_VALUE(r, g, b) \ ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y) #define CONVERT(in_type, max, components, is_yuv) \ { \ in_type *input = ((in_type*)src->get_rows()[i + y1]) + x1 * components; \ unsigned char *output = dst + i * dst_w; \ \ for(int j = 0; j < w; j++) \ { \ /* Y channel only */ \ if(is_yuv) \ { \ *output = *input; \ } \ /* RGB */ \ else \ { \ float r = (float)input[0] / max; \ float g = (float)input[1] / max; \ float b = (float)input[2] / max; \ *output = RGB_TO_VALUE(r, g, b); \ } \ \ input += components; \ output++; \ } \ } switch(src->get_color_model()) { case BC_RGB888: { CONVERT(unsigned char, 0xff, 3, 0) break; } case BC_RGBA8888: { CONVERT(unsigned char, 0xff, 4, 0) break; } case BC_RGB_FLOAT: { CONVERT(float, 1.0, 3, 0) break; } case BC_RGBA_FLOAT: { CONVERT(float, 1.0, 4, 0) break; } case BC_YUV888: { CONVERT(unsigned char, 0xff, 3, 1) break; } case BC_YUVA8888: { CONVERT(unsigned char, 0xff, 4, 1) break; } } } } void FindObjectMain::process_surf() { if(!object_image) { // Only does greyscale object_image = cvCreateImage( cvSize(object_image_w, object_image_h), 8, 1); } if(!scene_image) { // Only does greyscale scene_image = cvCreateImage( cvSize(scene_image_w, scene_image_h), 8, 1); } // Select only region with image size // Does this do anything? cvSetImageROI( object_image, cvRect( 0, 0, object_w, object_h ) ); cvSetImageROI( scene_image, cvRect( 0, 0, scene_w, scene_h ) ); if(!prev_object) prev_object = new unsigned char[object_image_w * object_image_h]; memcpy(prev_object, object_image->imageData, object_image_w * object_image_h); grey_crop((unsigned char*)scene_image->imageData, get_input(scene_layer), scene_x1, scene_y1, scene_x2, scene_y2, scene_image_w, scene_image_h); grey_crop((unsigned char*)object_image->imageData, get_input(object_layer), object_x1, object_y1, object_x2, object_y2, object_image_w, object_image_h); if(!storage) storage = cvCreateMemStorage(0); CvSURFParams params = cvSURFParams(500, 1); //printf("FindObjectMain::process_surf %d\n", __LINE__); // Only compute keypoints if the image changed if(memcmp(prev_object, object_image->imageData, object_image_w * object_image_h)) { if(object_keypoints) cvClearSeq(object_keypoints); if(object_descriptors) cvClearSeq(object_descriptors); cvExtractSURF(object_image, 0, &object_keypoints, &object_descriptors, storage, params, 0); } //printf("FindObjectMain::process_surf %d object keypoints=%d\n", __LINE__, object_keypoints->total); // Draw the keypoints // for(int i = 0; i < object_keypoints->total; i++) // { // CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( object_keypoints, i ); // int size = r1->size / 4; // draw_rect(frame[object_layer], // r1->pt.x + object_x1 - size, // r1->pt.y + object_y1 - size, // r1->pt.x + object_x1 + size, // r1->pt.y + object_y1 + size); // } //printf("FindObjectMain::process_surf %d\n", __LINE__); // TODO: make the surf data persistent & check for image changes instead if(scene_keypoints) cvClearSeq(scene_keypoints); if(scene_descriptors) cvClearSeq(scene_descriptors); cvExtractSURF(scene_image, 0, &scene_keypoints, &scene_descriptors, storage, params, 0); // Draw the keypoints // for(int i = 0; i < scene_keypoints->total; i++) // { // CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( scene_keypoints, i ); // int size = r1->size / 4; // draw_rect(frame[scene_layer], // r1->pt.x + scene_x1 - size, // r1->pt.y + scene_y1 - size, // r1->pt.x + scene_x1 + size, // r1->pt.y + scene_y1 + size); // } // printf("FindObjectMain::process_surf %d %d %d scene keypoints=%d\n", // __LINE__, // scene_w, // scene_h, // scene_keypoints->total); int *point_pairs = 0; int total_pairs = 0; CvPoint src_corners[4] = { { 0, 0 }, { object_w, 0 }, { object_w, object_h }, { 0, object_h } }; CvPoint dst_corners[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; //printf("FindObjectMain::process_surf %d\n", __LINE__); if(scene_keypoints->total && object_keypoints->total && locatePlanarObject(object_keypoints, object_descriptors, scene_keypoints, scene_descriptors, src_corners, dst_corners, &point_pairs, &total_pairs)) { // Draw keypoints in the scene & object layer if(config.draw_keypoints) { //printf("FindObjectMain::process_surf %d total pairs=%d\n", __LINE__, total_pairs); for(int i = 0; i < total_pairs; i++) { CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( object_keypoints, point_pairs[i * 2] ); CvSURFPoint* r2 = (CvSURFPoint*)cvGetSeqElem( scene_keypoints, point_pairs[i * 2 + 1] ); int size = r2->size * 1.2 / 9 * 2; draw_rect(get_input(scene_layer), r2->pt.x + scene_x1 - size, r2->pt.y + scene_y1 - size, r2->pt.x + scene_x1 + size, r2->pt.y + scene_y1 + size); draw_rect(get_input(object_layer), r1->pt.x + object_x1 - size, r1->pt.y + object_y1 - size, r1->pt.x + object_x1 + size, r1->pt.y + object_y1 + size); } } //printf("FindObjectMain::process_surf %d\n", __LINE__); // Get object outline in the scene layer border_x1 = dst_corners[0].x + scene_x1; border_y1 = dst_corners[0].y + scene_y1; border_x2 = dst_corners[1].x + scene_x1; border_y2 = dst_corners[1].y + scene_y1; border_x3 = dst_corners[2].x + scene_x1; border_y3 = dst_corners[2].y + scene_y1; border_x4 = dst_corners[3].x + scene_x1; border_y4 = dst_corners[3].y + scene_y1; //printf("FindObjectMain::process_surf %d\n", __LINE__); } //printf("FindObjectMain::process_surf %d\n", __LINE__); // for(int i = 0; i < object_y2 - object_y1; i++) // { // unsigned char *dst = get_input(object_layer)->get_rows()[i]; // unsigned char *src = (unsigned char*)object_image->imageData + i * (object_x2 - object_x1); // for(int j = 0; j < object_x2 - object_x1; j++) // { // *dst++ = *src; // *dst++ = 0x80; // *dst++ = 0x80; // src++; // } // } // Frees the image structures if(point_pairs) free(point_pairs); } void FindObjectMain::process_camshift() { // Some user defined parameters int vmin = config.vmin; int vmax = config.vmax; int smin = config.smin; float hranges[] = { 0, 180 }; const float* phranges = hranges; // Create aligned, RGB images if(!object_image) { object_image = cvCreateImage( cvSize(object_image_w, object_image_h), 8, 3); } if(!scene_image) { scene_image = cvCreateImage( cvSize(scene_image_w, scene_image_h), 8, 3); } // Temporary row pointers unsigned char **object_rows = new unsigned char*[object_image_h]; unsigned char **scene_rows = new unsigned char*[scene_image_h]; for(int i = 0; i < object_image_h; i++) { object_rows[i] = (unsigned char*)(object_image->imageData + i * object_image_w * 3); } for(int i = 0; i < scene_image_h; i++) { scene_rows[i] = (unsigned char*)(scene_image->imageData + i * scene_image_w * 3); } // Transfer object & scene to RGB images for OpenCV if(!prev_object) prev_object = new unsigned char[object_image_w * object_image_h * 3]; // Back up old object image memcpy(prev_object, object_image->imageData, object_image_w * object_image_h * 3); BC_CModels::transfer(object_rows, get_input(object_layer)->get_rows(), 0, 0, 0, 0, 0, 0, object_x1, object_y1, object_w, object_h, 0, 0, object_w, object_h, get_input(object_layer)->get_color_model(), BC_RGB888, 0, 0, 0); BC_CModels::transfer(scene_rows, get_input(scene_layer)->get_rows(), 0, 0, 0, 0, 0, 0, scene_x1, scene_y1, scene_w, scene_h, 0, 0, scene_w, scene_h, get_input(scene_layer)->get_color_model(), BC_RGB888, 0, 0, 0); delete [] object_rows; delete [] scene_rows; // from camshiftdemo.cpp // Compute new object if(memcmp(prev_object, object_image->imageData, object_image_w * object_image_h * 3) || !hist.dims) { Mat image(object_image); Mat hsv, hue, mask; cvtColor(image, hsv, CV_RGB2HSV); int _vmin = vmin, _vmax = vmax; //printf("FindObjectMain::process_camshift %d\n", __LINE__); inRange(hsv, Scalar(0, smin, MIN(_vmin,_vmax)), Scalar(180, 256, MAX(_vmin, _vmax)), mask); int ch[] = { 0, 0 }; hue.create(hsv.size(), hsv.depth()); mixChannels(&hsv, 1, &hue, 1, ch, 1); Rect selection = Rect(0, 0, object_w, object_h); trackWindow = selection; int hsize = 16; Mat roi(hue, selection), maskroi(mask, selection); calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges); normalize(hist, hist, 0, 255, CV_MINMAX); } // compute scene Mat image(scene_image); Mat hsv, hue, mask, backproj; cvtColor(image, hsv, CV_RGB2HSV); int _vmin = vmin, _vmax = vmax; inRange(hsv, Scalar(0, smin, MIN(_vmin,_vmax)), Scalar(180, 256, MAX(_vmin, _vmax)), mask); int ch[] = {0, 0}; hue.create(hsv.size(), hsv.depth()); mixChannels(&hsv, 1, &hue, 1, ch, 1); //printf("FindObjectMain::process_camshift %d %d %d\n", __LINE__, hist.dims, hist.size[1]); RotatedRect trackBox = RotatedRect( Point2f((object_x1 + object_x2) / 2, (object_y1 + object_y2) / 2), Size2f(object_w, object_h), 0); trackWindow = Rect(0, 0, scene_w, scene_h); if(hist.dims > 0) { calcBackProject(&hue, 1, 0, hist, backproj, &phranges); backproj &= mask; //printf("FindObjectMain::process_camshift %d\n", __LINE__); // if(trackWindow.width <= 0 || // trackWindow.height <= 0) // { // trackWindow.width = object_w; // trackWindow.height = object_h; // } trackBox = CamShift(backproj, trackWindow, TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 )); //printf("FindObjectMain::process_camshift %d\n", __LINE__); // if( trackWindow.area() <= 1 ) // { // int cols = backproj.cols; // int rows = backproj.rows; // int r = (MIN(cols, rows) + 5) / 6; // trackWindow = Rect(trackWindow.x - r, trackWindow.y - r, // trackWindow.x + r, trackWindow.y + r) & // Rect(0, 0, cols, rows); // } } // printf("FindObjectMain::process_camshift %d %d %d %d %d\n", // __LINE__, // trackWindow.x, // trackWindow.y, // trackWindow.width, // trackWindow.height); // Draw mask over scene if(config.draw_keypoints) { for(int i = 0; i < scene_h; i++) { switch(get_input(scene_layer)->get_color_model()) { case BC_YUV888: { unsigned char *input = backproj.data + i * scene_image_w; unsigned char *output = get_input(scene_layer)->get_rows()[i + scene_y1] + scene_x1 * 3; for(int j = 0; j < scene_w; j++) { output[0] = *input; output[1] = 0x80; output[2] = 0x80; output += 3; input++; } break; } } } } // Get object outline in the scene layer // printf("FindObjectMain::process_camshift %d %d %d %d %d %d\n", // __LINE__, // (int)trackBox.center.x, // (int)trackBox.center.y, // (int)trackBox.size.width, // (int)trackBox.size.height, // (int)trackBox.angle); double angle = trackBox.angle * 2 * M_PI / 360; double angle1 = atan2(-(double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle; double angle2 = atan2(-(double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle; double angle3 = atan2((double)trackBox.size.height / 2, (double)trackBox.size.width / 2) + angle; double angle4 = atan2((double)trackBox.size.height / 2, -(double)trackBox.size.width / 2) + angle; double radius = sqrt(SQR(trackBox.size.height / 2) + SQR(trackBox.size.width / 2)); border_x1 = (int)(trackBox.center.x + cos(angle1) * radius) + scene_x1; border_y1 = (int)(trackBox.center.y + sin(angle1) * radius) + scene_y1; border_x2 = (int)(trackBox.center.x + cos(angle2) * radius) + scene_x1; border_y2 = (int)(trackBox.center.y + sin(angle2) * radius) + scene_y1; border_x3 = (int)(trackBox.center.x + cos(angle3) * radius) + scene_x1; border_y3 = (int)(trackBox.center.y + sin(angle3) * radius) + scene_y1; border_x4 = (int)(trackBox.center.x + cos(angle4) * radius) + scene_x1; border_y4 = (int)(trackBox.center.y + sin(angle4) * radius) + scene_y1; } #define APPLY_MASK(type, max, components, do_yuv) \ { \ type *output_row = (type*)get_input(scene_layer)->get_rows()[i]; \ unsigned char *mask_row = mask_rows[i]; \ int chroma_offset = (int)(max + 1) / 2; \ \ for(int j = 0; j < scene_w; j++) \ { \ if(components == 4) \ { \ output_row[j * 4 + 3] = output_row[j * 4 + 3] * mask_row[j] / 255; \ } \ else \ { \ output_row[j * 3] = output_row[j * 3] * mask_row[j] / 255; \ output_row[j * 3 + 1] = output_row[j * 3 + 1] * mask_row[j] / 255; \ output_row[j * 3 + 2] = output_row[j * 3 + 2] * mask_row[j] / 255; \ \ if(do_yuv) \ { \ output_row[j * 3 + 1] += chroma_offset * (255 - mask_row[j]) / 255; \ output_row[j * 3 + 2] += chroma_offset * (255 - mask_row[j]) / 255; \ } \ } \ } \ } // blobtrack_sample.cpp void FindObjectMain::process_blob() { if(!blob_initialized) { blob_initialized = 1; blob_param.FGTrainFrames = 5; /* Create FG Detection module: */ blob_param.pFG = cvCreateFGDetectorBase(CV_BG_MODEL_FGD, NULL); /* Create Blob Entrance Detection module: */ blob_param.pBD = cvCreateBlobDetectorCC(); /* Create blob tracker module: */ blob_param.pBT = cvCreateBlobTrackerCCMSPF(); /* Create whole pipline: */ blob_pTracker = cvCreateBlobTrackerAuto1(&blob_param); } /* Process: */ IplImage* pMask = NULL; // Create aligned, RGB images if(!scene_image) { scene_image = cvCreateImage( cvSize(scene_image_w, scene_image_h), 8, 3); } // Temporary row pointers unsigned char **scene_rows = new unsigned char*[scene_image_h]; for(int i = 0; i < scene_image_h; i++) { scene_rows[i] = (unsigned char*)(scene_image->imageData + i * scene_image_w * 3); } BC_CModels::transfer(scene_rows, get_input(scene_layer)->get_rows(), 0, 0, 0, 0, 0, 0, scene_x1, scene_y1, scene_w, scene_h, 0, 0, scene_w, scene_h, get_input(scene_layer)->get_color_model(), BC_RGB888, 0, 0, 0); delete [] scene_rows; blob_pTracker->Process(scene_image, pMask); printf("FindObjectMain::process_blob %d %jd %d\n", __LINE__, get_source_position(), blob_pTracker->GetBlobNum()); #if 0 if(blob_pTracker->GetFGMask()) { IplImage* pFG = blob_pTracker->GetFGMask(); printf("FindObjectMain::process_blob %d %ld\n", __LINE__, get_source_position()); // Temporary row pointers unsigned char **mask_rows = new unsigned char*[scene_image_h]; for(int i = 0; i < scene_image_h; i++) { mask_rows[i] = (unsigned char*)(pFG->imageData + i * scene_image_w); } for(int i = 0; i < scene_image_h; i++) { switch(get_input(scene_layer)->get_color_model()) { case BC_RGB888: APPLY_MASK(unsigned char, 0xff, 3, 0) break; case BC_RGB_FLOAT: APPLY_MASK(float, 1.0, 3, 0) break; case BC_YUV888: APPLY_MASK(unsigned char, 0xff, 3, 1) break; case BC_RGBA8888: APPLY_MASK(unsigned char, 0xff, 4, 0) break; case BC_RGBA_FLOAT: APPLY_MASK(float, 1.0, 4, 0) break; case BC_YUVA8888: APPLY_MASK(unsigned char, 0xff, 4, 1) break; } } delete [] mask_rows; } #endif } int FindObjectMain::process_buffer(VFrame **frame, int64_t start_position, double frame_rate) { int prev_algorithm = config.algorithm; if(load_configuration()) { init_border = 1; } w = frame[0]->get_w(); h = frame[0]->get_h(); //printf("FindObjectMain::process_buffer %d\n", __LINE__); // Get the layer containing the object. object_layer = config.object_layer; // Get the layer to search in. scene_layer = config.scene_layer; // Get the layer with the replacement object replace_layer = config.replace_layer; object_layer = MIN(object_layer, PluginClient::get_total_buffers() - 1); scene_layer = MIN(scene_layer, PluginClient::get_total_buffers() - 1); replace_layer = MIN(replace_layer, PluginClient::get_total_buffers() - 1); // printf("FindObjectMain::process_buffer %d %d %d %d %d %d\n", // __LINE__, // PluginClient::get_total_buffers(), // config.object_layer, // config.scene_layer, // object_layer, // scene_layer); // // Create cropped images // TODO: use oblique corners & affine transform object_w = (int)(config.global_block_w * w / 100); object_h = (int)(config.global_block_h * h / 100); object_x1 = (int)(config.block_x * w / 100 - object_w / 2); object_y1 = (int)(config.block_y * h / 100 - object_h / 2); object_x2 = object_x1 + object_w; object_y2 = object_y1 + object_h; CLAMP(object_x1, 0, frame[0]->get_w() - 1); CLAMP(object_x2, 0, frame[0]->get_w() - 1); CLAMP(object_y1, 0, frame[0]->get_h() - 1); CLAMP(object_y2, 0, frame[0]->get_h() - 1); object_w = object_x2 - object_x1; object_h = object_y2 - object_y1; scene_w = (int)(config.global_range_w * w / 100); scene_h = (int)(config.global_range_h * h / 100); scene_x1 = (int)(config.block_x * w / 100 - scene_w / 2); scene_y1 = (int)(config.block_y * h / 100 - scene_h / 2); scene_x2 = scene_x1 + scene_w; scene_y2 = scene_y1 + scene_h; CLAMP(scene_x1, 0, frame[0]->get_w() - 1); CLAMP(scene_x2, 0, frame[0]->get_w() - 1); CLAMP(scene_y1, 0, frame[0]->get_h() - 1); CLAMP(scene_y2, 0, frame[0]->get_h() - 1); scene_w = scene_x2 - scene_x1; scene_h = scene_y2 - scene_y1; // Get quantized sizes int object_image_w = object_w; int object_image_h = object_h; int scene_image_w = scene_w; int scene_image_h = scene_h; if(object_w % QUANTIZE) object_image_w += QUANTIZE - (object_w % QUANTIZE); if(object_h % QUANTIZE) object_image_h += QUANTIZE - (object_h % QUANTIZE); if(scene_w % QUANTIZE) scene_image_w += QUANTIZE - (scene_w % QUANTIZE); if(scene_h % QUANTIZE) scene_image_h += QUANTIZE - (scene_h % QUANTIZE); if(object_image && (object_image_w != this->object_image_w || object_image_h != this->object_image_h || prev_algorithm != config.algorithm)) { cvReleaseImage(&object_image); object_image = 0; delete [] prev_object; prev_object = 0; } this->object_image_w = object_image_w; this->object_image_h = object_image_h; if(scene_image && (scene_image_w != this->scene_image_w || scene_image_h != this->scene_image_h || prev_algorithm != config.algorithm)) { cvReleaseImage(&scene_image); scene_image = 0; } this->scene_image_w = scene_image_w; this->scene_image_h = scene_image_h; //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); //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); //printf("FindObjectMain::process_buffer %d total_layers=%d\n", __LINE__, get_total_buffers()); // Read in the input frames for(int i = 0; i < PluginClient::get_total_buffers(); i++) { read_frame(frame[i], i, start_position, frame_rate); } // Search for object if(config.algorithm != NO_ALGORITHM && (config.replace_object || config.draw_border || config.draw_keypoints)) { switch(config.algorithm) { #if HAVE_OPENCV_SURF case ALGORITHM_SURF: process_surf(); break; #endif case ALGORITHM_CAMSHIFT: process_camshift(); break; case ALGORITHM_BLOB: process_blob(); break; } if(init_border) { border_x1_accum = border_x1; border_y1_accum = border_y1; border_x2_accum = border_x2; border_y2_accum = border_y2; border_x3_accum = border_x3; border_y3_accum = border_y3; border_x4_accum = border_x4; border_y4_accum = border_y4; init_border = 0; } else { border_x1_accum = (float)border_x1 * config.blend / 100 + border_x1_accum * (100 - config.blend) / 100; border_y1_accum = (float)border_y1 * config.blend / 100 + border_y1_accum * (100 - config.blend) / 100; border_x2_accum = (float)border_x2 * config.blend / 100 + border_x2_accum * (100 - config.blend) / 100; border_y2_accum = (float)border_y2 * config.blend / 100 + border_y2_accum * (100 - config.blend) / 100; border_x3_accum = (float)border_x3 * config.blend / 100 + border_x3_accum * (100 - config.blend) / 100; border_y3_accum = (float)border_y3 * config.blend / 100 + border_y3_accum * (100 - config.blend) / 100; border_x4_accum = (float)border_x4 * config.blend / 100 + border_x4_accum * (100 - config.blend) / 100; border_y4_accum = (float)border_y4 * config.blend / 100 + border_y4_accum * (100 - config.blend) / 100; } // Replace object in the scene layer if(config.replace_object) { // Some trickery to get the affine transform to alpha blend into the output if(!affine) affine = new AffineEngine(get_project_smp() + 1, get_project_smp() + 1); //printf("FindObjectMain::process_surf %d replace_layer=%d\n", __LINE__, replace_layer); if(!temp) temp = new VFrame(w, h, get_input(scene_layer)->get_color_model()); if(!overlayer) overlayer = new OverlayFrame(get_project_smp() + 1); temp->clear_frame(); affine->process(temp, get_input(replace_layer), 0, AffineEngine::PERSPECTIVE, border_x1_accum * 100 / w, border_y1_accum * 100 / h, border_x2_accum * 100 / w, border_y2_accum * 100 / h, border_x3_accum * 100 / w, border_y3_accum * 100 / h, border_x4_accum * 100 / w, border_y4_accum * 100 / h, 1); overlayer->overlay(get_input(scene_layer), temp, 0, 0, w, h, 0, 0, w, h, 1, // 0 - 1 TRANSFER_NORMAL, NEAREST_NEIGHBOR); } if(config.draw_border) { draw_line(get_input(scene_layer), border_x1_accum, border_y1_accum, border_x2_accum, border_y2_accum); draw_line(get_input(scene_layer), border_x2_accum, border_y2_accum, border_x3_accum, border_y3_accum); draw_line(get_input(scene_layer), border_x3_accum, border_y3_accum, border_x4_accum, border_y4_accum); draw_line(get_input(scene_layer), border_x4_accum, border_y4_accum, border_x1_accum, border_y1_accum); } } // Draw object outline in the object layer if(config.draw_object_border) { draw_line(frame[object_layer], object_x1, object_y1, object_x2, object_y1); draw_line(frame[object_layer], object_x2, object_y1, object_x2, object_y2); draw_line(frame[object_layer], object_x2, object_y2, object_x1, object_y2); draw_line(frame[object_layer], object_x1, object_y2, object_x1, object_y1); draw_line(frame[object_layer], scene_x1, scene_y1, scene_x2, scene_y1); draw_line(frame[object_layer], scene_x2, scene_y1, scene_x2, scene_y2); draw_line(frame[object_layer], scene_x2, scene_y2, scene_x1, scene_y2); draw_line(frame[object_layer], scene_x1, scene_y2, scene_x1, scene_y1); } return 0; }