|
|
@@ -78,6 +78,25 @@ struct ChannelState {
|
|
|
bool alarm_latched = false; // 报警沿触发: 每次新报警只截一张
|
|
|
chrono::steady_clock::time_point last_alarm_ts{};
|
|
|
chrono::steady_clock::time_point episode_start{}; // 本回合报警开始时刻
|
|
|
+ // 每路独立推理器(多核并行时避免共享context冲突)
|
|
|
+ YoloDetector det_model;
|
|
|
+ PoseDetector pose_model;
|
|
|
+ bool det_loaded = false;
|
|
|
+ bool pose_loaded = false;
|
|
|
+ // 每路独立推理线程: 主循环提交RGB, worker在独立核上推理
|
|
|
+ std::thread infer_thread;
|
|
|
+ std::atomic<bool> infer_running{false};
|
|
|
+ std::atomic<bool> infer_pending{false}; // 有新RGB待推理
|
|
|
+ std::atomic<uint64_t> infer_seq{0}; // 推理请求序号
|
|
|
+ std::atomic<uint64_t> infer_done_seq{0}; // 已完成的推理序号
|
|
|
+ vector<float> infer_rgb; // worker待推理的RGB
|
|
|
+ float infer_scale = 1.0f;
|
|
|
+ int infer_pad_x = 0, infer_pad_y = 0;
|
|
|
+ int infer_w = 0, infer_h = 0;
|
|
|
+ mutex infer_mtx;
|
|
|
+ condition_variable infer_cv;
|
|
|
+ vector<Detection> infer_dets; // worker推理结果
|
|
|
+ vector<PersonPose> infer_poses;
|
|
|
mutex mtx;
|
|
|
};
|
|
|
|
|
|
@@ -90,6 +109,59 @@ static void saveJson(const string& path, const json& j) {
|
|
|
ofstream ofs(path); ofs << j.dump(4) << endl;
|
|
|
}
|
|
|
|
|
|
+// 每路推理 worker: 在独立线程/独立NPU核上循环推理
|
|
|
+static void channelInferLoop(ChannelState* ch, bool target_enabled,
|
|
|
+ bool pose_ok) {
|
|
|
+ while (ch->infer_running.load()) {
|
|
|
+ // 阻塞等待新的推理请求
|
|
|
+ {
|
|
|
+ std::unique_lock<std::mutex> lk(ch->infer_mtx);
|
|
|
+ ch->infer_cv.wait(lk, [&] {
|
|
|
+ return ch->infer_pending.load() || !ch->infer_running.load();
|
|
|
+ });
|
|
|
+ if (!ch->infer_running.load()) break;
|
|
|
+ ch->infer_pending.store(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ vector<Detection> dets;
|
|
|
+ vector<PersonPose> poses;
|
|
|
+ bool do_det = target_enabled && ch->det_loaded;
|
|
|
+ bool do_pose = (pose_ok && ch->pose_running && ch->pose_loaded);
|
|
|
+
|
|
|
+ if (do_det && do_pose) {
|
|
|
+ std::thread tPose([&]() {
|
|
|
+ poses = ch->pose_model.detect(ch->infer_rgb.data(),
|
|
|
+ ch->infer_w, ch->infer_h,
|
|
|
+ ch->infer_scale,
|
|
|
+ ch->infer_pad_x, ch->infer_pad_y);
|
|
|
+ });
|
|
|
+ dets = ch->det_model.detect(ch->infer_rgb.data(),
|
|
|
+ ch->infer_w, ch->infer_h,
|
|
|
+ ch->infer_scale,
|
|
|
+ ch->infer_pad_x, ch->infer_pad_y);
|
|
|
+ tPose.join();
|
|
|
+ } else if (do_det) {
|
|
|
+ dets = ch->det_model.detect(ch->infer_rgb.data(),
|
|
|
+ ch->infer_w, ch->infer_h,
|
|
|
+ ch->infer_scale,
|
|
|
+ ch->infer_pad_x, ch->infer_pad_y);
|
|
|
+ } else if (do_pose) {
|
|
|
+ poses = ch->pose_model.detect(ch->infer_rgb.data(),
|
|
|
+ ch->infer_w, ch->infer_h,
|
|
|
+ ch->infer_scale,
|
|
|
+ ch->infer_pad_x, ch->infer_pad_y);
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ lock_guard<mutex> lk(ch->infer_mtx);
|
|
|
+ ch->infer_dets = std::move(dets);
|
|
|
+ ch->infer_poses = std::move(poses);
|
|
|
+ ch->infer_done_seq.store(ch->infer_seq.load(std::memory_order_relaxed),
|
|
|
+ std::memory_order_relaxed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void buildFenceFill(cv::Mat& fill, const vector<FenceRegion>& fences,
|
|
|
const cv::Size& size, float s) {
|
|
|
fill = cv::Mat::zeros(size, CV_8UC3);
|
|
|
@@ -564,6 +636,23 @@ int main(int argc, char* argv[]) {
|
|
|
ch->pose_running = pose_ok; // 姿态识别默认开启(模型加载成功时)
|
|
|
ch->rga.init(input_size, input_size);
|
|
|
ch->capture = make_shared<RtspCapture>(id, url, name);
|
|
|
+ // 每路独立加载模型: 按通道id轮转分配NPU核(1=Core0 2=Core1 4=Core2)
|
|
|
+ static const int CORE_TABLE[3] = {1, 2, 4};
|
|
|
+ int core = CORE_TABLE[id % 3];
|
|
|
+ if (target_enabled) {
|
|
|
+ ch->det_loaded = ch->det_model.load(model_path, input_size,
|
|
|
+ conf_thresh, nms_thresh, core);
|
|
|
+ }
|
|
|
+ if (pose_enabled) {
|
|
|
+ ch->pose_loaded = ch->pose_model.load(pose_model_path, pose_input_size,
|
|
|
+ pose_conf_thresh, pose_nms_thresh, core);
|
|
|
+ }
|
|
|
+ // 启动每路独立推理线程
|
|
|
+ if (ch->det_loaded || ch->pose_loaded) {
|
|
|
+ ch->infer_running = true;
|
|
|
+ ch->infer_thread = std::thread(channelInferLoop, ch.get(),
|
|
|
+ target_enabled, pose_ok);
|
|
|
+ }
|
|
|
return ch;
|
|
|
};
|
|
|
auto registerChannelProviders = [&](shared_ptr<ChannelState> ch) {
|
|
|
@@ -1665,6 +1754,17 @@ int main(int argc, char* argv[]) {
|
|
|
auto last_cleanup = chrono::steady_clock::now();
|
|
|
auto last_rb_check = chrono::steady_clock::now() - chrono::seconds(20);
|
|
|
|
|
|
+ // 路间并行推理: 每路临时结果槽, 3个NPU核=3线程并行
|
|
|
+ struct InferSlot {
|
|
|
+ shared_ptr<ChannelState> ch;
|
|
|
+ vector<Detection> dets;
|
|
|
+ vector<PersonPose> poses;
|
|
|
+ bool do_det = false;
|
|
|
+ bool do_pose = false;
|
|
|
+ bool ready = false;
|
|
|
+ };
|
|
|
+ vector<InferSlot> infer_slots;
|
|
|
+
|
|
|
while (g_running.load()) {
|
|
|
this_thread::sleep_for(chrono::milliseconds(1));
|
|
|
|
|
|
@@ -1810,37 +1910,37 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
|
float scale = 1.0f;
|
|
|
int pad_x = 0, pad_y = 0;
|
|
|
- if (do_infer)
|
|
|
+ if (do_infer) {
|
|
|
ch->rga.process(nv12, ch->rgb_buf, scale, pad_x, pad_y);
|
|
|
+ }
|
|
|
|
|
|
- if (do_infer && !ch->rgb_buf.empty()) {
|
|
|
+ if (do_infer && !ch->rgb_buf.empty() && ch->infer_running.load()) {
|
|
|
if (ch->frame_count <= 4)
|
|
|
cout << "[CH" << ch->id << "] infer frame=" << ch->frame_count
|
|
|
<< " rgb=" << ch->rgb_buf.size() << endl;
|
|
|
|
|
|
- // 检测与姿态并行推理(不同NPU核), 缩短单帧处理时间
|
|
|
+ // 提交给独立推理线程(在各自NPU核上并行)
|
|
|
+ {
|
|
|
+ lock_guard<mutex> lk(ch->infer_mtx);
|
|
|
+ ch->infer_rgb = ch->rgb_buf;
|
|
|
+ ch->infer_scale = scale;
|
|
|
+ ch->infer_pad_x = pad_x;
|
|
|
+ ch->infer_pad_y = pad_y;
|
|
|
+ ch->infer_w = nv12.width;
|
|
|
+ ch->infer_h = nv12.height;
|
|
|
+ ch->infer_seq.fetch_add(1, std::memory_order_relaxed);
|
|
|
+ ch->infer_pending.store(true);
|
|
|
+ }
|
|
|
+ ch->infer_cv.notify_one();
|
|
|
+
|
|
|
+ // 若上一次推理已完成, 取回结果用于报警/显示
|
|
|
vector<Detection> dets;
|
|
|
vector<PersonPose> poses;
|
|
|
- bool do_det = target_enabled;
|
|
|
- bool do_pose = (pose_ok && ch->pose_running);
|
|
|
- if (do_det && do_pose) {
|
|
|
- std::thread tPose([&]() {
|
|
|
- poses = poseDetector.detect(ch->rgb_buf.data(),
|
|
|
- nv12.width, nv12.height,
|
|
|
- scale, pad_x, pad_y);
|
|
|
- });
|
|
|
- dets = detector.detect(ch->rgb_buf.data(),
|
|
|
- nv12.width, nv12.height,
|
|
|
- scale, pad_x, pad_y);
|
|
|
- tPose.join();
|
|
|
- } else if (do_det) {
|
|
|
- dets = detector.detect(ch->rgb_buf.data(),
|
|
|
- nv12.width, nv12.height,
|
|
|
- scale, pad_x, pad_y);
|
|
|
- } else if (do_pose) {
|
|
|
- poses = poseDetector.detect(ch->rgb_buf.data(),
|
|
|
- nv12.width, nv12.height,
|
|
|
- scale, pad_x, pad_y);
|
|
|
+ if (ch->infer_done_seq.load(std::memory_order_relaxed) >=
|
|
|
+ ch->infer_seq.load(std::memory_order_relaxed) - 1) {
|
|
|
+ lock_guard<mutex> lk(ch->infer_mtx);
|
|
|
+ dets = ch->infer_dets;
|
|
|
+ poses = ch->infer_poses;
|
|
|
}
|
|
|
|
|
|
vector<cv::Point2f> centers;
|
|
|
@@ -2122,7 +2222,25 @@ int main(int argc, char* argv[]) {
|
|
|
cout << "[Main] 正在退出..." << endl;
|
|
|
{
|
|
|
lock_guard<mutex> lk(channels_mtx);
|
|
|
- for (auto& ch : channels) ch->capture->stop();
|
|
|
+ for (auto& ch : channels) {
|
|
|
+ ch->capture->stop();
|
|
|
+ if (ch->infer_running.load()) {
|
|
|
+ ch->infer_running = false;
|
|
|
+ ch->infer_pending = false;
|
|
|
+ if (ch->infer_thread.joinable()) ch->infer_thread.join();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ {
|
|
|
+ lock_guard<mutex> lk(bucket_channels_mtx);
|
|
|
+ for (auto& ch : bucket_channels) {
|
|
|
+ ch->capture->stop();
|
|
|
+ if (ch->infer_running.load()) {
|
|
|
+ ch->infer_running = false;
|
|
|
+ ch->infer_pending = false;
|
|
|
+ if (ch->infer_thread.joinable()) ch->infer_thread.join();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
relay.stop(); // 先停继电器线程, 避免HTTP处理线程阻塞在transact上拖住web.stop()
|
|
|
web.stop();
|