-
Tristan Walter authored
* fix continuous refresh
Tristan Walter authored* fix continuous refresh
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Timeline.cpp 33.18 KiB
#include "Timeline.h"
#include <gui/DrawCVBase.h>
#include <gui/gui.h>
#include <file/CSVExport.h>
#include <gui/HttpGui.h>
#include <processing/PadImage.h>
#include <tracking/FOI.h>
#include <misc/ReverseAdapter.h>
#include <tracking/Recognition.h>
#include <tracking/DatasetQuality.h>
namespace gui {
const float bar_height = 30;
static Timeline* _instance = nullptr;
std::tuple<Vec2, float> Timeline::timeline_offsets() {
//const float max_w = Tracker::average().cols;
const float max_w = _instance && !_instance->_terminate && GUI::instance() && GUI::instance()->best_base() ? GUI::instance()->best_base()->window_dimensions().width * gui::interface_scale() : Tracker::average().cols;
Vec2 offset(0);
return {offset, max_w};
}
Timeline::Timeline(GUI& gui, FrameInfo& info)
: _bar(nullptr),
tracker_endframe(-1), tracker_startframe(-1),
tdelta(0),
_gui(gui),
_tracker(*Tracker::instance()),
_frame_info(info),
_visible(true),
_mOverFrame(-1),
_title_layout({}, Vec2(20, 20), Bounds(0, 0, 17, 0)),
_status_text("", Vec2(), White, 0.8),
_status_text2("", Vec2(), White, 0.8),
_status_text3("", Vec2(), White, 0.8),
_raw_text("[RAW]", Vec2(), Black, Font(0.8, Style::Bold)),
_auto_text("", Vec2(), Black, Font(0.8, Style::Bold)),
_pause("pause", Size2(100,27))
{
_instance = this;
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
//if(_proximity_bar.image.empty())
// _proximity_bar.image.create(cv::Mat::zeros(20, 20, CV_8UC4));
_status_text.set_clickable(true);
_status_text.on_hover([](auto e) {
if(!GUI::instance())
return;
if(e.hover.hovered) {
GUI::instance()->set_info_visible(true);
} else
GUI::instance()->set_info_visible(false);
});
_status_text2.on_click([this](auto){
SETTING(gui_frame) = _frame_info.global_segment_order.empty() ? 0 : _frame_info.global_segment_order.front().start;
});
_status_text2.on_hover([this](auto){
_status_text2.set_dirty();
});
_status_text2.set_clickable(true);
_pause.on_click([](auto) {
Tracker::analysis_state((Tracker::AnalysisState)!SETTING(analysis_paused));
});
_update_events_thread = std::make_shared<std::thread>([this](){
set_thread_name("Timeline::update_thread");
this->update_thread();
});
}
/*void Timeline::update_border() {
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
_recognition_image.set_source(Image());
}*/
void Timeline::update_consecs(float max_w, const Range<long_t>& consec, const std::vector<Rangel>& other_consec, float scale) {
if(!_bar)
return;
static Range<long_t> previous_consec(-1, -1);
static std::vector<Rangel> previous_other_consec = {};
static float previous_scale = 0;
if(scale < 1)
scale = 1;
float new_height = roundf(bar_height) + 5 * scale;
if(consec == previous_consec
&& other_consec == previous_other_consec
&& scale == previous_scale
&& _consecutives && _bar
&& _bar->source()->cols == _consecutives->source()->cols
&& _consecutives->source()->rows == uint(new_height))
return;
previous_consec = consec;
previous_other_consec = other_consec;
previous_scale = scale;
const uchar alpha = 255 - GUI_SETTINGS(gui_background_color).a;
if(!_consecutives
|| _bar->source()->cols != _consecutives->source()->cols
|| _consecutives->source()->rows != new_height)
{
auto image = std::make_unique<Image>(new_height, _bar->source()->cols, 4);
if(!_consecutives)
_consecutives = std::make_unique<ExternalImage>(std::move(image), Vec2());
else
_consecutives->update_with(*image);
}
std::fill(_consecutives->source()->data(), _consecutives->source()->data() + _consecutives->source()->size(), 0);
auto mat = _consecutives->source()->get();
auto offset = Vec2(0,5) * scale;
if(!consec.empty()) {
//Size2(max_w * percent / use_scale.x, bar_height);
auto position = offset + Vec2(max_w * consec.start / float(_frame_info.video_length), 0);
auto size = Size2(max_w * (consec.end - consec.start) / float(_frame_info.video_length), bar_height);
std::deque<Color> colors {
Green,
Yellow,
Color(255,128,57,255),
Gray
};
cv::rectangle(mat, position - Vec2(1), position - Vec2(1) + size + Size2(2), colors.front().alpha(50), cv::FILLED);
cv::rectangle(mat, position - Vec2(1), position - Vec2(1) + size + Size2(2), Color(alpha, alpha, alpha, 255));
//base.rect(Bounds(position - Vec2(1), size + Size2(2)), colors.front().alpha(50), Color(alpha, alpha, alpha, 255));
colors.pop_front();
for(auto &consec : other_consec) {
position = offset + Vec2(max_w * consec.start / float(_frame_info.video_length), 0);
size = Size2(max_w * (consec.end - consec.start) / float(_frame_info.video_length), bar_height);
cv::rectangle(mat, position - Vec2(1), position - Vec2(1) + size + Size2(2), colors.front().alpha(50), cv::FILLED);
cv::rectangle(mat, position - Vec2(1), position - Vec2(1) + size + Size2(2), Color(alpha, alpha, alpha, 255));
colors.pop_front();
}
}
//base.line(pos - Vec2(0,1), pos + Vec2(max_w * tracker_endframe / float(_frame_info.video_length), 0) - Vec2(0,1), 1, Red.alpha(255));
for(auto &consec : _frame_info.consecutive) {
if( consec.length() > 2 && consec.length() >= consec.length() * 0.25) {
auto position = offset + Vec2(max_w * consec.start / float(_frame_info.video_length), 0);
auto size = Size2(max_w * consec.length() / float(_frame_info.video_length), bar_height);
--position.y;
cv::line(mat, position, position + Vec2(size.width, 0), Green.alpha(alpha));
cv::line(mat, position, position + Vec2(0, -5 * scale), Green.alpha(alpha), scale);
}
}
if(!_frame_info.training_ranges.empty()) {
for(auto range : _frame_info.training_ranges) {
auto position = offset + Vec2(max_w * range.start / float(_frame_info.video_length), 0);
auto size = Size2(max_w * range.length() / float(_frame_info.video_length), bar_height);
cv::rectangle(mat, position - Vec2(1), position - Vec2(1, 0) + size + Size2(2), Red.alpha(50), cv::FILLED);
cv::rectangle(mat, position - Vec2(1), position - Vec2(1, 0) + size + Size2(2), Color(alpha, alpha, alpha, 255));
}
}
}
void Timeline::draw(gui::DrawStructure &base) {
gui::DrawStructure::SectionGuard section(base, "timeline");
const Vec2 use_scale = base.scale().reciprocal();
auto && [offset, max_w] = timeline_offsets();
const float y = 55;
section._section->set_scale(use_scale);
if(FAST_SETTINGS(analysis_paused)) {
_pause.set_txt("continue");
_pause.set_fill_clr(Color(25,75,25,200));
}
else {
_pause.set_txt("pause");
_pause.set_fill_clr(Color(75,25,25,200));
}
std::stringstream number;
number << _frame_info.frameIndex << "/" << _frame_info.video_length << ", " << _frame_info.big_count << " tracks";
if(_frame_info.small_count)
number << " (" << _frame_info.small_count << " short)";
if(_frame_info.up_to_this_frame != _frame_info.big_count)
number << ", " << _frame_info.up_to_this_frame << " known here";
if(_frame_info.current_count != FAST_SETTINGS(track_max_individuals))
number << " " << _frame_info.current_count << " this frame";
if(!FAST_SETTINGS(analysis_paused))
number << " (analysis: " << _frame_info.current_fps << " fps)";
else
number << " (analysis paused)";
DurationUS duration{uint64_t((double(_frame_info.frameIndex.load()) / double(FAST_SETTINGS(frame_rate)))) * 1000u * 1000u};
number << " " << Meta::toStr(duration);
_status_text.set_txt(number.str());
number.str("");
auto consec = _frame_info.global_segment_order.empty() ? Rangel(-1,-1) : _frame_info.global_segment_order.front();
std::vector<Rangel> other_consec;
if(_frame_info.global_segment_order.size() > 1) {
for (int i=0; i<3 && i+1 < (int)_frame_info.global_segment_order.size(); ++i) {
other_consec.push_back(_frame_info.global_segment_order.at(i+1));
}
}
number << "consec: " << consec.start << "-" << consec.end << " (" << consec.end - consec.start << ")";
Color consec_color = White;
if(consec.contains(_frame_info.frameIndex))
consec_color = Green;
if(_status_text2.hovered())
consec_color = consec_color.brightenHSL(0.9);
_status_text2.set_color(consec_color);
_status_text2.set_txt(number.str());
number.str("");
number << "delta: " << _frame_info.tdelta << "s";
//number << ", " << tracker_endframe << ")";
//number << " tdelta:" << std::fixed << std::setprecision(3) << tdelta << " " << std::fixed << std::setprecision(3) << _frame_info.tdelta_gui;
number << NetworkStats::status();
auto status = EventAnalysis::status();
if(!status.empty())
number << " " << status;
//number << " midline-err/frame:" << Tracker::instance()->midline_errors_frame();
_title_layout.set_pos(Vec2(20, 28) - offset);
_title_layout.set_origin(Vec2(0, 0.5));
_status_text3.set_txt(number.str());
_title_layout.set_policy(HorizontalLayout::Policy::CENTER);
std::vector<Layout::Ptr> in_layout{&_pause, &_status_text, &_status_text2, &_status_text3};
if(_frame_info.video_length == tracker_endframe) {
in_layout.erase(in_layout.begin());
}
if(GUI_SETTINGS(gui_mode) == mode_t::blobs && _bar) {
base.rect(-offset, Size2(max_w, bar_height + y), Red.alpha(75));
in_layout.insert(in_layout.begin(), &_raw_text);
}
if(GUI_SETTINGS(auto_train)) {
base.rect(-offset, Size2(max_w, bar_height + y), Red.alpha(75));
_auto_text.set_txt("[auto_train]");
in_layout.insert(in_layout.begin(), &_auto_text);
} else if(GUI_SETTINGS(auto_apply)) {
base.rect(-offset, Size2(max_w, bar_height + y), Red.alpha(75));
_auto_text.set_txt("[auto_apply]");
in_layout.insert(in_layout.begin(), &_auto_text);
} else if(GUI_SETTINGS(auto_quit)) {
base.rect(-offset, Size2(max_w, bar_height + y), Red.alpha(75));
_auto_text.set_txt("[auto_quit]");
in_layout.insert(in_layout.begin(), &_auto_text);
}
_title_layout.set_children(in_layout);
base.wrap_object(_title_layout);
pos = Vec2(0, y) - offset;
gui::Color red_bar_clr(250, 250, 250, _bar && _bar->hovered() ? 180 : 150);
base.rect(pos, Vec2(max_w, bar_height), White.alpha(125));
float percent = float(tracker_endframe) / _frame_info.video_length;
base.rect(pos, Size2(max_w * percent, bar_height), red_bar_clr);
if(_bar && use_scale.y > 0) {
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
float new_height = roundf(bar_height);
_bar->set_scale(Vec2(1, new_height));
_bar->set_color(White.alpha(150));
_bar->set_pos(pos);
base.wrap_object(*_bar);
if(FAST_SETTINGS(recognition_enable)) {
update_consecs(max_w, consec, other_consec, use_scale.y * 0.75);
if(_consecutives) {
_consecutives->set_pos(pos - Vec2(0,5) * max(1, use_scale.y * 0.75));
base.wrap_object(*_consecutives);
}
}
base.add_object(new Text(Meta::toStr(tracker_endframe.load()), pos + Vec2(max_w * tracker_endframe / float(_frame_info.video_length) + 5, bar_height * 0.5), Black, Font(0.5), Vec2(1), Vec2(0,0.5)));
// display hover sign with frame number
if(_mOverFrame != -1) {
//auto it = _proximity_bar.changed_frames.find(_mOverFrame);
//if(it != _proximity_bar.changed_frames.end() || _mOverFrame >= _proximity_bar.end)
{
std::string t = "Frame "+std::to_string(_mOverFrame);
auto dims = Base::text_dimensions(t, &_title_layout, Font(0.7));
Vec2 pp(max_w / float(_frame_info.video_length) * _mOverFrame, _bar->pos().y + _bar->global_bounds().height / use_scale.y + dims.height * 0.5 + 2);
if(pp.x < dims.width * 0.5)
pp.x = dims.width * 0.5;
if(pp.x + dims.width * 0.5 > max_w)
pp.x = max_w - dims.width * 0.5;
pp -= offset;
base.rect(pp - dims * 0.5 - Vec2(5, 2), dims + Vec2(10, 4), Black.alpha(125));
base.text(t, pp, gui::White, Font(0.7, Align::Center));
}
}
}
if(_frame_info.analysis_range.start != 0) {
auto start_pos = pos;
auto end_pos = Vec2(max_w / float(_frame_info.video_length) * _frame_info.analysis_range.start, bar_height);
base.rect(start_pos, end_pos, Gray);
}
if(_frame_info.analysis_range.end < _frame_info.video_length-1) {
auto start_pos = pos + Vec2(max_w / float(_frame_info.video_length) * _frame_info.analysis_range.end, 0);
auto end_pos = Vec2(max_w, bar_height);
base.rect(start_pos, end_pos, Gray);
}
// current position indicator
auto current_pos = Vec2(max_w / float(_frame_info.video_length) * _frame_info.frameIndex, y) - offset;
base.rect(current_pos - Vec2(2),
Size2(5,bar_height + 4),
Black.alpha(255), White.alpha(255));
//base.rect(current_pos - Vec2(2, 1), Vec2(5, 2), DarkCyan, Black);
//base.rect(current_pos + Vec2(-2, bar_height + 3), Vec2(5, 2), DarkCyan, Black);
}
void Timeline::update_fois() {
static Timing timing("update_fois", 10);
TakeTiming take(timing);
const Vec2 use_scale = _bar ? _bar->stage_scale() : Vec2(1);
auto && [offset, max_w] = timeline_offsets();
//const float max_h = Tracker::average().rows;
uint64_t last_change = FOI::last_change();
auto name = SETTING(gui_foi_name).value<std::string>();
if(last_change != _foi_state.last_change || name != _foi_state.name) {
_foi_state.name = name;
if(!_foi_state.name.empty()) {
long_t id = FOI::to_id(_foi_state.name);
if(id != -1) {
_foi_state.changed_frames = FOI::foi(id);//_tracker.changed_frames();
_foi_state.color = FOI::color(_foi_state.name);
}
}
_foi_state.last_change = last_change;
}
//if(_proximity_bar.image.rows && _proximity_bar.image.cols) {
if(_bar == NULL) {
_bar = std::make_unique<ExternalImage>(std::make_unique<Image>(), pos);
_bar->set_clickable(true);
_bar->on_hover([this](Event e) {
if(!GUI::instance())
return;
auto && [offset_, max_w_] = timeline_offsets();
//if(!_proximity_bar.changed_frames.empty())
{
float distance2frame = FLT_MAX;
long_t framemOver = -1;
if(_bar && _bar->hovered()) {
//Vec2 pp(max_w / float(_frame_info.video_length) * idx.first, 50);
//float dis = abs(e.hover.x - pp.x);
static Timing timing("Scrubbing", 0.01);
long_t idx = roundf(e.hover.x / max_w_ * float(_frame_info.video_length));
auto it = _proximity_bar.changed_frames.find(idx);
if(it != _proximity_bar.changed_frames.end()) {
framemOver = idx;
distance2frame = 0;
} else if((it = _proximity_bar.changed_frames.find(idx - 1)) != _proximity_bar.changed_frames.end()) {
framemOver = idx - 1;
distance2frame = 1;
} else if((it = _proximity_bar.changed_frames.find(idx + 1)) != _proximity_bar.changed_frames.end()) {
framemOver = idx + 1;
distance2frame = 1;
}
}
if (distance2frame < 2) {
_mOverFrame = framemOver;
} else if(_bar->hovered()) {
if(tracker_endframe != -1) {
_mOverFrame = min(_frame_info.video_length, e.hover.x * float(_frame_info.video_length) / max_w_);
_bar->set_dirty();
}
}
else
_mOverFrame = -1;
}
if(_bar->hovered() && _bar->pressed() && this->mOverFrame() != -1)
{
SETTING(gui_frame) = this->mOverFrame();
}
});
_bar->add_event_handler(MBUTTON, [this](Event e) {
if(e.mbutton.pressed && this->mOverFrame() != -1 && e.mbutton.button == 0) {
_gui.set_redraw();
SETTING(gui_frame) = this->mOverFrame();
}
});
}
float new_height = roundf(bar_height / use_scale.y);
//_bar->set_scale(Vec2(1, new_height));
/*if(_proximity_bar._image) {
_bar->set_source(std::move(_proximity_bar._image));
//_proximity_bar.changed = false;
}*/
_bar->set_color(White.alpha(150));
_bar->set_pos(pos);
bool changed = false;
if(use_scale.y > 0) {
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
static std::string last_name;
// update proximity bar, whenever the FOI to display changed
if(last_name != _foi_state.name)
_proximity_bar.end = -1;
last_name = _foi_state.name;
if(!_bar
|| (uint)max_w != _bar->source()->cols
|| (uint)new_height != _bar->source()->rows
|| _proximity_bar.end == -1)
{
auto image = std::make_unique<Image>(1, max_w, 4);
image->set_to(0);
_bar->set_source(std::move(image));
_proximity_bar.end = _proximity_bar.start = -1;
changed = true;
_proximity_bar.changed_frames.clear();
}
}
if(tracker_endframe != -1 && _proximity_bar.end < tracker_endframe) {
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
auto individual_coverage = [](long_t frame) {
float count = 0;
if(Tracker::properties(frame)) {
for(auto fish : Tracker::instance()->active_individuals(frame)) {
if(fish->centroid(frame))
count++;
}
}
return (1 - count / float(Tracker::instance()->individuals().size()));
};
if(_proximity_bar.end == -1) {
_proximity_bar.start = _proximity_bar.end = _tracker.start_frame();
}
Vec2 pos(max_w / float(_frame_info.video_length) * _proximity_bar.end, 0);
cv::Mat img = _bar->source()->get();
if(_proximity_bar.end < _tracker.end_frame()) {
_proximity_bar.end = _tracker.end_frame();
changed = true;
}
Vec2 previous_point(-1, 0);
_proximity_bar.samples_per_pixel.resize(max_w);
for(auto & px : _proximity_bar.samples_per_pixel)
px = 0;
assert(max_w > 0);
std::set<uint32_t> multiple_assignments;
for (auto &c : _foi_state.changed_frames) {
float x = round(max_w / float(_frame_info.video_length) * c.frames().start);
if(x >= _proximity_bar.samples_per_pixel.size())
x = _proximity_bar.samples_per_pixel.size()-1;
++_proximity_bar.samples_per_pixel[uint32_t(x)];
if(_proximity_bar.samples_per_pixel[uint32_t(x)] > 1)
multiple_assignments.insert(uint32_t(x));
//auto it = _proximity_bar.changed_frames.find(c.frames().start);
//if(it == _proximity_bar.changed_frames.end()) {
/*float x = max_w / float(_frame_info.video_length) * c.frames().start;
float w = max(2, max_w / float(_frame_info.video_length) * c.frames().end - x);
Vec2 pp(x, 0);
cv::rectangle(img, pp, pp+Vec2(w,img.rows), _foi_state.color, -1);*/
//if(!_proximity_bar.changed) {
auto it = _proximity_bar.changed_frames.find(c.frames().start);
if(it == _proximity_bar.changed_frames.end() || it->second != c.fdx())
{
_proximity_bar.changed_frames[c.frames().start] = c.fdx();
changed = true;
}
}
if(changed) {
uint32_t px;
uint32_t N = 1;
if(multiple_assignments.size() >= _foi_state.changed_frames.size() * 0.1)
{
//Debug("Too many multi-assignments (%d / %d). Normalizing colors.", multiple_assignments.size(), _foi_state.changed_frames.size());
uint32_t Nx = 0;
for(auto x : multiple_assignments) {
auto n = _proximity_bar.samples_per_pixel[x];
if(n > N) {
N = n;
Nx = x;
}
}
}
for(size_t i=0; i<_proximity_bar.samples_per_pixel.size(); ++i) {
px = _proximity_bar.samples_per_pixel[i];
if(px > 0) {
Vec2 pp(i, 0);
float d = float(px) / float(N);
img(Bounds(pp, Size2(1, img.rows))) = (cv::Scalar)_foi_state.color.alpha(50 + 205 * min(1, SQR(d)));
}
//cv::rectangle(img, pp, pp+Vec2(1,img.rows), _foi_state.color, -1);
}
float x = max_w / float(_frame_info.video_length) * tracker_endframe;
if(previous_point.x != -1 && previous_point.x != x)
{
Vec2 point(x, individual_coverage(tracker_endframe) * img.rows);
cv::line(img, previous_point, Vec2(x-1, previous_point.y), Red);
cv::line(img, Vec2(x-1, previous_point.y), point, Red);
}
}
/*if(!_bar || !_bar->source()->operator==(_proximity_bar.image)) {
_proximity_bar.changed = true;
}*/
}
}
void Timeline::update_thread() {
_terminate = false;
_foi_state.color = Color(255, 200, 100, 255);
_foi_state.last_change = 0;
_foi_state.name = "";
auto long_wait_time = std::chrono::seconds(1);
auto short_wait_time = std::chrono::milliseconds(5);
while(!_terminate) {
bool changed = false;
//! Update the cached data
if(GUI::instance() && Tracker::instance()) {
if(!GUI::instance())
break;
std::lock_guard<std::recursive_mutex> lock(GUI::instance()->gui().lock());
Tracker::LockGuard guard("Timeline::update_thread", 100);
if(guard.locked()) {
Timer timer;
long_t index = _frame_info.frameIndex;
auto props = Tracker::properties(index);
auto prev_props = Tracker::properties(index - 1);
_frame_info.tdelta = props && prev_props ? props->time - prev_props->time : 0;
_frame_info.small_count = 0;
_frame_info.big_count = 0;
_frame_info.current_count = 0;
_frame_info.up_to_this_frame = 0;
_frame_info.analysis_range = Tracker::analysis_range();
tracker_endframe = _tracker.end_frame();
tracker_startframe = _tracker.start_frame();
if(prev_props && props) {
tdelta = _frame_info.tdelta;
}
_frame_info.training_ranges = _tracker.recognition() ? _tracker.recognition()->trained_ranges() : std::set<Rangel>{};
_frame_info.consecutive = _tracker.consecutive();
_frame_info.global_segment_order = track::Tracker::global_segment_order();
//if(longest != _frame_info.longest_consecutive && Tracker::recognition())
//if(Tracker::recognition()) {
/*for(auto &consec : _frame_info.global_segment_order) {
if(!Tracker::recognition()->dataset_quality() || !Tracker::recognition()->dataset_quality()->has(consec)) {
Tracker::recognition()->update_dataset_quality();
break;
}
}*/
//Tracker::recognition()->update_dataset_quality();
//}
if(Tracker::properties(_frame_info.frameIndex)) {
for (auto& fish : _frame_info.frameIndex >= tracker_startframe && _frame_info.frameIndex < tracker_endframe ? Tracker::active_individuals(_frame_info.frameIndex) : Tracker::set_of_individuals_t{}) {
if ((int)fish->frame_count() < FAST_SETTINGS(frame_rate)*3) {
_frame_info.small_count++;
} else
_frame_info.big_count++;
if(fish->has(_frame_info.frameIndex))
++_frame_info.current_count;
if(fish->start_frame() <= _frame_info.frameIndex) {
_frame_info.up_to_this_frame++;
}
}
}
//if(FAST_SETTINGS(calculate_posture))
// changed = EventAnalysis::update_events(_frame_info.frameIndex < tracker_endframe ? Tracker::active_individuals(_frame_info.frameIndex) : std::set<Individual*>{});
// needs Tracker lock
GUI::instance()->update_recognition_rect();
update_fois();
_update_thread_updated_once = true;
if(timer.elapsed() > 0.1 && !FAST_SETTINGS(analysis_paused)) {
if(long_wait_time < std::chrono::seconds(30)) {
long_wait_time = std::chrono::seconds(30);
short_wait_time = std::chrono::seconds(30);
if(!FAST_SETTINGS(analysis_paused))
Warning("Throtteling some non-essential gui functions until analysis is over.");
}
} else {
long_wait_time = std::chrono::seconds(1);
short_wait_time = std::chrono::milliseconds(5);
}
}
}
if(!changed)
std::this_thread::sleep_for(long_wait_time);
else
std::this_thread::sleep_for(short_wait_time);
}
}
void Timeline::reset_events(long_t after_frame) {
EventAnalysis::reset_events(after_frame);
{
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
if(after_frame == -1) {
_proximity_bar.changed_frames.clear();
} else {
for(auto iter = _proximity_bar.changed_frames.begin(), endIter = _proximity_bar.changed_frames.end(); iter != endIter; ) {
if (iter->first >= after_frame) {
_proximity_bar.changed_frames.erase(iter++);
} else {
++iter;
}
}
if(_bar && !_bar->source()->empty()) {
cv::Mat img = _bar->source()->get();
Vec2 pos(0, 0);
float x0 = Tracker::average().cols / float(_frame_info.video_length) * after_frame;
float x1 = Tracker::average().cols;
Debug("Clearing from %f to %f", x0, x1 + pos.x);
cv::rectangle(img, Vec2(x0, 0), Vec2(pos + Vec2(x1, img.rows)), Transparent, -1);
}
}
_proximity_bar.end = after_frame == -1 ? -1 : (after_frame - 1);
//_proximity_bar.changed = true;
tracker_endframe = _proximity_bar.end;
}
}
void Timeline::set_visible(bool v) {
if(_visible != v) {
_gui.cache().set_tracking_dirty();
_gui.set_redraw();
_visible = v;
}
}
void Timeline::next_poi(long_t _s_fdx) {
auto frame = GUI::frame();
long_t next_frame = frame;
std::set<FOI::fdx_t> fdx;
{
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
for(auto && [idx, number] : _proximity_bar.changed_frames) {
if(_s_fdx != -1) {
if(number.find(FOI::fdx_t(_s_fdx)) == number.end())
continue;
}
if(idx > frame) {
next_frame = idx;
fdx = number;
break;
}
}
}
if(frame != next_frame) {
SETTING(gui_frame) = next_frame;
if(_s_fdx == -1) {
auto &cache = GUI::instance()->cache();
if(!fdx.empty()) {
cache.deselect_all();
for(auto id : fdx) {
if(!cache.is_selected(id.id))
cache.do_select(id.id);
}
}
}
}
}
void Timeline::prev_poi(long_t _s_fdx) {
auto frame = GUI::frame();
long_t next_frame = frame;
std::set<FOI::fdx_t> fdx;
{
std::lock_guard<std::mutex> guard(_proximity_bar.mutex);
for(auto && [idx, number] : MakeReverse(_proximity_bar.changed_frames)) {
if(_s_fdx != -1) {
if(number.find(FOI::fdx_t(_s_fdx)) == number.end())
continue;
}
if(idx < frame) {
next_frame = idx;
fdx = number;
break;
}
}
}
if(frame != next_frame && next_frame != -1) {
SETTING(gui_frame) = next_frame;
if(_s_fdx == -1) {
auto &cache = GUI::instance()->cache();
if(!fdx.empty()) {
cache.deselect_all();
for(auto id : fdx) {
if(!cache.is_selected(id.id))
cache.do_select(id.id);
}
}
}
}
}
}