/* * CINELERRA * Copyright (C) 2008 Adam Williams * Copyright (C) 2003-2016 Cinelerra CV contributors * * 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 * */ #include "bcdisplayinfo.h" #include "clip.h" #include "edl.h" #include "fonts.h" #include "edlsession.h" #include "language.h" #include "motion-cv.h" #include "motionwindow-cv.h" #include "mwindow.h" #include "pluginserver.h" MotionCVWindow::MotionCVWindow(MotionCVMain *plugin) : PluginClientWindow(plugin, xS(815), yS(600), xS(815), yS(600), 0) { this->plugin = plugin; } MotionCVWindow::~MotionCVWindow() { } void MotionCVWindow::create_objects() { int xs10 = xS(10), xs20 = xS(20), xs30 = xS(30), xs50 = xS(50), xs120 = xS(120), xs410 = xS(410); int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40), ys50 = yS(50); int x1 = xs10, x = xs10, y = ys10; int x2 = xs410; BC_Title *title; add_subwindow(global = new MotionCVGlobal(plugin, this, x1, y)); add_subwindow(rotate = new MotionCVRotate(plugin, this, x2, y)); y += ys50; add_subwindow(title = new BC_Title(x1, y, _("Translation search radius:\n(W/H Percent of image)"))); add_subwindow(global_range_w = new GlobalRange(plugin, x1 + title->get_w() + xs10, y, &plugin->config.global_range_w)); add_subwindow(global_range_h = new GlobalRange(plugin, x1 + title->get_w() + xs30 + global_range_w->get_w(), y, &plugin->config.global_range_h)); add_subwindow(title = new BC_Title(x2, y, _("Rotation search radius:\n(Degrees)"))); add_subwindow(rotation_range = new RotationRange(plugin, x2 + title->get_w() + xs10, y)); y += ys50; add_subwindow(title = new BC_Title(x1, y, _("Translation block size:\n(W/H Percent of image)"))); add_subwindow(global_block_w = new BlockSize(plugin, x1 + title->get_w() + xs10, y, &plugin->config.global_block_w)); add_subwindow(global_block_h = new BlockSize(plugin, x1 + title->get_w() + xs30 + global_block_w->get_w(), y, &plugin->config.global_block_h)); add_subwindow(title = new BC_Title(x2, y, _("Rotation block size:\n(W/H Percent of image)"))); add_subwindow(rotation_block_w = new BlockSize(plugin, x2 + title->get_w() + xs10, y, &plugin->config.rotation_block_w)); add_subwindow(rotation_block_h = new BlockSize(plugin, x2 + title->get_w() + xs30 + rotation_block_w->get_w(), y, &plugin->config.rotation_block_h)); y += ys50; add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:"))); add_subwindow(global_search_positions = new GlobalSearchPositions(plugin, x1 + title->get_w() + xs10, y, xs120)); global_search_positions->create_objects(); add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:"))); add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin, x2 + title->get_w() + xs10, y, xs120)); rotation_search_positions->create_objects(); y += ys50; add_subwindow(title = new BC_Title(x, y, _("Translation direction:"))); add_subwindow(mode3 = new Mode3(plugin, this, x + title->get_w() + xs10, y)); mode3->create_objects(); y += ys40; int y1 = y; add_subwindow(title = new BC_Title(x2, y, _("Tracking file:"))); add_subwindow(tracking_file = new MotionCVTrackingFile(plugin, plugin->config. tracking_file, this, x2 + title->get_w() + xs20, y)); y1 += tracking_file->get_h() + ys10; add_subwindow(title = new BC_Title(x, y + xs10, _("Block X:"))); add_subwindow(block_x = new MotionCVBlockX(plugin, this, x + title->get_w() + xs10, y)); add_subwindow(block_x_text = new MotionCVBlockXText(plugin, this, x + title->get_w() + xs10 + block_x->get_w() + xs10, y + ys10)); y += ys40; add_subwindow(title = new BC_Title(x, y + ys10, _("Block Y:"))); add_subwindow(block_y = new MotionCVBlockY(plugin, this, x + title->get_w() + xs10, y)); add_subwindow(block_y_text = new MotionCVBlockYText(plugin, this, x + title->get_w() + xs10 + block_y->get_w() + xs10, y + ys10)); add_subwindow(title = new BC_Title(x2, y1 + ys10, _("Maximum absolute offset:"))); add_subwindow(magnitude = new MotionCVMagnitude(plugin, x2 + title->get_w() + xs10, y1)); y1 += ys40; add_subwindow(title = new BC_Title(x2, y1 + ys10, _("Settling speed:"))); add_subwindow(return_speed = new MotionCVReturnSpeed(plugin, x2 + title->get_w() + xs10, y1)); y1 += ys40; add_subwindow(vectors = new MotionCVDrawVectors(plugin, this, x2, y1)); y = y1 + vectors->get_h() + ys10; x1 = x; y1 = y; add_subwindow(track_single = new TrackSingleFrame(plugin, this, x1, y1)); y += ys20; add_subwindow(track_previous = new TrackPreviousFrame(plugin, this, x, y)); y += ys20; add_subwindow(previous_same = new PreviousFrameSameBlock(plugin, this, x, y)); y += ys40; add_subwindow(title = new BC_Title(x, y, _("Master layer:"))); add_subwindow(master_layer = new MasterLayer(plugin, this, x + title->get_w() + xs10, y)); master_layer->create_objects(); add_subwindow(title = new BC_Title(x1=x2, y1=y, _("Frame number:"))); add_subwindow(track_frame_number = new TrackFrameNumber(plugin, this, x1 += title->get_w(), y1)); if( plugin->config.mode3 != MotionCVConfig::TRACK_SINGLE ) track_frame_number->disable(); add_subwindow(addtrackedframeoffset = new AddTrackedFrameOffset(plugin, this, x1=x2, y1+=track_frame_number->get_h())); int pef = client->server->mwindow->edl->session->video_every_frame; add_subwindow(pef_title = new BC_Title(x1=x2+xs50, y1+=addtrackedframeoffset->get_h() + yS(5), !pef ? _("For best results\n" " Set: Play every frame\n" " Preferences-> Playback-> Video Out") : _("Currently using: Play every frame"), MEDIUMFONT, !pef ? RED : GREEN)); y += ys30; add_subwindow(title = new BC_Title(x, y, _("Action:"))); add_subwindow(mode1 = new Mode1(plugin, this, x + title->get_w() + xs10, y)); mode1->create_objects(); y += ys30; add_subwindow(title = new BC_Title(x, y, _("Calculation:"))); add_subwindow(mode2 = new Mode2(plugin, this, x + title->get_w() + xs10, y)); mode2->create_objects(); show_window(1); } void MotionCVWindow::update_mode() { global_range_w->update(plugin->config.global_range_w, MIN_RADIUS, MAX_RADIUS); global_range_h->update(plugin->config.global_range_h, MIN_RADIUS, MAX_RADIUS); rotation_range->update(plugin->config.rotation_range, MIN_ROTATION, MAX_ROTATION); vectors->update(plugin->config.draw_vectors); tracking_file->update(plugin->config.tracking_file); global->update(plugin->config.global); rotate->update(plugin->config.rotate); addtrackedframeoffset->update(plugin->config.addtrackedframeoffset); } GlobalRange::GlobalRange(MotionCVMain *plugin, int x, int y, int *value) :BC_IPot(x, y, (int64_t) * value, (int64_t) MIN_RADIUS, (int64_t) MAX_RADIUS) { this->plugin = plugin; this->value = value; } int GlobalRange::handle_event() { *value = (int)get_value(); plugin->send_configure_change(); return 1; } RotationRange::RotationRange(MotionCVMain *plugin, int x, int y) : BC_IPot(x, y, (int64_t) plugin->config.rotation_range, (int64_t) MIN_ROTATION, (int64_t) MAX_ROTATION) { this->plugin = plugin; } int RotationRange::handle_event() { plugin->config.rotation_range = (int)get_value(); plugin->send_configure_change(); return 1; } BlockSize::BlockSize(MotionCVMain *plugin, int x, int y, int *value) : BC_IPot(x, y, (int64_t) * value, (int64_t) MIN_BLOCK, (int64_t) MAX_BLOCK) { this->plugin = plugin; this->value = value; } int BlockSize::handle_event() { *value = (int)get_value(); plugin->send_configure_change(); return 1; } GlobalSearchPositions::GlobalSearchPositions(MotionCVMain *plugin, int x, int y, int w) : BC_PopupMenu(x, y, w, "", 1) { this->plugin = plugin; } void GlobalSearchPositions::create_objects() { add_item(new BC_MenuItem("64")); add_item(new BC_MenuItem("128")); add_item(new BC_MenuItem("256")); add_item(new BC_MenuItem("512")); add_item(new BC_MenuItem("1024")); add_item(new BC_MenuItem("2048")); add_item(new BC_MenuItem("4096")); add_item(new BC_MenuItem("8192")); add_item(new BC_MenuItem("16384")); add_item(new BC_MenuItem("32768")); add_item(new BC_MenuItem("65536")); add_item(new BC_MenuItem("131072")); char string[BCTEXTLEN]; sprintf(string, "%d", plugin->config.global_positions); set_text(string); } int GlobalSearchPositions::handle_event() { plugin->config.global_positions = atoi(get_text()); plugin->send_configure_change(); return 1; } RotationSearchPositions::RotationSearchPositions(MotionCVMain *plugin, int x, int y, int w) : BC_PopupMenu(x, y, w, "", 1) { this->plugin = plugin; } void RotationSearchPositions::create_objects() { add_item(new BC_MenuItem("4")); add_item(new BC_MenuItem("8")); add_item(new BC_MenuItem("16")); add_item(new BC_MenuItem("32")); char string[BCTEXTLEN]; sprintf(string, "%d", plugin->config.rotate_positions); set_text(string); } int RotationSearchPositions::handle_event() { plugin->config.rotate_positions = atoi(get_text()); plugin->send_configure_change(); return 1; } MotionCVMagnitude::MotionCVMagnitude(MotionCVMain *plugin, int x, int y) : BC_IPot(x, y, (int64_t) plugin->config.magnitude, (int64_t) 0, (int64_t) 100) { this->plugin = plugin; } int MotionCVMagnitude::handle_event() { plugin->config.magnitude = (int)get_value(); plugin->send_configure_change(); return 1; } MotionCVReturnSpeed::MotionCVReturnSpeed(MotionCVMain *plugin, int x, int y) : BC_IPot(x, y, (int64_t) plugin->config.return_speed, (int64_t) 0, (int64_t) 100) { this->plugin = plugin; } int MotionCVReturnSpeed::handle_event() { plugin->config.return_speed = (int)get_value(); plugin->send_configure_change(); return 1; } AddTrackedFrameOffset::AddTrackedFrameOffset(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_CheckBox(x, y, plugin->config.addtrackedframeoffset, _("Add (loaded) offset from tracked frame")) { this->plugin = plugin; this->gui = gui; } int AddTrackedFrameOffset::handle_event() { plugin->config.addtrackedframeoffset = get_value(); plugin->send_configure_change(); return 1; } MotionCVTrackingFile::MotionCVTrackingFile(MotionCVMain *plugin, const char *filename, MotionCVWindow *gui, int x, int y) : BC_TextBox(x, y, xS(250), 1, filename) { this->plugin = plugin; this->gui = gui; }; int MotionCVTrackingFile::handle_event() { strcpy(plugin->config.tracking_file, get_text()); plugin->send_configure_change(); return 1; } MotionCVGlobal::MotionCVGlobal(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) :BC_CheckBox(x, y, plugin->config.global, _("Track translation")) { this->plugin = plugin; this->gui = gui; } int MotionCVGlobal::handle_event() { plugin->config.global = get_value(); plugin->send_configure_change(); return 1; } MotionCVRotate::MotionCVRotate(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_CheckBox(x, y, plugin->config.rotate, _("Track rotation")) { this->plugin = plugin; this->gui = gui; } int MotionCVRotate::handle_event() { plugin->config.rotate = get_value(); plugin->send_configure_change(); return 1; } MotionCVBlockX::MotionCVBlockX(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_FPot(x, y, plugin->config.block_x, (float)0, (float)100) { this->plugin = plugin; this->gui = gui; } int MotionCVBlockX::handle_event() { plugin->config.block_x = get_value(); gui->block_x_text->update((float)plugin->config.block_x); plugin->send_configure_change(); return 1; } MotionCVBlockY::MotionCVBlockY(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_FPot(x, y, (float)plugin->config.block_y, (float)0, (float)100) { this->plugin = plugin; this->gui = gui; } int MotionCVBlockY::handle_event() { plugin->config.block_y = get_value(); gui->block_y_text->update((float)plugin->config.block_y); plugin->send_configure_change(); return 1; } MotionCVBlockXText::MotionCVBlockXText(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_TextBox(x, y, xS(75), 1, (float)plugin->config.block_x) { this->plugin = plugin; this->gui = gui; set_precision(4); } int MotionCVBlockXText::handle_event() { plugin->config.block_x = atof(get_text()); gui->block_x->update(plugin->config.block_x); plugin->send_configure_change(); return 1; } MotionCVBlockYText::MotionCVBlockYText(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_TextBox(x, y, xS(75), 1, (float)plugin->config.block_y) { this->plugin = plugin; this->gui = gui; set_precision(4); } int MotionCVBlockYText::handle_event() { plugin->config.block_y = atof(get_text()); gui->block_y->update(plugin->config.block_y); plugin->send_configure_change(); return 1; } MotionCVDrawVectors::MotionCVDrawVectors(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_CheckBox(x, y, plugin->config.draw_vectors, _("Draw vectors")) { this->gui = gui; this->plugin = plugin; } int MotionCVDrawVectors::handle_event() { plugin->config.draw_vectors = get_value(); plugin->send_configure_change(); return 1; } TrackSingleFrame::TrackSingleFrame(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_Radial(x, y, plugin->config.mode3 == MotionCVConfig::TRACK_SINGLE, _("Track single frame")) { this->plugin = plugin; this->gui = gui; } int TrackSingleFrame::handle_event() { plugin->config.mode3 = MotionCVConfig::TRACK_SINGLE; gui->track_previous->update(0); gui->previous_same->update(0); gui->track_frame_number->enable(); plugin->send_configure_change(); return 1; } TrackFrameNumber::TrackFrameNumber(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_TextBox(x, y, xS(100), 1, plugin->config.track_frame) { this->plugin = plugin; this->gui = gui; } int TrackFrameNumber::handle_event() { plugin->config.track_frame = atol(get_text()); plugin->send_configure_change(); return 1; } TrackPreviousFrame::TrackPreviousFrame(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_Radial(x, y, plugin->config.mode3 == MotionCVConfig::TRACK_PREVIOUS, _("Track previous frame")) { this->plugin = plugin; this->gui = gui; } int TrackPreviousFrame::handle_event() { plugin->config.mode3 = MotionCVConfig::TRACK_PREVIOUS; gui->track_single->update(0); gui->previous_same->update(0); gui->track_frame_number->disable(); plugin->send_configure_change(); return 1; } PreviousFrameSameBlock::PreviousFrameSameBlock(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_Radial(x, y, plugin->config.mode3 == MotionCVConfig::PREVIOUS_SAME_BLOCK, _("Previous frame same block")) { this->plugin = plugin; this->gui = gui; } int PreviousFrameSameBlock::handle_event() { plugin->config.mode3 = MotionCVConfig::PREVIOUS_SAME_BLOCK; gui->track_single->update(0); gui->track_previous->update(0); gui->track_frame_number->disable(); plugin->send_configure_change(); return 1; } MasterLayer::MasterLayer(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_PopupMenu(x, y, calculate_w(gui), to_text(plugin->config.bottom_is_master)) { this->plugin = plugin; this->gui = gui; } int MasterLayer::handle_event() { plugin->config.bottom_is_master = from_text(get_text()); plugin->send_configure_change(); return 1; } void MasterLayer::create_objects() { add_item(new BC_MenuItem(to_text(0))); add_item(new BC_MenuItem(to_text(1))); } int MasterLayer::from_text(char *text) { if( !strcmp(text, _("Top")) ) return 0; return 1; } const char *MasterLayer::to_text(int mode) { return mode ? _("Bottom") : _("Top"); } int MasterLayer::calculate_w(MotionCVWindow *gui) { int result = 0; result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1))); return result + xS(80); } Mode1::Mode1(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_PopupMenu(x, y, calculate_w(gui), to_text(plugin->config.mode1)) { this->plugin = plugin; this->gui = gui; } int Mode1::handle_event() { plugin->config.mode1 = from_text(get_text()); plugin->send_configure_change(); return 1; } void Mode1::create_objects() { add_item(new BC_MenuItem(to_text(MotionCVConfig::TRACK))); add_item(new BC_MenuItem(to_text(MotionCVConfig::TRACK_PIXEL))); add_item(new BC_MenuItem(to_text(MotionCVConfig::STABILIZE))); add_item(new BC_MenuItem(to_text(MotionCVConfig::STABILIZE_PIXEL))); add_item(new BC_MenuItem(to_text(MotionCVConfig::NOTHING))); } int Mode1::from_text(char *text) { if( !strcmp(text, _("Track Subpixel")) ) return MotionCVConfig::TRACK; if( !strcmp(text, _("Track Pixel")) ) return MotionCVConfig::TRACK_PIXEL; if( !strcmp(text, _("Stabilize Subpixel")) ) return MotionCVConfig::STABILIZE; if( !strcmp(text, _("Stabilize Pixel")) ) return MotionCVConfig::STABILIZE_PIXEL; //if( !strcmp(text, _("Do Nothing")) ) return MotionCVConfig::NOTHING; return MotionCVConfig::NOTHING; } const char *Mode1::to_text(int mode) { switch( mode ) { case MotionCVConfig::TRACK: return _("Track Subpixel"); case MotionCVConfig::TRACK_PIXEL: return _("Track Pixel"); case MotionCVConfig::STABILIZE: return _("Stabilize Subpixel"); case MotionCVConfig::STABILIZE_PIXEL: return _("Stabilize Pixel"); case MotionCVConfig::NOTHING: return _("Do Nothing"); } return ""; } int Mode1::calculate_w(MotionCVWindow *gui) { int result = 0; result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::TRACK))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::TRACK_PIXEL))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::STABILIZE))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::STABILIZE_PIXEL))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::NOTHING))); return result + xS(80); } Mode2::Mode2(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_PopupMenu(x, y, calculate_w(gui), to_text(plugin->config.mode2)) { this->plugin = plugin; this->gui = gui; } int Mode2::handle_event() { plugin->config.mode2 = from_text(get_text()); plugin->send_configure_change(); return 1; } void Mode2::create_objects() { add_item(new BC_MenuItem(to_text(MotionCVConfig::SAVE))); add_item(new BC_MenuItem(to_text(MotionCVConfig::LOAD))); add_item(new BC_MenuItem(to_text(MotionCVConfig::RECALCULATE))); add_item(new BC_MenuItem(to_text(MotionCVConfig::NO_CALCULATE))); } int Mode2::from_text(char *text) { if( !strcmp(text, _("Recalculate")) ) return MotionCVConfig::RECALCULATE; if( !strcmp(text, _("Save coords to tracking file")) ) return MotionCVConfig::SAVE; if( !strcmp(text, _("Load coords from tracking file")) ) return MotionCVConfig::LOAD; //if( !strcmp(text, _("Don't Calculate")) ) return MotionCVConfig::NO_CALCULATE; return MotionCVConfig::NO_CALCULATE; } const char *Mode2::to_text(int mode) { switch( mode ) { case MotionCVConfig::NO_CALCULATE: return _("Don't Calculate"); case MotionCVConfig::RECALCULATE: return _("Recalculate"); case MotionCVConfig::SAVE: return _("Save coords to tracking file"); case MotionCVConfig::LOAD: return _("Load coords from tracking file"); } return ""; } int Mode2::calculate_w(MotionCVWindow *gui) { int result = 0; result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::NO_CALCULATE))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::RECALCULATE))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::SAVE))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::LOAD))); return result + xS(80); } Mode3::Mode3(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y) : BC_PopupMenu(x, y, calculate_w(gui), to_text(plugin->config.horizontal_only, plugin->config.vertical_only)) { this->plugin = plugin; this->gui = gui; } int Mode3::handle_event() { from_text(&plugin->config.horizontal_only, &plugin->config.vertical_only, get_text()); plugin->send_configure_change(); return 1; } void Mode3::create_objects() { add_item(new BC_MenuItem(to_text(1, 0))); add_item(new BC_MenuItem(to_text(0, 1))); add_item(new BC_MenuItem(to_text(0, 0))); } void Mode3::from_text(int *horizontal_only, int *vertical_only, char *text) { *horizontal_only = 0; *vertical_only = 0; if( !strcmp(text, to_text(1, 0)) ) *horizontal_only = 1; if( !strcmp(text, to_text(0, 1)) ) *vertical_only = 1; } const char *Mode3::to_text(int horizontal_only, int vertical_only) { if( horizontal_only ) return _("Horizontal only"); if( vertical_only ) return _("Vertical only"); return _("Both"); } int Mode3::calculate_w(MotionCVWindow *gui) { int result = 0; result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1, 0))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 1))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 0))); return result + xS(80); }