safesight/edge/plugins/event_fusion/event_fusion_node.cpp
tian 29d9ef5d0d refactor: 项目结构梳理 - 设备端/管理端对称布局
仓库结构:
  edge/     设备端(原根目录设备端代码整体移入)
  control/  管理端(清理后)
  docs/     文档(PRD 移入 design/)
  README.md 根导航(新增)

清理:
- control/.brainstorm 临时草稿删除
- control 根级重复文档(API表/PRD_04)并入 docs/design/
- control/plan.md -> docs/implementation/control-plan.md
- control/safesightd-linux-arm64 二进制取消版本控制(.gitignore)
- edge/transform 模型转换产物归入 models/,onnx/pt 大源文件取消跟踪(.gitignore)
- Readme.md(PRD) -> docs/design/PRD_Product_v1.2.md(避开 README 大小写冲突)

更新:
- 根 README.md 导航、docs/README.md 文档索引
- deployment.md/检查表路径加 edge/ 前缀
- .gitignore 重写(edge/control 分区规则)
2026-08-02 11:39:54 +08:00

140 lines
3.6 KiB
C++

#include "event_fusion_node.h"
#include <algorithm>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "behavior/behavior_event.h"
namespace rk3588 {
namespace {
struct ActiveEvent {
int event_id = -1;
BehaviorEventItem last_item{};
bool seen_in_frame = false;
};
static std::string TypeName(BehaviorEventType type) {
switch (type) {
case BehaviorEventType::Intrusion: return "intrusion";
case BehaviorEventType::Climb: return "climb";
case BehaviorEventType::Fall: return "fall";
case BehaviorEventType::Fight: return "fight";
}
return "unknown";
}
static std::string MakeKey(const BehaviorEventItem& item) {
std::vector<int> track_ids = item.track_ids;
std::sort(track_ids.begin(), track_ids.end());
std::ostringstream oss;
oss << TypeName(item.type) << "|" << item.region_id << "|" << item.source;
for (int track_id : track_ids) {
oss << "|" << track_id;
}
return oss.str();
}
} // namespace
struct EventFusionNode::Impl {
int next_event_id = 1;
std::map<std::string, ActiveEvent> active_events;
};
EventFusionNode::EventFusionNode() : impl_(std::make_unique<Impl>()) {}
EventFusionNode::~EventFusionNode() = default;
std::string EventFusionNode::Id() const {
return id_;
}
std::string EventFusionNode::Type() const {
return "event_fusion";
}
bool EventFusionNode::Init(const SimpleJson& config, const NodeContext& ctx) {
id_ = config.ValueOr<std::string>("id", "event_fusion");
output_queues_ = ctx.output_queues;
return true;
}
bool EventFusionNode::Start() {
return true;
}
void EventFusionNode::Stop() {}
NodeStatus EventFusionNode::Process(FramePtr frame) {
if (!frame) return NodeStatus::DROP;
EnsureBehaviorEvents(*frame);
for (auto& [_, active] : impl_->active_events) {
active.seen_in_frame = false;
}
std::vector<BehaviorEventItem> normalized;
normalized.reserve(frame->behavior_events->items.size() + impl_->active_events.size());
for (auto item : frame->behavior_events->items) {
const std::string key = MakeKey(item);
auto& active = impl_->active_events[key];
if (active.event_id < 0) {
active.event_id = impl_->next_event_id++;
}
active.seen_in_frame = true;
item.event_id = active.event_id;
active.last_item = item;
normalized.push_back(std::move(item));
}
std::vector<std::string> to_remove;
for (auto& [key, active] : impl_->active_events) {
if (active.seen_in_frame) continue;
BehaviorEventItem ended = active.last_item;
ended.status = BehaviorEventStatus::Ended;
ended.event_id = active.event_id;
ended.last_pts = frame->pts;
if (frame->pts >= ended.start_pts) {
ended.duration_ms = frame->pts - ended.start_pts;
}
normalized.push_back(std::move(ended));
to_remove.push_back(key);
}
for (const auto& key : to_remove) {
impl_->active_events.erase(key);
}
frame->behavior_events->items = std::move(normalized);
PushToDownstream(frame);
return NodeStatus::OK;
}
void EventFusionNode::EnsureBehaviorEvents(Frame& frame) {
if (!frame.behavior_events) {
frame.behavior_events = std::make_shared<BehaviorEventResult>();
}
}
void EventFusionNode::PushToDownstream(const FramePtr& frame) {
for (auto& q : output_queues_) {
if (q) q->Push(frame);
}
}
#ifndef RK3588_TEST_BUILD
REGISTER_NODE(EventFusionNode, "event_fusion");
#endif
} // namespace rk3588