1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
/************************************************************************
*
* Copyright (C) 2018-2024 IRCAD France
* Copyright (C) 2018-2019 IHU Strasbourg
*
* This file is part of Sight.
*
* Sight is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Sight 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Sight. If not, see <https://www.gnu.org/licenses/>.
*
***********************************************************************/
#pragma once
#include <data/frame_tl.hpp>
#include <service/controller.hpp>
#include <opencv2/core.hpp>
namespace sight::module::filter::vision
{
/**
* @brief Service used to compute optical flow (Lukas-Kanade) to detect if camera is moving or not.
* \b Note: this service is not detecting if something is moving in a video,
* due to internal parameters it only detects if camera is moving globally.
*
* @section Signals Signals
* - \b camera_moved: send when camera has moved.
* -\b camera_remained: send when camera is detected as stable.
*
* @section Slots Slots
* - \b updating: called when a new frame is pushed into the timeline. Detected if camera has moved or not.
* @section XML XML Configuration
*
* @code{.xml}
<service uid="..." type="sight::module::filter::vision::optical_flow" worker="ofWorker >
<in key="timeline" uid="..." auto_connect="true" />
<config latency="333" scaleFactor="3.6" />
</service>
@endcode
* @subsection Input Input:
* - \b timeline [sight::data::frame_tl]: timeline on which optical flow will be computed.
* @subsection Configuration Configuration:
* - \b latency (optional): There is no need to process every frames coming in.
* Use `latency` to wait between two consecutive frame. Ex: if set to 333 (in ms), it will compute ~1/10 frames at 30fps
* (Default: 333 ms).
* Usually you don't need to change the value.
* - \b scaleFactor (optional): if image is > 640 x 480 the scaleFactor is applied to downscale image
* to keep a good balance between computation time and feature tracking quality (default 3,6),
* usually you don't need to change the value.
*/
class optical_flow : public service::controller
{
public:
SIGHT_DECLARE_SERVICE(optical_flow, sight::service::controller);
using motion_signal_t = core::com::signal<void ()>;
using no_motion_signal_t = core::com::signal<void ()>;
/// Constructor
optical_flow() noexcept;
/// Destructor
~optical_flow() noexcept override;
/// Connects ::arData:FrameTL::signals::PUSHED to service::slots::UPDATE
service::connections_t auto_connections() const override;
protected:
/// Does nothing.
void configuring() override;
/// Does nothing.
void starting() override;
/// Computes Optical flow.
void updating() override;
/// Does nothing.
void stopping() override;
private:
/// Handles concurrency.
std::mutex m_main_mutex;
/// Signal send when motion is detected.
motion_signal_t::sptr m_motion_signal;
/// Signal send when no motion is detected.
no_motion_signal_t::sptr m_no_motion_signal;
/// Stores last image.
cv::Mat m_last_gray_img;
/// Stores last corners.
cv::Mat m_last_corners;
/// Waiting time between to frames.
unsigned int m_latency {333};
/// Factor of re-scale: resize image to keep good balance between computation time and feature tracking quality.
float m_image_scale_factor {3.6F};
/// Optical flow can only be computed if a frame is already present (see: m_lastGrayImg).
/// True if it is, False otherwise
bool m_initialization {false};
/// Stores last behavior (true if motion, false otherwise).
bool m_motion {false};
/// Stores last processed frame timestamp.
core::clock::type m_last_timestamp {0};
static constexpr std::string_view FRAME_TIMELINE_INPUT = "timeline";
sight::data::ptr<sight::data::frame_tl, sight::data::access::in> m_timeline {this, FRAME_TIMELINE_INPUT};
};
} //namespace sight::module::filter::vision
|