diff --git a/Application/src/commons/common/gui/GuiTypes.cpp b/Application/src/commons/common/gui/GuiTypes.cpp index a273d8a9a2b033ef594ac6796f00c8cc238da3d3..cd96bc6ded50ead92bf21e15485bddbf84b9906b 100644 --- a/Application/src/commons/common/gui/GuiTypes.cpp +++ b/Application/src/commons/common/gui/GuiTypes.cpp @@ -180,7 +180,13 @@ Polygon::Polygon(const std::vector<Vertex>& vertices) bool Polygon::in_bounds(float x, float y) { if(Drawable::in_bounds(x, y)) { - return pnpoly(*_vertices, Vec2(x, y)); + std::vector<Vec2> points; + points.reserve(_relative->size()); + auto transform = global_transform(); + for(auto &pt : *_relative) { + points.push_back(transform.transformPoint(pt)); + } + return pnpoly(points, Vec2(x, y)); } return false; } diff --git a/Application/src/tracker/gui/gui.cpp b/Application/src/tracker/gui/gui.cpp index dc222ac7db78f17cc2f230b73f837a163d7b9708..a562ae64f49a5bc2e30c2777564aef82d60c4c3a 100644 --- a/Application/src/tracker/gui/gui.cpp +++ b/Application/src/tracker/gui/gui.cpp @@ -3026,7 +3026,7 @@ void GUI::update_recognition_rect() { auto worker = [&border_distance, max_h](ushort x) { for (ushort y = 0; y < max_h; ++y) { if(Tracker::instance()->border().in_recognition_bounds(Vec2(x, y))) - border_distance->set_pixel(y, x, DarkCyan.alpha(15)); + border_distance->set_pixel(x, y, DarkCyan.alpha(15)); } }; @@ -3043,20 +3043,21 @@ void GUI::update_recognition_rect() { _recognition_image.set_source(std::move(border_distance)); _cache.set_tracking_dirty(); _cache.set_blobs_dirty(); + _cache.set_raw_blobs_dirty(); _cache.set_redraw(); } - if(!FAST_SETTINGS(track_whitelist).empty()) + if(!FAST_SETTINGS(track_include).empty()) { - auto keys = extract_keys(_whitelist_rects); + auto keys = extract_keys(_include_shapes); - for(auto &rect : FAST_SETTINGS(track_whitelist)) { - auto it = _whitelist_rects.find(rect); - if(it == _whitelist_rects.end()) { + for(auto &rect : FAST_SETTINGS(track_include)) { + auto it = _include_shapes.find(rect); + if(it == _include_shapes.end()) { if(rect.size() == 2) { auto ptr = std::make_shared<Rect>(Bounds(rect[0], rect[1] - rect[0]), Green.alpha(25), Green.alpha(100)); ptr->set_clickable(true); - _whitelist_rects[rect] = ptr; + _include_shapes[rect] = ptr; } else if(rect.size() > 2) { //auto r = std::make_shared<std::vector<Vec2>>(rect); @@ -3065,34 +3066,34 @@ void GUI::update_recognition_rect() { ptr->set_fill_clr(Green.alpha(25)); ptr->set_border_clr(Green.alpha(100)); ptr->set_clickable(true); - _whitelist_rects[rect] = ptr; + _include_shapes[rect] = ptr; } - _cache.set_redraw(); } keys.erase(rect); } for(auto &key : keys) { - _whitelist_rects.erase(key); - _cache.set_redraw(); + _include_shapes.erase(key); } - } else if(FAST_SETTINGS(track_whitelist).empty() && !_whitelist_rects.empty()) { - _whitelist_rects.clear(); - _cache.set_redraw(); + _cache.set_raw_blobs_dirty(); + + } else if(FAST_SETTINGS(track_include).empty() && !_include_shapes.empty()) { + _include_shapes.clear(); + _cache.set_raw_blobs_dirty(); } - if(!FAST_SETTINGS(track_blacklist).empty()) + if(!FAST_SETTINGS(track_ignore).empty()) { - auto keys = extract_keys(_blacklist_rects); + auto keys = extract_keys(_ignore_shapes); - for(auto &rect : FAST_SETTINGS(track_blacklist)) { - auto it = _blacklist_rects.find(rect); - if(it == _blacklist_rects.end()) { + for(auto &rect : FAST_SETTINGS(track_ignore)) { + auto it = _ignore_shapes.find(rect); + if(it == _ignore_shapes.end()) { if(rect.size() == 2) { auto ptr = std::make_shared<Rect>(Bounds(rect[0], rect[1] - rect[0]), Red.alpha(25), Red.alpha(100)); ptr->set_clickable(true); - _blacklist_rects[rect] = ptr; + _ignore_shapes[rect] = ptr; } else if(rect.size() > 2) { //auto r = std::make_shared<std::vector<Vec2>>(rect); @@ -3101,21 +3102,21 @@ void GUI::update_recognition_rect() { ptr->set_fill_clr(Red.alpha(25)); ptr->set_border_clr(Red.alpha(100)); ptr->set_clickable(true); - _blacklist_rects[rect] = ptr; + _ignore_shapes[rect] = ptr; } - _cache.set_redraw(); } keys.erase(rect); } for(auto &key : keys) { - _blacklist_rects.erase(key); - _cache.set_redraw(); + _ignore_shapes.erase(key); } - } else if(FAST_SETTINGS(track_blacklist).empty() && !_blacklist_rects.empty()) { - _blacklist_rects.clear(); - _cache.set_redraw(); + _cache.set_raw_blobs_dirty(); + + } else if(FAST_SETTINGS(track_ignore).empty() && !_ignore_shapes.empty()) { + _ignore_shapes.clear(); + _cache.set_raw_blobs_dirty(); } } @@ -3228,7 +3229,7 @@ void GUI::draw_raw(gui::DrawStructure &base, long_t) { } if(_timeline->visible()) { - for(auto && [rect, ptr] : _whitelist_rects) { + for(auto && [rect, ptr] : _include_shapes) { base.wrap_object(*ptr); if(ptr->hovered()) { @@ -3238,7 +3239,7 @@ void GUI::draw_raw(gui::DrawStructure &base, long_t) { } } - for(auto && [rect, ptr] : _blacklist_rects) { + for(auto && [rect, ptr] : _ignore_shapes) { base.wrap_object(*ptr); if(ptr->hovered()) { diff --git a/Application/src/tracker/gui/gui.h b/Application/src/tracker/gui/gui.h index 3c19f22fa0006d0b11b08de7a55b8b4c7839352f..2be5759dbc2dfee3ee35941427fdc5de1336af86 100644 --- a/Application/src/tracker/gui/gui.h +++ b/Application/src/tracker/gui/gui.h @@ -175,7 +175,7 @@ protected: gui::WorkProgress *_work_progress; gui::ExternalImage _recognition_image; - std::map<std::vector<Vec2>, std::shared_ptr<gui::Drawable>> _blacklist_rects, _whitelist_rects; + std::map<std::vector<Vec2>, std::shared_ptr<gui::Drawable>> _ignore_shapes, _include_shapes; GETTER_SETTER(bool, info_visible) diff --git a/Application/src/tracker/misc/default_config.cpp b/Application/src/tracker/misc/default_config.cpp index 521ccd3c7d5588233b4b6fdec3e6d1d02cf5216b..49920bc0edb1c90b557403427d920202b121095d 100644 --- a/Application/src/tracker/misc/default_config.cpp +++ b/Application/src/tracker/misc/default_config.cpp @@ -90,8 +90,10 @@ namespace default_config { {"fish_time_probability_enabled", "track_time_probability_enabled"}, {"number_fish", "track_max_individuals"}, {"outline_remove_loops", ""}, - {"whitelist_rect", "track_whitelist"}, - {"exclude_rect", "track_blacklist"}, + {"whitelist_rect", "track_include"}, + {"track_whitelist", "track_include"}, + {"exclude_rect", "track_ignore"}, + {"track_blacklist", "track_ignore"}, {"posture_threshold_constant", "track_posture_threshold"}, {"threshold_constant", "track_threshold"}, {"recognition_rect", "recognition_shapes"}, @@ -522,8 +524,8 @@ file::Path conda_environment_path() { CONFIG("manually_approved", std::map<long_t,long_t>(), "A list of ranges of manually approved frames that may be used for generating training datasets {232:232,5555:5560}."); CONFIG("gui_focus_group", std::vector<idx_t>(), "Focus on this group of individuals."); - CONFIG("track_blacklist", std::vector<std::vector<Vec2>>(), "If this is not empty, objects within the given rectangles or polygons (>= 3 points) [[x0,y0],[x1,y1](, ...)], ...] will be ignored during tracking."); - CONFIG("track_whitelist", std::vector<std::vector<Vec2>>(), "If this is not empty, objects within the given rectangles or polygons (>= 3 points) [[x0,y0],[x1,y1](, ...)], ...] will be the only objects being tracked. (overwrites `track_blacklist`)"); + CONFIG("track_ignore", std::vector<std::vector<Vec2>>(), "If this is not empty, objects within the given rectangles or polygons (>= 3 points) [[x0,y0],[x1,y1](, ...)], ...] will be ignored during tracking."); + CONFIG("track_include", std::vector<std::vector<Vec2>>(), "If this is not empty, objects within the given rectangles or polygons (>= 3 points) [[x0,y0],[x1,y1](, ...)], ...] will be the only objects being tracked. (overwrites `track_ignore`)"); CONFIG("huge_timestamp_ends_segment", true, ""); CONFIG("track_trusted_probability", float(0.5), "If the probability, that is used to assign an individual to an object, is smaller than this value, the current segment will be ended (thus this will also not be a consecutive segment anymore for this individual)."); diff --git a/Application/src/tracker/tracking/Tracker.cpp b/Application/src/tracker/tracking/Tracker.cpp index 887724f44cf61ff61d62d8b584ea78f37e3815f5..3d1f784b07044be10e2779706a6c8a3010312730 100644 --- a/Application/src/tracker/tracking/Tracker.cpp +++ b/Application/src/tracker/tracking/Tracker.cpp @@ -226,224 +226,6 @@ const FrameProperties* Tracker::properties(long_t frameIndex, const CacheHints* } bool callback_registered = false; - /*std::vector<std::string> read_these { - "smooth_window", - "cm_per_pixel", - "frame_rate", - "track_max_reassign_time", - "calculate_posture", - "track_max_speed", - "debug", - "blob_size_ranges", - "track_threshold", - "track_threshold_2", - "threshold_ratio_range", - "track_max_individuals", - "track_posture_threshold", - "outline_smooth_step", - "outline_smooth_samples", - "outline_resample", - "manual_matches", - "curvature_range", - "midline_resolution", - "midline_samples", - "meta_mass_mg", - "individual_names", - "midline_stiff_percentage", - "matching_probability_threshold", - "posture_direction_smoothing", - "tags_path", - "manual_identities", - //"correct_luminance", - "grid_points", - "recognition_shapes", - "grid_points_scaling", - "track_blacklist", - "track_whitelist", - "huge_timestamp_ends_segment", - "huge_timestamp_seconds", - "manually_approved", - "pixel_grid_cells", - "track_speed_decay", - "midline_invert", - "manual_splits", - "track_time_probability_enabled", - "posture_head_percentage", - "enable_absolute_difference", - "blobs_per_thread", - "individual_prefix", - "video_length", - "analysis_range", - "recognition_enable", - "visual_field_eye_offset", - "visual_field_eye_separation", - "track_end_segment_for_speed", - "match_mode", - "track_do_history_split", - "posture_closing_steps", - "posture_closing_size", - "recognition_image_scale", - "analysis_paused", - "track_trusted_probability" - };*/ - - /*void Tracker::changed_setting(const sprite::Map&, const std::string &key, const sprite::PropertyType& value) { - if(contains(read_these, key)) { - LockGuard guard("Tracker::changed_setting "+key); - - #define UPDATE_VALUE(NAME) (key == #NAME ) \ - FAST_SETTINGS(NAME) = value.value< \ - std::remove_cv< \ - std::remove_reference< \ - decltype(FAST_SETTINGS(NAME)) \ - >::type \ - >::type>() - #define UPDATE_VALUE_(TYPE, NAME) (key == #NAME ) FAST_SETTINGS(NAME) = value.value< TYPE >() - - if UPDATE_VALUE_(int, smooth_window); - else if UPDATE_VALUE(cm_per_pixel); - else if UPDATE_VALUE(frame_rate); - else if UPDATE_VALUE(track_max_reassign_time); - else if UPDATE_VALUE(speed_extrapolation); - else if UPDATE_VALUE(calculate_posture); - else if UPDATE_VALUE(track_max_speed); - else if UPDATE_VALUE(track_end_segment_for_speed); - else if UPDATE_VALUE(match_mode); - else if UPDATE_VALUE(debug); - else if UPDATE_VALUE(blob_size_ranges); - else if UPDATE_VALUE(track_threshold); - else if UPDATE_VALUE(track_threshold_2); - else if UPDATE_VALUE(threshold_ratio_range); - else if UPDATE_VALUE(track_max_individuals); - else if UPDATE_VALUE(track_posture_threshold); - else if UPDATE_VALUE(outline_smooth_step); - else if UPDATE_VALUE(outline_smooth_samples); - //else if UPDATE_VALUE(outline_resample); - //else if UPDATE_VALUE(manual_matches); - else if UPDATE_VALUE(curvature_range); - else if UPDATE_VALUE_(int, midline_resolution); - else if UPDATE_VALUE(midline_samples); - else if UPDATE_VALUE(meta_mass_mg); - else if UPDATE_VALUE(individual_names); - else if UPDATE_VALUE(midline_stiff_percentage); - else if UPDATE_VALUE(recognition_image_scale); - else if UPDATE_VALUE(track_trusted_probability); - else if UPDATE_VALUE(analysis_paused); - else if UPDATE_VALUE(matching_probability_threshold); - //else if UPDATE_VALUE(posture_direction_smoothing); - else if (key == "posture_direction_smoothing") { - static_assert(std::is_same<decltype(_settings.posture_direction_smoothing), size_t>::value, "posture_direction_smoothing assumed to be size_t."); - size_t v = value.value<size_t>(); - - if(v != FAST_SETTINGS(posture_direction_smoothing)) { - FAST_SETTINGS(posture_direction_smoothing) = v; - - Debug("Updating midlines / head positions..."); - auto worker = [key](){ - LockGuard guard("Updating midlines in changed_setting("+key+")"); - - for (auto && [id, fish] : Tracker::individuals()) { - Tracker::instance()->_thread_pool.enqueue([](long_t id, Individual *fish){ - Debug("\t%d", id); - fish->clear_post_processing(); - fish->update_midlines(nullptr); - }, id, fish); - } - - Tracker::instance()->_thread_pool.wait(); - if(Tracker::recognition() && Tracker::recognition()->dataset_quality()) { - Tracker::recognition()->dataset_quality()->remove_frames(start_frame()); - Tracker::recognition()->update_dataset_quality(); - } - }; - - if(GUI::instance()) { - GUI::work().add_queue("updating midlines / head positions...", worker); - } else - worker(); - } - } - else if UPDATE_VALUE(tags_path); - else if UPDATE_VALUE(manual_identities); - //else if UPDATE_VALUE(correct_luminance); - else if UPDATE_VALUE(grid_points); - else if UPDATE_VALUE(recognition_shapes); - else if UPDATE_VALUE(grid_points_scaling); - else if (key == "track_blacklist" || key == "track_whitelist") { - Tracker::instance()->thread_pool().enqueue([key](std::vector<std::vector<Vec2>> tmp) - { - bool changed = false; - for(auto &vec : tmp) { - if(vec.size() > 2) { - auto ptr = poly_convex_hull(&vec); - if(ptr) { - if(vec != *ptr) { - vec = *ptr; - changed = true; - } - } - } - } - - if(changed) - GlobalSettings::get(key) = tmp; - }, value.value<std::vector<std::vector<Vec2>>>()); - - if(key == "track_blacklist") - FAST_SETTINGS(track_blacklist) = value.value<std::vector<std::vector<Vec2>>>(); - else if(key == "track_whitelist") - FAST_SETTINGS(track_whitelist) = value.value<std::vector<std::vector<Vec2>>>(); - } - //else if UPDATE_VALUE(track_blacklist); - //else if UPDATE_VALUE(track_whitelist); - else if UPDATE_VALUE(huge_timestamp_ends_segment); - else if UPDATE_VALUE(huge_timestamp_seconds); - else if (key == "manually_approved") { - FAST_SETTINGS(manually_approved) = value.value<std::map<long_t, long_t>>(); - - if(recognition() && recognition()->dataset_quality()) { - recognition()->update_dataset_quality(); - } - } //UPDATE_VALUE(manually_approved); - else if UPDATE_VALUE(pixel_grid_cells); - else if UPDATE_VALUE(track_speed_decay); - else if UPDATE_VALUE(track_time_probability_enabled); - else if UPDATE_VALUE(midline_invert); - else if UPDATE_VALUE(posture_head_percentage); - else if UPDATE_VALUE(enable_absolute_difference); - else if UPDATE_VALUE(track_do_history_split); - else if UPDATE_VALUE(posture_closing_steps); - else if UPDATE_VALUE(posture_closing_size); - else if UPDATE_VALUE(blobs_per_thread); - else if UPDATE_VALUE(individual_prefix); - else if UPDATE_VALUE(video_length); - else if UPDATE_VALUE(analysis_range); - else if UPDATE_VALUE(recognition_enable); - else if UPDATE_VALUE(visual_field_eye_offset); - else if UPDATE_VALUE(visual_field_eye_separation); - else if(key == "outline_resample") { - //! Dont allow outline_resample to be 0 (currently because of compression). - static_assert(std::is_same<decltype(_settings.outline_resample), float>::value, "outline_resample assumed to be float."); - float v = value.value<float>(); - - if(v <= 0) { - Warning("outline_resample defaulting to 1.0 instead of %f", v); - SETTING(outline_resample) = v = 1.f; - } - - if(FAST_SETTINGS(outline_resample) != v) - FAST_SETTINGS(outline_resample) = v; - } - - if(key == "frame_rate") { - std::lock_guard<std::mutex> guard(_properties_mutex); - _properties_cache.clear(); //! TODO: need to refill as well - } - - #undef UPDATE_VALUE_ - #undef UPDATE_VALUE - } - }*/ Recognition* Tracker::recognition() { if(!_instance) @@ -489,8 +271,9 @@ const FrameProperties* Tracker::properties(long_t frameIndex, const CacheHints* } }); - auto track_list_update = [](auto&key, auto&value){ - Tracker::instance()->thread_pool().enqueue([key](Settings::track_blacklist_t tmp) + auto track_list_update = [](auto&key, auto&value) + { + auto update = [key = key, tmp = value.template value<Settings::track_ignore_t>()]() mutable { bool changed = false; for(auto &vec : tmp) { @@ -505,12 +288,21 @@ const FrameProperties* Tracker::properties(long_t frameIndex, const CacheHints* } } - if(changed) + if(changed && GUI::instance()) { + std::lock_guard<std::recursive_mutex> guard(GUI::instance()->gui().lock()); GlobalSettings::get(key) = tmp; - }, value.template value<Settings::track_blacklist_t>()); + } else if(changed) { + GlobalSettings::get(key) = tmp; + } + }; + + if(GUI::instance()) { + GUI::work().add_queue("", update); + } else + update(); }; - Settings::set_callback(Settings::track_blacklist, track_list_update); - Settings::set_callback(Settings::track_whitelist, track_list_update); + Settings::set_callback(Settings::track_ignore, track_list_update); + Settings::set_callback(Settings::track_include, track_list_update); Settings::set_callback(Settings::frame_rate, [this](auto&, auto&){ std::lock_guard<std::mutex> guard(_properties_mutex); _properties_cache.clear(); //! TODO: need to refill as well @@ -549,7 +341,10 @@ const FrameProperties* Tracker::properties(long_t frameIndex, const CacheHints* if (!callback_registered) { - auto variable_changed = [](auto&map, auto&key, auto&value){ if(contains(Settings::names(), key)) { Tracker::LockGuard guard("changed_settings"); Settings :: variable_changed(map, key, value); }}; + auto variable_changed = [](auto&map, auto&key, auto&value){ if(contains(Settings::names(), key)) { + Tracker::LockGuard guard("changed_settings"); + Settings :: variable_changed(map, key, value); + }}; cmn::GlobalSettings::map().register_callback((void*)"Settings", variable_changed); for(auto &n : Settings :: names()) variable_changed(cmn::GlobalSettings::map(), n, cmn::GlobalSettings::get(n).get()); @@ -1044,15 +839,15 @@ bool operator<(long_t frame, const FrameProperties& props) { float recount = b->recount(result->threshold, *result->background); - if(!FAST_SETTINGS(track_blacklist).empty()) { - if(blob_matches_shapes(b, FAST_SETTINGS(track_blacklist))) { + if(!FAST_SETTINGS(track_ignore).empty()) { + if(blob_matches_shapes(b, FAST_SETTINGS(track_ignore))) { filtered_out.push_back(b); continue; } } - if(!FAST_SETTINGS(track_whitelist).empty()) { - if(!blob_matches_shapes(b, FAST_SETTINGS(track_whitelist))) { + if(!FAST_SETTINGS(track_include).empty()) { + if(!blob_matches_shapes(b, FAST_SETTINGS(track_include))) { filtered_out.push_back(b); continue; } @@ -1240,7 +1035,7 @@ bool operator<(long_t frame, const FrameProperties& props) { const int threshold = FAST_SETTINGS(track_threshold); const BlobSizeRange& fish_size = FAST_SETTINGS(blob_size_ranges); const float cm_sq = SQR(FAST_SETTINGS(cm_per_pixel)); - auto blacklist = FAST_SETTINGS(track_blacklist); + auto blacklist = FAST_SETTINGS(track_ignore); std::mutex _mutex; auto work = [&](auto b, std::vector<pv::BlobPtr>& big_filtered, std::vector<pv::BlobPtr>& noise){ diff --git a/Application/src/tracker/tracking/Tracker.h b/Application/src/tracker/tracking/Tracker.h index f2e8bdcdfeed9133c712980259a18fa1c0289dba..b01b3da5bc5e50542037bb1ee2f488652ee003d9 100644 --- a/Application/src/tracker/tracking/Tracker.h +++ b/Application/src/tracker/tracking/Tracker.h @@ -72,8 +72,8 @@ CREATE_STRUCT(Settings, (std::vector<Vec2>, grid_points), (std::vector<std::vector<Vec2>>, recognition_shapes), (float, grid_points_scaling), - (std::vector<std::vector<Vec2>>, track_blacklist), - (std::vector<std::vector<Vec2>>, track_whitelist), + (std::vector<std::vector<Vec2>>, track_ignore), + (std::vector<std::vector<Vec2>>, track_include), (bool, huge_timestamp_ends_segment), (double, huge_timestamp_seconds), (mapproved_t, manually_approved), @@ -158,67 +158,6 @@ CREATE_STRUCT(Settings, static std::string thread_name_holding(); #define FAST_SETTINGS(NAME) track::Settings::copy<track::Settings:: NAME>() - /*struct Settings { - uint32_t smooth_window; - float cm_per_pixel; - int frame_rate; - float track_max_reassign_time; - float speed_extrapolation; - bool calculate_posture; - float track_max_speed; - bool debug; - BlobSizeRange blob_size_ranges; - int track_threshold; - int track_threshold_2; - Rangef threshold_ratio_range; - idx_t track_max_individuals; - int track_posture_threshold; - uint8_t outline_smooth_step; - uint8_t outline_smooth_samples; - float outline_resample; - std::map<long_t, std::map<idx_t, int64_t>> manual_matches; - std::map<long_t, std::set<int64_t>> manual_splits; - int curvature_range; - uint32_t midline_resolution; - uint64_t midline_samples; - float meta_mass_mg; - std::map<idx_t, std::string> individual_names; - float midline_stiff_percentage; - float matching_probability_threshold; - size_t posture_direction_smoothing; - file::Path tags_path; - std::set<idx_t> manual_identities; - //bool correct_luminance; - std::vector<Vec2> grid_points; - std::vector<std::vector<Vec2>> recognition_shapes; - float grid_points_scaling; - std::vector<std::vector<Vec2>> track_blacklist; - std::vector<std::vector<Vec2>> track_whitelist; - bool huge_timestamp_ends_segment; - double huge_timestamp_seconds; - std::map<long_t,long_t> manually_approved; - size_t pixel_grid_cells; - float track_speed_decay; - bool midline_invert; - bool track_time_probability_enabled; - float posture_head_percentage; - bool enable_absolute_difference; - float blobs_per_thread; - std::string individual_prefix; - size_t video_length; - std::pair<long_t,long_t> analysis_range; - bool recognition_enable; - float visual_field_eye_offset; - float visual_field_eye_separation; - bool track_end_segment_for_speed; - default_config::matching_mode_t::Class match_mode; - bool track_do_history_split; - uint8_t posture_closing_steps; - uint8_t posture_closing_size; - float recognition_image_scale; - bool analysis_paused; - float track_trusted_probability; - };*/ struct Statistics { float adding_seconds;