first commit
This commit is contained in:
5
nodes/ba/README.md
Normal file
5
nodes/ba/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## tips for BA node ##
|
||||
- behaviour analysis(short as BA) works dependently on tracking, all BA nodes Must attached after track node in pipeline.
|
||||
- all types of BA nodes support multi-channel, single instance of BA node supports multi channels as input.
|
||||
- all BA nodes can be divided into 2 categories, one is instantaneous(like crossline) and another one is continuous(like stop, jam). `vp_ba_type` contains pair member for continuous BA such as `STOP` and `UNSTOP`, which means target enter BA status and leave BA status.
|
||||
- there is no flag of BA inside `vp_frame_target` type, all nodes in pipeline need maintain it by themself if they want to know BA status for some task(like counter for crossline).
|
||||
124
nodes/ba/vp_ba_crossline_node.cpp
Normal file
124
nodes/ba/vp_ba_crossline_node.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
|
||||
#include "vp_ba_crossline_node.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
|
||||
vp_ba_crossline_node::vp_ba_crossline_node(std::string node_name,
|
||||
std::map<int, vp_objects::vp_line> lines,
|
||||
bool need_record_image,
|
||||
bool need_record_video):
|
||||
vp_node(node_name), all_lines(lines), need_record_image(need_record_image), need_record_video(need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] %s", node_name.c_str(), to_string().c_str()));
|
||||
this->initialized();
|
||||
}
|
||||
|
||||
vp_ba_crossline_node::~vp_ba_crossline_node() {
|
||||
deinitialized();
|
||||
}
|
||||
|
||||
std::string vp_ba_crossline_node::to_string() {
|
||||
/*
|
||||
* return 2 points of all lines
|
||||
* [channel 0: x1,y1 x2,y2][channel 1: x1,y1 x2,y2]...
|
||||
*/
|
||||
std::stringstream ss;
|
||||
for(auto& p: all_lines) {
|
||||
ss << "[channel" << p.first << ": " << p.second.start.x << "," << p.second.start.y << " " << p.second.end.x << "," << p.second.end.y << "]";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::shared_ptr<vp_objects::vp_meta> vp_ba_crossline_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
|
||||
// if need applied on current channel or not
|
||||
if (all_lines.count(meta->channel_index) == 0) {
|
||||
return meta;
|
||||
}
|
||||
|
||||
// for current channel
|
||||
auto& total_crossline = all_total_crossline[meta->channel_index];
|
||||
auto& line = all_lines[meta->channel_index];
|
||||
|
||||
// for vp_frame_target only
|
||||
for (auto& target : meta->targets) {
|
||||
auto len = target->tracks.size();
|
||||
std::vector<int> involve_targets;
|
||||
if (len > 1 && target->track_id >= 0) {
|
||||
// check the last 2 points in tracks
|
||||
auto p1 = target->tracks[len - 1].track_point();
|
||||
auto p2 = target->tracks[len - 2].track_point();
|
||||
|
||||
auto check1 = at_1_side_of_line(p1, line);
|
||||
auto check2 = at_1_side_of_line(p2, line);
|
||||
|
||||
// `true and false` or `false and true`
|
||||
// means target passed the line in current frame
|
||||
if (check1 ^ check2) {
|
||||
total_crossline++;
|
||||
involve_targets.push_back(target->track_id);
|
||||
|
||||
// not empty need fill ba result back to frame meta
|
||||
if (involve_targets.size() > 0) {
|
||||
// send record image and record video signal, recording actions would occur if record nodes exist in pipeline
|
||||
std::string image_file_name_without_ext = ""; // empty means no recording image
|
||||
std::string video_file_name_without_ext = ""; // empty means no recording video
|
||||
|
||||
// send image record control meta
|
||||
if (need_record_image) {
|
||||
image_file_name_without_ext = vp_utils::time_format(NOW, "crossline_image__<year><mon><day><hour><min><sec><mili>");
|
||||
auto image_record_control_meta = std::make_shared<vp_objects::vp_image_record_control_meta>(meta->channel_index, image_file_name_without_ext, true);
|
||||
pendding_meta(image_record_control_meta);
|
||||
}
|
||||
// send video record control meta
|
||||
if (need_record_video) {
|
||||
video_file_name_without_ext = vp_utils::time_format(NOW, "crossline_video__<year><mon><day><hour><min><sec><mili>");
|
||||
auto video_record_control_meta = std::make_shared<vp_objects::vp_video_record_control_meta>(meta->channel_index, video_file_name_without_ext);
|
||||
pendding_meta(video_record_control_meta);
|
||||
}
|
||||
|
||||
std::vector<vp_objects::vp_point> involve_region {line.start, line.end};
|
||||
auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::CROSSLINE,
|
||||
meta->channel_index,
|
||||
meta->frame_index,
|
||||
involve_targets,
|
||||
involve_region,
|
||||
"cross line", // meaningful label
|
||||
image_file_name_without_ext,
|
||||
video_file_name_without_ext);
|
||||
// fill back to frame meta
|
||||
meta->ba_results.push_back(ba_result);
|
||||
// info log
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] has found target cross line, total number of crossline: [%d]", node_name.c_str(), meta->channel_index, total_crossline));
|
||||
if (need_record_image || need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] image & video record file names are: [%s & %s]", node_name.c_str(), meta->channel_index, image_file_name_without_ext.c_str(), video_file_name_without_ext.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
bool vp_ba_crossline_node::at_1_side_of_line(vp_objects::vp_point p, vp_objects::vp_line line) {
|
||||
auto p1 = line.start;
|
||||
auto p2 = line.end;
|
||||
|
||||
if (p1.x == p2.x) {
|
||||
return p.x < p1.x;
|
||||
}
|
||||
|
||||
if (p1.y == p2.y) {
|
||||
return p.y < p1.y;
|
||||
}
|
||||
|
||||
if (p2.x < p1.x) {
|
||||
auto tmp = p2;
|
||||
p2 = p1;
|
||||
p1 = tmp;
|
||||
}
|
||||
|
||||
int ret = (p2.y - p.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p.x);
|
||||
return ret < 0;
|
||||
}
|
||||
}
|
||||
38
nodes/ba/vp_ba_crossline_node.h
Normal file
38
nodes/ba/vp_ba_crossline_node.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "../vp_node.h"
|
||||
#include "../../objects/shapes/vp_point.h"
|
||||
#include "../../objects/shapes/vp_line.h"
|
||||
#include "../../objects/vp_image_record_control_meta.h"
|
||||
#include "../../objects/vp_video_record_control_meta.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
// behaviour analysis node for crossline (support multi channels)
|
||||
class vp_ba_crossline_node: public vp_node
|
||||
{
|
||||
private:
|
||||
// channel -> counter
|
||||
std::map<int, int> all_total_crossline;
|
||||
|
||||
// channel -> line, 1 channel supports only 1 line at most (can be 0, which means no crossline check on this channel)
|
||||
std::map<int, vp_objects::vp_line> all_lines;
|
||||
|
||||
// record params
|
||||
bool need_record_image;
|
||||
bool need_record_video;
|
||||
|
||||
// check if point at one side of line
|
||||
bool at_1_side_of_line(vp_objects::vp_point p, vp_objects::vp_line line);
|
||||
protected:
|
||||
virtual std::shared_ptr<vp_objects::vp_meta> handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) override;
|
||||
public:
|
||||
vp_ba_crossline_node(std::string node_name,
|
||||
std::map<int, vp_objects::vp_line> lines,
|
||||
bool need_record_image = true,
|
||||
bool need_record_video = false);
|
||||
~vp_ba_crossline_node();
|
||||
|
||||
std::string to_string() override;
|
||||
};
|
||||
}
|
||||
180
nodes/ba/vp_ba_jam_node.cpp
Normal file
180
nodes/ba/vp_ba_jam_node.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
|
||||
|
||||
#include "vp_ba_jam_node.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
|
||||
vp_ba_jam_node::vp_ba_jam_node(std::string node_name,
|
||||
std::map<int, std::vector<vp_objects::vp_point>> jam_regions,
|
||||
bool need_record_image,
|
||||
bool need_record_video):
|
||||
vp_node(node_name), all_jam_regions(jam_regions), need_record_image(need_record_image), need_record_video(need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] %s", node_name.c_str(), to_string().c_str()));
|
||||
this->initialized();
|
||||
}
|
||||
|
||||
vp_ba_jam_node::~vp_ba_jam_node() {
|
||||
deinitialized();
|
||||
}
|
||||
|
||||
std::string vp_ba_jam_node::to_string() {
|
||||
/*
|
||||
* return vertexs of all jam regions
|
||||
* [channel0: x1,y1 x2,y2 ...][channel1: x1,y1 x2,y2 ...]...
|
||||
*/
|
||||
std::stringstream ss;
|
||||
for(auto& r: all_jam_regions) {
|
||||
ss << "[" << r.first << ":";
|
||||
for(auto& p: r.second) {
|
||||
ss << " " << p.x << "," << p.y;
|
||||
}
|
||||
ss << "]";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool vp_ba_jam_node::point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region) {
|
||||
int i, j, c = 0;
|
||||
int nvert = region.size();
|
||||
|
||||
for (i = 0, j = nvert-1; i < nvert; j = i++) {
|
||||
if (((region[i].y > p.y) != (region[j].y > p.y)) &&
|
||||
(p.x < (region[j].x - region[i].x) * (p.y - region[i].y)
|
||||
/ (region[j].y - region[i].y) + region[i].x))
|
||||
c = !c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::shared_ptr<vp_objects::vp_meta> vp_ba_jam_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
|
||||
// if need applied on current channel or not
|
||||
if (all_jam_regions.count(meta->channel_index) == 0) {
|
||||
return meta;
|
||||
}
|
||||
|
||||
// for current channel
|
||||
auto& jam_region = all_jam_regions[meta->channel_index];
|
||||
auto& stop_checking_status = all_stop_checking_status[meta->channel_index];
|
||||
auto& jam_result = all_jam_results[meta->channel_index];
|
||||
auto& last_notify = all_last_notifys[meta->channel_index];
|
||||
|
||||
// for vp_frame_target only
|
||||
std::vector<int> hit_traget_ids;
|
||||
for (auto& target : meta->targets) {
|
||||
auto len = target->tracks.size();
|
||||
auto loc = target->get_rect().track_point();
|
||||
|
||||
// target has been tracked AND tracked enough frames
|
||||
if (len < check_interval_frames || target->track_id < 0) {
|
||||
continue;
|
||||
}
|
||||
// if target inside of stop region or not
|
||||
if (!point_in_poly(loc, jam_region)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pre_loc = target->tracks[len - check_interval_frames].track_point();
|
||||
if (pre_loc.distance_with(loc) <= check_max_distance) {
|
||||
stop_checking_status[target->track_id]++;
|
||||
hit_traget_ids.push_back(target->track_id);
|
||||
}
|
||||
}
|
||||
|
||||
// count for stop targets
|
||||
auto stops = 0;
|
||||
std::vector<int> involve_targets;
|
||||
for (auto i = stop_checking_status.begin(); i != stop_checking_status.end();) {
|
||||
if (std::find(hit_traget_ids.begin(), hit_traget_ids.end(), i->first) == hit_traget_ids.end()) {
|
||||
// remove since it not satisfy stop condition
|
||||
i = stop_checking_status.erase(i);
|
||||
continue;
|
||||
}
|
||||
if (i->second >= check_min_hit_frames) {
|
||||
involve_targets.push_back(i->first);
|
||||
stops++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// enter jam status
|
||||
if (stops >= check_min_stops && !jam_result && (meta->frame_index - last_notify) > (check_notify_interval * meta->fps)) {
|
||||
jam_result = true;
|
||||
last_notify = meta->frame_index;
|
||||
|
||||
// send record image and record video signal, recording actions would occur if record nodes exist in pipeline
|
||||
std::string image_file_name_without_ext = ""; // empty means no recording image
|
||||
std::string video_file_name_without_ext = ""; // empty means no recording video
|
||||
|
||||
// send image record control meta
|
||||
if (need_record_image) {
|
||||
image_file_name_without_ext = vp_utils::time_format(NOW, "jam_image__<year><mon><day><hour><min><sec><mili>");
|
||||
auto image_record_control_meta = std::make_shared<vp_objects::vp_image_record_control_meta>(meta->channel_index, image_file_name_without_ext, true);
|
||||
pendding_meta(image_record_control_meta);
|
||||
}
|
||||
// send video record control meta
|
||||
if (need_record_video) {
|
||||
video_file_name_without_ext = vp_utils::time_format(NOW, "jam_video__<year><mon><day><hour><min><sec><mili>");
|
||||
auto video_record_control_meta = std::make_shared<vp_objects::vp_video_record_control_meta>(meta->channel_index, video_file_name_without_ext);
|
||||
pendding_meta(video_record_control_meta);
|
||||
}
|
||||
|
||||
std::vector<vp_objects::vp_point> involve_region = jam_region;
|
||||
auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::JAM,
|
||||
meta->channel_index,
|
||||
meta->frame_index,
|
||||
involve_targets,
|
||||
involve_region,
|
||||
"jam", // meaningful label
|
||||
image_file_name_without_ext,
|
||||
video_file_name_without_ext);
|
||||
// fill back to frame meta
|
||||
meta->ba_results.push_back(ba_result);
|
||||
// info log
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] has found jam", node_name.c_str(), meta->channel_index));
|
||||
if (need_record_image || need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] image & video record file names are: [%s & %s]", node_name.c_str(), meta->channel_index, image_file_name_without_ext.c_str(), video_file_name_without_ext.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// leave jam status
|
||||
if (stops < check_min_stops && jam_result) {
|
||||
jam_result = false;
|
||||
last_notify = meta->frame_index;
|
||||
|
||||
// send record image and record video signal, recording actions would occur if record nodes exist in pipeline
|
||||
std::string image_file_name_without_ext = ""; // empty means no recording image
|
||||
std::string video_file_name_without_ext = ""; // empty means no recording video
|
||||
|
||||
// send image record control meta
|
||||
if (need_record_image) {
|
||||
image_file_name_without_ext = vp_utils::time_format(NOW, "unjam_image__<year><mon><day><hour><min><sec><mili>");
|
||||
auto image_record_control_meta = std::make_shared<vp_objects::vp_image_record_control_meta>(meta->channel_index, image_file_name_without_ext, true);
|
||||
pendding_meta(image_record_control_meta);
|
||||
}
|
||||
// send video record control meta
|
||||
if (need_record_video) {
|
||||
video_file_name_without_ext = vp_utils::time_format(NOW, "unjam_video__<year><mon><day><hour><min><sec><mili>");
|
||||
auto video_record_control_meta = std::make_shared<vp_objects::vp_video_record_control_meta>(meta->channel_index, video_file_name_without_ext);
|
||||
pendding_meta(video_record_control_meta);
|
||||
}
|
||||
|
||||
std::vector<vp_objects::vp_point> involve_region = jam_region;
|
||||
auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::UNJAM,
|
||||
meta->channel_index,
|
||||
meta->frame_index,
|
||||
involve_targets,
|
||||
involve_region,
|
||||
"unjam", // meaningful label
|
||||
image_file_name_without_ext,
|
||||
video_file_name_without_ext);
|
||||
// fill back to frame meta
|
||||
meta->ba_results.push_back(ba_result);
|
||||
// info log
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] has found unjam", node_name.c_str(), meta->channel_index));
|
||||
if (need_record_image || need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] image & video record file names are: [%s & %s]", node_name.c_str(), meta->channel_index, image_file_name_without_ext.c_str(), video_file_name_without_ext.c_str()));
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
50
nodes/ba/vp_ba_jam_node.h
Normal file
50
nodes/ba/vp_ba_jam_node.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "../vp_node.h"
|
||||
#include "../../objects/shapes/vp_point.h"
|
||||
#include "../../objects/shapes/vp_line.h"
|
||||
#include "../../objects/vp_image_record_control_meta.h"
|
||||
#include "../../objects/vp_video_record_control_meta.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
// behaviour analysis node for stop (support multi channels)
|
||||
class vp_ba_jam_node: public vp_node
|
||||
{
|
||||
private:
|
||||
// channel -> vertexs of region, 1 channel supports only 1 region at most (can be 0, which means no jam check on this channel)
|
||||
std::map<int, std::vector<vp_objects::vp_point>> all_jam_regions;
|
||||
|
||||
// channel -> status of targets (id -> num of hit frames)
|
||||
std::map<int, std::map<int, int>> all_stop_checking_status;
|
||||
|
||||
// channel -> jam status of channel (jam or not)
|
||||
std::map<int, bool> all_jam_results;
|
||||
|
||||
// channel -> last frame index to notify jam
|
||||
std::map<int, int> all_last_notifys;
|
||||
|
||||
// record params
|
||||
bool need_record_image;
|
||||
bool need_record_video;
|
||||
|
||||
// check if point inside of polygon
|
||||
bool point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region);
|
||||
|
||||
// jam checking logic parameters which may be configed by constructor passed in by user
|
||||
const int check_interval_frames = 20;
|
||||
const int check_min_hit_frames = 25 * 2; // 25 fps * 2 seconds
|
||||
const int check_max_distance = 8;
|
||||
const int check_min_stops = 8;
|
||||
const int check_notify_interval = 10; // interval time (seconds) to notify (ensure not frequently)
|
||||
protected:
|
||||
virtual std::shared_ptr<vp_objects::vp_meta> handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) override;
|
||||
public:
|
||||
vp_ba_jam_node(std::string node_name,
|
||||
std::map<int, std::vector<vp_objects::vp_point>> jam_regions,
|
||||
bool need_record_image = true,
|
||||
bool need_record_video = true);
|
||||
~vp_ba_jam_node();
|
||||
std::string to_string() override;
|
||||
};
|
||||
}
|
||||
172
nodes/ba/vp_ba_stop_node.cpp
Normal file
172
nodes/ba/vp_ba_stop_node.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
|
||||
#include "vp_ba_stop_node.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
|
||||
vp_ba_stop_node::vp_ba_stop_node(std::string node_name,
|
||||
std::map<int, std::vector<vp_objects::vp_point>> stop_regions,
|
||||
bool need_record_image,
|
||||
bool need_record_video):
|
||||
vp_node(node_name), all_stop_regions(stop_regions), need_record_image(need_record_image), need_record_video(need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] %s", node_name.c_str(), to_string().c_str()));
|
||||
this->initialized();
|
||||
}
|
||||
|
||||
vp_ba_stop_node::~vp_ba_stop_node() {
|
||||
deinitialized();
|
||||
}
|
||||
|
||||
std::string vp_ba_stop_node::to_string() {
|
||||
/*
|
||||
* return vertexs of all stop regions
|
||||
* [channel0: x1,y1 x2,y2 ...][channel1: x1,y1 x2,y2 ...]...
|
||||
*/
|
||||
std::stringstream ss;
|
||||
for(auto& r: all_stop_regions) {
|
||||
ss << "[channel" << r.first << ":";
|
||||
for(auto& p: r.second) {
|
||||
ss << " " << p.x << "," << p.y;
|
||||
}
|
||||
ss << "]";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool vp_ba_stop_node::point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region) {
|
||||
int i, j, c = 0;
|
||||
int nvert = region.size();
|
||||
|
||||
for (i = 0, j = nvert-1; i < nvert; j = i++) {
|
||||
if (((region[i].y > p.y) != (region[j].y > p.y)) &&
|
||||
(p.x < (region[j].x - region[i].x) * (p.y - region[i].y)
|
||||
/ (region[j].y - region[i].y) + region[i].x))
|
||||
c = !c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::shared_ptr<vp_objects::vp_meta> vp_ba_stop_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
|
||||
// if need applied on current channel or not
|
||||
if (all_stop_regions.count(meta->channel_index) == 0) {
|
||||
return meta;
|
||||
}
|
||||
|
||||
// for current channel
|
||||
auto& stop_region = all_stop_regions[meta->channel_index];
|
||||
auto& stop_checking_status = all_stop_checking_status[meta->channel_index];
|
||||
|
||||
// for vp_frame_target only
|
||||
std::vector<int> hit_traget_ids;
|
||||
for (auto& target : meta->targets) {
|
||||
auto len = target->tracks.size();
|
||||
auto loc = target->get_rect().track_point();
|
||||
|
||||
// target has been tracked AND tracked enough frames
|
||||
if (len < check_interval_frames || target->track_id < 0) {
|
||||
continue;
|
||||
}
|
||||
// if target inside of stop region or not
|
||||
if (!point_in_poly(loc, stop_region)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pre_loc = target->tracks[len - check_interval_frames].track_point();
|
||||
if (pre_loc.distance_with(loc) <= check_max_distance) {
|
||||
stop_checking_status[target->track_id]++;
|
||||
hit_traget_ids.push_back(target->track_id);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = stop_checking_status.begin(); i != stop_checking_status.end();) {
|
||||
if (std::find(hit_traget_ids.begin(), hit_traget_ids.end(), i->first) == hit_traget_ids.end()) {
|
||||
// statisfy unstop condition
|
||||
if (i->second >= check_min_hit_frames) {
|
||||
std::vector<int> involve_targets;
|
||||
involve_targets.push_back(i->first);
|
||||
|
||||
// send record image and record video signal, recording actions would occur if record nodes exist in pipeline
|
||||
std::string image_file_name_without_ext = ""; // empty means no recording image
|
||||
std::string video_file_name_without_ext = ""; // empty means no recording video
|
||||
|
||||
// send image record control meta
|
||||
if (need_record_image) {
|
||||
image_file_name_without_ext = vp_utils::time_format(NOW, "unstop_image__<year><mon><day><hour><min><sec><mili>");
|
||||
auto image_record_control_meta = std::make_shared<vp_objects::vp_image_record_control_meta>(meta->channel_index, image_file_name_without_ext, true);
|
||||
pendding_meta(image_record_control_meta);
|
||||
}
|
||||
// send video record control meta
|
||||
if (need_record_video) {
|
||||
video_file_name_without_ext = vp_utils::time_format(NOW, "unstop_video__<year><mon><day><hour><min><sec><mili>");
|
||||
auto video_record_control_meta = std::make_shared<vp_objects::vp_video_record_control_meta>(meta->channel_index, video_file_name_without_ext);
|
||||
pendding_meta(video_record_control_meta);
|
||||
}
|
||||
|
||||
std::vector<vp_objects::vp_point> involve_region = stop_region;
|
||||
auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::UNSTOP,
|
||||
meta->channel_index,
|
||||
meta->frame_index,
|
||||
involve_targets,
|
||||
involve_region,
|
||||
"unstop", // meaningful label
|
||||
image_file_name_without_ext,
|
||||
video_file_name_without_ext);
|
||||
// fill back to frame meta
|
||||
meta->ba_results.push_back(ba_result);
|
||||
// info log
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] has found target unstop", node_name.c_str(), meta->channel_index));
|
||||
if (need_record_image || need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] image & video record file names are: [%s & %s]", node_name.c_str(), meta->channel_index, image_file_name_without_ext.c_str(), video_file_name_without_ext.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// remove since it not satisfy stop condition
|
||||
i = stop_checking_status.erase(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// equal means first time to satisfy stop condition
|
||||
if (i->second == check_min_hit_frames) {
|
||||
std::vector<int> involve_targets;
|
||||
involve_targets.push_back(i->first);
|
||||
|
||||
// send record image and record video signal, recording actions would occur if record nodes exist in pipeline
|
||||
std::string image_file_name_without_ext = ""; // empty means no recording image
|
||||
std::string video_file_name_without_ext = ""; // empty means no recording video
|
||||
|
||||
// send image record control meta
|
||||
if (need_record_image) {
|
||||
image_file_name_without_ext = vp_utils::time_format(NOW, "stop_image__<year><mon><day><hour><min><sec><mili>");
|
||||
auto image_record_control_meta = std::make_shared<vp_objects::vp_image_record_control_meta>(meta->channel_index, image_file_name_without_ext, true);
|
||||
pendding_meta(image_record_control_meta);
|
||||
}
|
||||
// send video record control meta
|
||||
if (need_record_video) {
|
||||
video_file_name_without_ext = vp_utils::time_format(NOW, "stop_video__<year><mon><day><hour><min><sec><mili>");
|
||||
auto video_record_control_meta = std::make_shared<vp_objects::vp_video_record_control_meta>(meta->channel_index, video_file_name_without_ext);
|
||||
pendding_meta(video_record_control_meta);
|
||||
}
|
||||
|
||||
std::vector<vp_objects::vp_point> involve_region = stop_region;
|
||||
auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::STOP,
|
||||
meta->channel_index,
|
||||
meta->frame_index,
|
||||
involve_targets,
|
||||
involve_region,
|
||||
"stop", // meaningful label
|
||||
image_file_name_without_ext,
|
||||
video_file_name_without_ext);
|
||||
// fill back to frame meta
|
||||
meta->ba_results.push_back(ba_result);
|
||||
// info log
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] has found target stop", node_name.c_str(), meta->channel_index));
|
||||
if (need_record_image || need_record_video) {
|
||||
VP_INFO(vp_utils::string_format("[%s] [channel %d] image & video record file names are: [%s & %s]", node_name.c_str(), meta->channel_index, image_file_name_without_ext.c_str(), video_file_name_without_ext.c_str()));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
42
nodes/ba/vp_ba_stop_node.h
Normal file
42
nodes/ba/vp_ba_stop_node.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "../vp_node.h"
|
||||
#include "../../objects/shapes/vp_point.h"
|
||||
#include "../../objects/shapes/vp_line.h"
|
||||
#include "../../objects/vp_image_record_control_meta.h"
|
||||
#include "../../objects/vp_video_record_control_meta.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
// behaviour analysis node for stop (support multi channels)
|
||||
class vp_ba_stop_node: public vp_node
|
||||
{
|
||||
private:
|
||||
// channel -> vertexs of region, 1 channel supports only 1 region at most (can be 0, which means no stop check on this channel)
|
||||
std::map<int, std::vector<vp_objects::vp_point>> all_stop_regions;
|
||||
|
||||
// channel -> status of targets (id -> num of hit frames)
|
||||
std::map<int, std::map<int, int>> all_stop_checking_status;
|
||||
|
||||
// record params
|
||||
bool need_record_image;
|
||||
bool need_record_video;
|
||||
|
||||
// check if point inside of polygon
|
||||
bool point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region);
|
||||
|
||||
// stop checking logic parameters which may be configed by constructor passed in by user
|
||||
const int check_interval_frames = 20;
|
||||
const int check_min_hit_frames = 25 * 2; // 25 fps * 2 seconds
|
||||
const int check_max_distance = 5;
|
||||
protected:
|
||||
virtual std::shared_ptr<vp_objects::vp_meta> handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) override;
|
||||
public:
|
||||
vp_ba_stop_node(std::string node_name,
|
||||
std::map<int, std::vector<vp_objects::vp_point>> stop_regions,
|
||||
bool need_record_image = true,
|
||||
bool need_record_video = true);
|
||||
~vp_ba_stop_node();
|
||||
std::string to_string() override;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user