YODAU 1.0
YEAR OF THE DEPEND ADULT UNDERGARMENT
Loading...
Searching...
No Matches
opencv_client.hpp
Go to the documentation of this file.
1#ifndef YODAU_BACKEND_OPENCV_CLIENT_HPP
2#define YODAU_BACKEND_OPENCV_CLIENT_HPP
3
4#ifdef YODAU_OPENCV
5
6#include "event.hpp"
7#include "frame.hpp"
8#include "stream.hpp"
9#include "stream_manager.hpp"
10
11#include <opencv2/opencv.hpp>
12
13#include <chrono>
14#include <cstddef>
15#include <functional>
16#include <mutex>
17#include <optional>
18#include <stop_token>
19#include <string>
20#include <unordered_map>
21#include <vector>
22
23namespace yodau::backend {
24
25/**
26 * @brief OpenCV-based backend helper for capture and motion/tripwire analytics.
27 *
28 * This class provides:
29 * - a frame-producing daemon for a given @ref stream using @c cv::VideoCapture,
30 * - a motion / tripwire frame processor that returns @ref event objects,
31 * - adapters returning hooks compatible with @ref stream_manager.
32 *
33 * The implementation keeps per-stream state (previous gray frame, last emit
34 * time, last motion position, and per-tripwire cooldowns) protected by an
35 * internal mutex.
36 *
37 * Coordinate system:
38 * - Motion and tripwire positions are reported as percentage-based points
39 * (@ref point), i.e. x,y in [0.0; 100.0].
40 *
41 * Thread-safety:
42 * - Public methods are safe to call concurrently; internal maps are guarded by
43 * @ref mtx.
44 */
45class opencv_client {
46public:
47 /**
48 * @brief Default constructor.
49 *
50 * No heavy initialization is performed. Internal state is created lazily.
51 */
52 opencv_client() = default;
53
54 /**
55 * @brief Start capturing frames from a stream and push them to a callback.
56 *
57 * The daemon:
58 * - opens a @c cv::VideoCapture either by local index (for "/dev/videoN")
59 * or directly by path/URL,
60 * - reads frames until @p st requests stop or capture ends,
61 * - converts each @c cv::Mat to @ref frame and calls @p on_frame.
62 *
63 * If the stream is file-based and looping is enabled, the capture position
64 * is reset to frame 0 on end-of-file.
65 *
66 * @param s Stream describing the source.
67 * @param on_frame Callback invoked for each captured frame (frame is
68 * moved).
69 * @param st Stop token used for cooperative cancellation.
70 */
71 void daemon_start(
72 const stream& s, const std::function<void(frame&&)>& on_frame,
73 const std::stop_token& st
74 );
75
76 /**
77 * @brief Analyze a frame and produce motion/tripwire events.
78 *
79 * High-level algorithm (see implementation for exact thresholds):
80 * 1. Convert BGR frame to gray, blur, and diff against previous gray frame
81 * per stream.
82 * 2. Threshold + morphology to obtain motion mask.
83 * 3. Find contours, keep the largest, filter by minimum area and global
84 * non-zero ratio.
85 * 4. Enforce a per-stream cooldown to limit event rate.
86 * 5. Compute motion centroid, convert to percentage coordinates.
87 * 6. If a previous centroid is available, test connected lines from the
88 * stream for intersections with the motion contour and emit tripwire events
89 * respecting @ref line::dir and a per-(stream,line,direction) cooldown.
90 * 7. Emit a primary motion event at centroid.
91 * 8. Emit additional "bubble" motion events on a coarse grid over the mask
92 * (capped) to approximate motion shape.
93 *
94 * @param s Stream context (used for connected lines and naming).
95 * @param f Frame to analyze.
96 * @return Vector of produced events; may be empty.
97 */
98 std::vector<event> motion_processor(const stream& s, const frame& f);
99
100 /**
101 * @brief Create a @ref stream_manager::daemon_start_fn bound to this
102 * instance.
103 *
104 * The returned functor forwards to @ref daemon_start.
105 *
106 * @return Daemon start hook for a manager.
107 */
108 stream_manager::daemon_start_fn daemon_start_fn();
109
110 /**
111 * @brief Create a @ref stream_manager::frame_processor_fn bound to this
112 * instance.
113 *
114 * The returned functor forwards to @ref motion_processor.
115 *
116 * @return Frame processor hook for a manager.
117 */
118 stream_manager::frame_processor_fn frame_processor_fn();
119
120private:
121 /**
122 * @brief Parse local V4L2 index from a device path.
123 *
124 * Accepts paths of the form "/dev/videoN".
125 *
126 * @param path Stream path.
127 * @return Device index N, or -1 if @p path is not a local device.
128 */
129 int local_index_from_path(const std::string& path) const;
130
131 /**
132 * @brief Convert an OpenCV matrix to a backend frame.
133 *
134 * Ensures resulting frame is BGR24.
135 *
136 * @param m Source cv::Mat.
137 * @return Converted @ref frame.
138 */
139 frame mat_to_frame(const cv::Mat& m) const;
140
141 /**
142 * @brief Z-component of cross product (AB x AC).
143 *
144 * Used for orientation tests in 2D geometry.
145 */
146 float cross_z(const point& a, const point& b, const point& c) const;
147
148 /**
149 * @brief Orientation of triangle (a,b,c).
150 *
151 * @return 1 if counter-clockwise, -1 if clockwise, 0 if collinear
152 * within @ref point::epsilon.
153 */
154 int orient(const point& a, const point& b, const point& c) const;
155
156 /**
157 * @brief Check whether c lies between a and b (inclusive with tolerance).
158 */
159 bool between(float a, float b, float c) const;
160
161 /**
162 * @brief Check whether point c lies on segment ab.
163 */
164 bool on_segment(const point& a, const point& b, const point& c) const;
165
166 /**
167 * @brief Test if two 2D segments intersect.
168 *
169 * Handles proper intersections and collinear overlaps.
170 */
171 bool segments_intersect(
172 const point& p1, const point& p2, const point& q1, const point& q2
173 ) const;
174
175 /**
176 * @brief Compute intersection point of two segments if they intersect.
177 *
178 * Uses parametric line intersection with epsilon checks.
179 *
180 * @return Intersection point in percentage coordinates, or std::nullopt.
181 */
182 std::optional<point> segment_intersection(
183 const point& p1, const point& p2, const point& q1, const point& q2
184 ) const;
185
186 /**
187 * @brief Append a motion event to the output vector.
188 *
189 * @param out Output event list to append to.
190 * @param stream_name Source stream name.
191 * @param ts Event timestamp.
192 * @param pos_pct Motion position in percentage coordinates.
193 */
194 void add_motion_event(
195 std::vector<event>& out, const std::string& stream_name,
196 const std::chrono::steady_clock::time_point ts, const point& pos_pct
197 ) const;
198
199 /**
200 * @brief Update best intersection candidate if current one is closer.
201 *
202 * Used while checking contour intersections with line segments.
203 */
204 void consider_hit(
205 bool& hit, float& best_dist2, point& best_a, point& best_b,
206 point& best_pos, const point& cur_pos_pct, const point& a,
207 const point& b, const point& pos
208 ) const;
209
210 /**
211 * @brief Test a single line segment against a contour polyline.
212 *
213 * Updates best intersection (if any) through @ref consider_hit.
214 *
215 * @param hit In/out: whether any hit was found.
216 * @param best_dist2 In/out: best squared distance to current position.
217 * @param best_a In/out: line segment start of best hit.
218 * @param best_b In/out: line segment end of best hit.
219 * @param best_pos In/out: intersection position for best hit.
220 * @param cur_pos_pct Current motion centroid.
221 * @param contour_pct Motion contour in percentage coordinates.
222 * @param a Segment start.
223 * @param b Segment end.
224 */
225 void test_line_segment_against_contour(
226 bool& hit, float& best_dist2, point& best_a, point& best_b,
227 point& best_pos, const point& cur_pos_pct,
228 const std::vector<point>& contour_pct, const point& a, const point& b
229 ) const;
230
231 /**
232 * @brief Check a motion contour against a line and emit tripwire events.
233 *
234 * Determines the closest intersecting segment of @p l, infers crossing
235 * direction from @p prev_pos to @p cur_pos_pct, applies direction
236 * constraint and cooldown, and appends a tripwire @ref event if allowed.
237 *
238 * @param out Output event list.
239 * @param s Source stream.
240 * @param l Line to test.
241 * @param prev_pos Previous centroid position.
242 * @param cur_pos_pct Current centroid position.
243 * @param contour_pct Motion contour (percentage coordinates).
244 * @param now Current timestamp.
245 */
246 void process_tripwire_for_line(
247 std::vector<event>& out, const stream& s, const line& l,
248 const point& prev_pos, const point& cur_pos_pct,
249 const std::vector<point>& contour_pct,
250 const std::chrono::steady_clock::time_point now
251 );
252
253 /**
254 * @brief Find index of the largest OpenCV contour by area.
255 *
256 * @param contours Contours from OpenCV.
257 * @return Index of maximum-area contour, or std::nullopt if empty.
258 */
259 std::optional<size_t> find_largest_contour_index(
260 const std::vector<std::vector<cv::Point>>& contours
261 ) const;
262
263private:
264 /** @brief Mutex guarding all per-stream state. */
265 mutable std::mutex mtx;
266
267 /**
268 * @brief Previous blurred grayscale frame per stream.
269 *
270 * Used for frame differencing.
271 */
272 std::unordered_map<std::string, cv::Mat> prev_gray_by_stream;
273
274 /**
275 * @brief Last time a motion event was emitted per stream.
276 *
277 * Used for per-stream cooldown throttling.
278 */
279 std::unordered_map<std::string, std::chrono::steady_clock::time_point>
280 last_emit_by_stream;
281
282 /**
283 * @brief Last known motion centroid per stream.
284 *
285 * Used to infer tripwire crossing direction.
286 */
287 std::unordered_map<std::string, point> last_pos_by_stream;
288
289 /**
290 * @brief Last time a tripwire was emitted per (stream|line|direction) key.
291 *
292 * Used to enforce direction-specific tripwire cooldown.
293 */
294 std::unordered_map<std::string, std::chrono::steady_clock::time_point>
295 last_tripwire_by_key;
296};
297
298/**
299 * @brief Global OpenCV daemon start wrapper.
300 *
301 * This function forwards to a hidden global @ref opencv_client instance.
302 * It is provided for convenient use as a @ref stream_manager::daemon_start_fn.
303 *
304 * @param s Stream to capture.
305 * @param on_frame Callback invoked with captured frames.
306 * @param st Stop token.
307 */
308void opencv_daemon_start(
309 const stream& s, const std::function<void(frame&&)>& on_frame,
310 const std::stop_token& st
311);
312
313/**
314 * @brief Global OpenCV motion processor wrapper.
315 *
316 * This function forwards to a hidden global @ref opencv_client instance.
317 * It is provided for convenient use as a
318 * @ref stream_manager::frame_processor_fn.
319 *
320 * @param s Stream context.
321 * @param f Frame to analyze.
322 * @return Produced events.
323 */
324std::vector<event> opencv_motion_processor(const stream& s, const frame& f);
325
326} // namespace yodau::backend
327
328#endif // YODAU_OPENCV
329#endif // YODAU_BACKEND_OPENCV_CLIENT_HPP
Simple interactive CLI (REPL) for controlling a stream_manager.
void cmd_start_stream(const std::vector< std::string > &args) const
Handler for start-stream.
void dispatch_command(const std::string &cmd, const std::vector< std::string > &args) const
Dispatch a command to its handler.
void cmd_set_line(const std::vector< std::string > &args) const
Handler for set-line.
int run() const
Run the interactive command loop.
void cmd_add_line(const std::vector< std::string > &args) const
Handler for add-line.
static cxxopts::ParseResult parse_with_cxxopts(const std::string &cmd, const std::vector< std::string > &args, cxxopts::Options &options)
Parse command arguments using cxxopts.
backend::stream_manager & stream_mgr
Stream manager controlled by this CLI.
void cmd_stop_stream(const std::vector< std::string > &args) const
Handler for stop-stream.
void cmd_list_streams(const std::vector< std::string > &args) const
Handler for list-streams.
void cmd_add_stream(const std::vector< std::string > &args) const
Handler for add-stream.
void cmd_list_lines(const std::vector< std::string > &args) const
Handler for list-lines.
cli_client(backend::stream_manager &mgr)
Construct a CLI client operating on an existing manager.
Definition cli_client.cpp:5
static std::vector< std::string > tokenize(const std::string &line)
Split a line into whitespace-separated tokens.
Central coordinator for streams, geometry, frame processing and events.
std::function< void(const std::string &stream_name, frame &&f)> manual_push_fn
Hook for manual frame pushing.
Represents a single video stream and its analytic connections.
Definition stream.hpp:64
std::string get_name() const
Get logical stream name.
Definition stream.cpp:96
stream & operator=(stream &&other) noexcept
Move-assign a stream.
Definition stream.cpp:42
std::string name
Logical stream name.
Definition stream.hpp:222
std::vector< line_ptr > lines_snapshot() const
Get a snapshot of all connected lines.
Definition stream.cpp:154
void activate(stream_pipeline pipeline=stream_pipeline::automatic)
Activate the stream in a pipeline.
Definition stream.cpp:129
stream(std::string path, std::string name, const std::string &type_str={}, bool loop=true)
Construct a stream description.
Definition stream.cpp:5
stream & operator=(const stream &)=delete
Non-copyable (streams manage shared connections / mutex).
stream(stream &&other) noexcept
Move-construct a stream.
Definition stream.cpp:30
bool loop
Looping behavior for file streams.
Definition stream.hpp:231
void dump(std::ostream &out, bool connections=false) const
Dump stream metadata to an output stream.
Definition stream.cpp:106
std::vector< std::string > line_names() const
Get a list of names of all connected lines.
Definition stream.cpp:147
bool is_looping() const
Whether the stream is configured to loop on exhaustion.
Definition stream.cpp:104
void connect_line(line_ptr line)
Connect a geometric line to this stream.
Definition stream.cpp:139
stream_pipeline pipeline() const
Get current pipeline activity of the stream.
Definition stream.cpp:133
stream(const stream &)=delete
Non-copyable (streams manage shared connections / mutex).
std::unordered_map< std::string, line_ptr > lines
Connected lines keyed by their logical names.
Definition stream.hpp:241
void deactivate()
Deactivate the stream.
Definition stream.cpp:137
std::string path
Path or URL to the stream source.
Definition stream.hpp:225
static std::string type_name(const stream_type type)
Convert a stream type to a canonical textual name.
Definition stream.cpp:73
static stream_type identify(const std::string &path)
Identify stream type from a path/URL.
Definition stream.cpp:60
std::string get_path() const
Get stream path or URL.
Definition stream.cpp:98
stream_type get_type() const
Get the stream transport/source type.
Definition stream.cpp:100
stream_type type
Detected or user-specified stream type.
Definition stream.hpp:228
std::mutex lines_mtx
Mutex guarding lines.
Definition stream.hpp:244
static std::string pipeline_name(const stream_pipeline pipeline)
Convert a pipeline mode to its textual name.
Definition stream.cpp:85
stream_pipeline active
Currently active pipeline mode.
Definition stream.hpp:234
static yodau::backend::tripwire_dir parse_tripwire_dir(const std::string &s)
line_ptr make_line(std::vector< point > points, std::string name, bool closed=false)
Create and normalize a line.
Definition geometry.cpp:82
std::string normalize_str(std::string_view str)
Remove whitespace and parentheses from a string.
Definition geometry.cpp:133
std::vector< point > parse_points(const std::string &points_str)
Parse points from a textual representation.
Definition geometry.cpp:94
float parse_float(std::string_view num_str)
Parse a float from a string view.
Definition geometry.cpp:145
stream_pipeline
Processing pipeline mode for a stream.
Definition stream.hpp:40
std::shared_ptr< line const > line_ptr
Shared, immutable line pointer.
Definition geometry.hpp:146
event_kind
High-level classification of backend events.
Definition event.hpp:19
tripwire_dir
Allowed crossing direction for a tripwire.
Definition geometry.hpp:62
pixel_format
Pixel format of a frame buffer.
Definition frame.hpp:16
stream_type
Source/transport type of a video stream.
Definition stream.hpp:23
Generic event produced by the backend.
Definition event.hpp:44
std::chrono::steady_clock::time_point ts
Monotonic timestamp when the event was generated.
Definition event.hpp:70
event_kind kind
Type of the event.
Definition event.hpp:50
std::string stream_name
Name/identifier of the stream that produced the event.
Definition event.hpp:57
std::optional< point > pos_pct
Optional position associated with the event in percentage coordinates.
Definition event.hpp:79
std::string line_name
Name of the line / ROI / rule responsible for this event.
Definition event.hpp:86
std::string message
Human-readable event description or payload.
Definition event.hpp:65
Video frame container.
Definition frame.hpp:44
int width
Frame width in pixels.
Definition frame.hpp:48
int stride
Number of bytes per row.
Definition frame.hpp:60
int height
Frame height in pixels.
Definition frame.hpp:53
std::vector< std::uint8_t > data
Raw pixel bytes.
Definition frame.hpp:74
std::chrono::steady_clock::time_point ts
Monotonic timestamp when the frame was captured/produced.
Definition frame.hpp:79
pixel_format format
Pixel format of the buffer.
Definition frame.hpp:67
Polyline / polygon described in percentage coordinates.
Definition geometry.hpp:81
std::string name
Logical name of the line (e.g., "entrance_tripwire").
Definition geometry.hpp:85
tripwire_dir dir
Optional tripwire direction constraint.
Definition geometry.hpp:104
bool closed
Whether the chain is closed.
Definition geometry.hpp:97
void dump(std::ostream &out) const
Print a human-readable representation of the line.
Definition geometry.cpp:17
std::vector< point > points
Vertex list in percentage coordinates.
Definition geometry.hpp:90
void normalize()
Canonicalize point order.
Definition geometry.cpp:29
bool operator==(const line &other) const
Equality check using canonical point comparison.
Definition geometry.cpp:70
Point in percentage-based image coordinates.
Definition geometry.hpp:19
float distance_to(const point &other) const
Compute Euclidean distance to another point.
Definition geometry.cpp:7
float x
Horizontal coordinate (percentage of width).
Definition geometry.hpp:23
float y
Vertical coordinate (percentage of height).
Definition geometry.hpp:28
static constexpr float epsilon
Tolerance used for fuzzy point comparisons.
Definition geometry.hpp:33
bool compare(const point &other) const
Compare two points with tolerance epsilon.
Definition geometry.cpp:13