From 8b0e31121a9a29b92a41fc575138a2e9b4c12d8e Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期六, 18 一月 2025 22:12:28 +0800
Subject: [PATCH] add person gathering

---
 nodes/ba/vp_ba_jam_node.h                                                          |    6 
 samples/from_argv_ba_jam_rtsp.cpp                                                  |  120 ++++
 nodes/ba/vp_ba_person_gathering_node.h                                             |   52 ++
 nodes/ba/vp_ba_wrong_direction_node.cpp                                            |  225 +++++++++
 nodes/ba/vp_ba_jam_node.cpp                                                        |   34 
 nodes/vp_infer_node.cpp                                                            |   21 
 samples/similiarity_search/face_encoding_pipeline                                  |    0 
 objects/ba/vp_ba_result.h                                                          |    5 
 samples/from_argv_ba_wrong_direction.cpp                                           |   78 +++
 samples/lpr_camera/plate_recognize_pipeline                                        |    0 
 samples/from_argv_ba_jam_rtsp_bak.cpp                                              |  127 +++++
 samples/vehicle_behaviour_analysis/vehicle_ba_pipeline                             |    0 
 samples/config.json                                                                |   28 +
 objects/vp_frame_target.h                                                          |    2 
 nodes/ba/vp_ba_person_gathering_node.cpp                                           |  163 ++++++
 nodes/vp_rtsp_src_node.h                                                           |    5 
 samples/vehicle_property_and_similiarity_search/vehicle_encoding_classify_pipeline |    0 
 samples/face_recognize/face_recognize_pipeline                                     |    0 
 nodes/vp_infer_node.h                                                              |    1 
 samples/CMakeLists.txt                                                             |   18 
 samples/from_argv_ba_stop_rtsp_d.cpp                                               |   82 +++
 nodes/ba/vp_ba_wrong_direction_node.h                                              |   60 ++
 samples/ba_stop_sample_rtsp.cpp                                                    |   52 ++
 samples/from_argv_ba_jam_rtsp_d.cpp                                                |   82 +++
 nodes/ba/vp_ba_person_falldown_node.cpp                                            |  136 +++++
 samples/from_argv_ba_person.cpp                                                    |   74 ++
 samples/from_argv_ba_stop_rtsp.cpp                                                 |   82 +++
 nodes/ba/vp_ba_person_falldown_node.h                                              |   47 +
 samples/similiarity_search/vehicle_encoding_pipeline                               |    0 
 29 files changed, 1,474 insertions(+), 26 deletions(-)

diff --git a/nodes/ba/vp_ba_jam_node.cpp b/nodes/ba/vp_ba_jam_node.cpp
index b34ca17..b4f2643 100644
--- a/nodes/ba/vp_ba_jam_node.cpp
+++ b/nodes/ba/vp_ba_jam_node.cpp
@@ -60,23 +60,23 @@
 
         // 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);
+        for (auto &target : meta->targets) {
+            if (target->primary_label != target->class_label_of_person) {
+                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);
+                }
             }
         }
 
diff --git a/nodes/ba/vp_ba_jam_node.h b/nodes/ba/vp_ba_jam_node.h
index 7048c3b..aa52b25 100644
--- a/nodes/ba/vp_ba_jam_node.h
+++ b/nodes/ba/vp_ba_jam_node.h
@@ -34,9 +34,9 @@
         // 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)
+        const int check_max_distance = 3;
+        const int check_min_stops = 1;
+        const int check_notify_interval = 15;  // 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:
diff --git a/nodes/ba/vp_ba_person_falldown_node.cpp b/nodes/ba/vp_ba_person_falldown_node.cpp
new file mode 100644
index 0000000..5663362
--- /dev/null
+++ b/nodes/ba/vp_ba_person_falldown_node.cpp
@@ -0,0 +1,136 @@
+
+
+#include "vp_ba_person_falldown_node.h"
+
+namespace vp_nodes
+{
+
+    vp_ba_person_falldown_node::vp_ba_person_falldown_node(std::string node_name,
+                                                           bool need_record_image,
+                                                           bool need_record_video) : vp_node(node_name), 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_person_falldown_node::~vp_ba_person_falldown_node()
+    {
+        deinitialized();
+    }
+
+    std::string vp_ba_person_falldown_node::to_string()
+    {
+        /*
+         * return vertexs of all jam regions
+         * [channel0: x1,y1 x2,y2 ...][channel1: x1,y1 x2,y2 ...]...
+         */
+       
+        return "vp_ba_person_falldown_node";
+    }
+
+    bool vp_ba_person_falldown_node::isPersonFallen(int person_width, int person_height, float fallThreshold)
+    {
+        return (person_height / person_width) < fallThreshold; // 璺屽�掑垽鏂潯浠�
+    }
+      
+
+    std::shared_ptr<vp_objects::vp_meta> vp_ba_person_falldown_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta)
+    {
+        // for current channel
+        auto &person_falldown_checking_status = all_person_falldown_checking_status[meta->channel_index];
+        auto &person_falldown_result = all_person_falldown_results[meta->channel_index];
+        auto &last_notify = all_last_notifys[meta->channel_index];
+
+        // for vp_frame_target only
+        // for vp_frame_target only
+        std::vector<int> hit_traget_ids;
+        for (auto &target : meta->targets)
+        {
+            if (target->primary_label == target->class_label_of_person)
+            {
+                auto len = target->tracks.size();
+
+                // 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;
+                //}
+                if (isPersonFallen(target->width,target->height,person_fall_down_threshold))
+                {
+                    person_falldown_checking_status[target->track_id]++;
+                    hit_traget_ids.push_back(target->track_id);
+                }
+            }
+        }
+        std::vector<int> involve_targets;
+        for (auto i = person_falldown_checking_status.begin(); i != person_falldown_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 = person_falldown_checking_status.erase(i);
+                continue;
+            }
+            if (i->second >= check_min_hit_frames)
+            {
+                involve_targets.push_back(i->first);
+            }
+            i++;
+        }
+        VP_INFO(std::to_string(involve_targets.size()));
+
+
+        if (involve_targets.size() > 0 && (meta->frame_index - last_notify) > (check_notify_interval * meta->fps))
+        {
+            person_falldown_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, "person_falldown_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, "person_falldown_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;
+            auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::FALLDOWN,
+                                                                        meta->channel_index,
+                                                                        meta->frame_index,
+                                                                        involve_targets,
+                                                                        involve_region,
+                                                                        "person_falldown", // 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 person falldown.", 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()));
+            }
+        }
+        if (involve_targets.size() == 0 && person_falldown_result)
+        {
+            person_falldown_result = false;
+            last_notify = meta->frame_index;
+        }
+        return meta;
+    }
+}
\ No newline at end of file
diff --git a/nodes/ba/vp_ba_person_falldown_node.h b/nodes/ba/vp_ba_person_falldown_node.h
new file mode 100644
index 0000000..95ee84e
--- /dev/null
+++ b/nodes/ba/vp_ba_person_falldown_node.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <map>
+#include <algorithm>
+#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_person_falldown_node: public vp_node 
+    {
+    private:
+        // channel -> status of targets (id -> num of hit frames)
+        std::map<int, std::map<int, int>> all_person_falldown_checking_status;
+
+        // channel -> jam status of channel (jam or not)
+        std::map<int, bool> all_person_falldown_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;
+
+        bool isPersonFallen(int person_width, int person_height,float fallThreshold) ;
+
+        float person_fall_down_threshold = 1.5f;
+
+        // jam checking logic parameters which may be configed by constructor passed in by user
+        const int check_interval_frames = 1;
+        const int check_min_hit_frames = 2 * 1;  // 25 fps * 2 seconds
+  
+        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_person_falldown_node(std::string node_name, 
+                            bool need_record_image = true,
+                            bool need_record_video = true);
+        ~vp_ba_person_falldown_node();
+        std::string to_string() override;
+    };
+}
\ No newline at end of file
diff --git a/nodes/ba/vp_ba_person_gathering_node.cpp b/nodes/ba/vp_ba_person_gathering_node.cpp
new file mode 100644
index 0000000..22113b3
--- /dev/null
+++ b/nodes/ba/vp_ba_person_gathering_node.cpp
@@ -0,0 +1,163 @@
+
+
+#include "vp_ba_person_gathering_node.h"
+
+namespace vp_nodes
+{
+
+    vp_ba_person_gathering_node::vp_ba_person_gathering_node(std::string node_name,
+                                                             int min_gathering_person,
+                                                             bool need_record_image,
+                                                             bool need_record_video) : vp_node(node_name), min_gathering_person(min_gathering_person), 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_person_gathering_node::~vp_ba_person_gathering_node()
+    {
+        deinitialized();
+    }
+
+    std::string vp_ba_person_gathering_node::to_string()
+    {
+        /*
+         * return vertexs of all jam regions
+         * [channel0: x1,y1 x2,y2 ...][channel1: x1,y1 x2,y2 ...]...
+         */
+
+        return "vp_ba_person_gathering_node";
+    }
+
+    bool vp_ba_person_gathering_node::isNearby(int p1_width, int p1_x, int p1_y, int p2_width, int p2_x, int p2_y, float factor)
+    {
+        // 鍔ㄦ�佽窛绂绘牴鎹搴﹁绠�
+        float dynamicDistance = std::max(p1_width, p2_width) * factor;
+
+        // 娆у嚑閲屽緱璺濈璁$畻
+        float dx = p1_x - p2_x;
+        float dy = p1_y - p2_y;
+        float distance = std::sqrt(dx * dx + dy * dy);
+
+        return distance < dynamicDistance;
+    }
+
+    std::shared_ptr<vp_objects::vp_meta> vp_ba_person_gathering_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta)
+    {
+        // for current channel
+        auto &person_gathering_checking_status = all_person_gathering_checking_status[meta->channel_index];
+        auto &person_gathering_result = all_person_gathering_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)
+        {
+            if (target->primary_label == target->class_label_of_person)
+            {
+                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;
+                //}
+
+                bool is_this_target_gathering= false;
+
+                for (auto &tempTarget : meta->targets)
+                {
+
+                    if (isNearby(target->width, target->x, target->y, tempTarget->width, tempTarget->x, tempTarget->y, person_gathering_distance_factor))
+                    {
+                        is_this_target_gathering = true;
+                        //person_gathering_checking_status[target->track_id]++;
+                        //hit_traget_ids.push_back(target->track_id);
+                    }
+                }
+                if (is_this_target_gathering)
+                {
+                    person_gathering_checking_status[target->track_id]++;
+                    hit_traget_ids.push_back(target->track_id);
+
+                }
+            }
+        }
+
+        // count for stop targets
+        auto personGathers = 0;
+        std::vector<int> involve_targets;
+        for (auto i = person_gathering_checking_status.begin(); i != person_gathering_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 = person_gathering_checking_status.erase(i);
+                continue;
+            }
+            if (i->second >= check_min_hit_frames)
+            {
+                involve_targets.push_back(i->first);
+                personGathers++;
+            }
+            i++;
+        }
+        VP_INFO(std::to_string(involve_targets.size()));
+
+
+
+        if (personGathers >= min_gathering_person && !person_gathering_result && (meta->frame_index - last_notify) > (check_notify_interval * meta->fps))
+        {
+            person_gathering_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, "person_gathering_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, "person_gathering_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;
+            auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::GATHERING,
+                                                                        meta->channel_index,
+                                                                        meta->frame_index,
+                                                                        involve_targets,
+                                                                        involve_region,
+                                                                        "person_gathering", // 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 person falldown.", 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()));
+            }
+        }
+        if (personGathers < min_gathering_person && person_gathering_result)
+        {
+            person_gathering_result = false;
+            last_notify = meta->frame_index;
+        }
+        return meta;
+    }
+}
\ No newline at end of file
diff --git a/nodes/ba/vp_ba_person_gathering_node.h b/nodes/ba/vp_ba_person_gathering_node.h
new file mode 100644
index 0000000..08c0c67
--- /dev/null
+++ b/nodes/ba/vp_ba_person_gathering_node.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <map>
+#include <algorithm>
+#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_person_gathering_node : public vp_node
+    {
+    private:
+        // channel -> status of targets (id -> num of hit frames)
+        std::map<int, std::map<int, int>> all_person_gathering_checking_status;
+
+        // channel -> jam status of channel (jam or not)
+        std::map<int, bool> all_person_gathering_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;
+
+        bool isNearby(int p1_width, int p1_x, int p1_y, int p2_width, int p2_x, int p2_y, float factor);
+
+        float person_gathering_distance_factor = 4.0f;
+
+        // jam checking logic parameters which may be configed by constructor passed in by user
+        const int check_interval_frames = 1;
+        const int check_min_hit_frames = 1 * 1; // 25 fps * 2 seconds
+
+        int min_gathering_person = 3;
+
+        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_person_gathering_node(std::string node_name,
+                                    int min_gathering_person,
+                                    bool need_record_image = true,
+                                    bool need_record_video = true);
+        ~vp_ba_person_gathering_node();
+        std::string to_string() override;
+    };
+}
\ No newline at end of file
diff --git a/nodes/ba/vp_ba_wrong_direction_node.cpp b/nodes/ba/vp_ba_wrong_direction_node.cpp
new file mode 100644
index 0000000..a6374df
--- /dev/null
+++ b/nodes/ba/vp_ba_wrong_direction_node.cpp
@@ -0,0 +1,225 @@
+
+
+#include "vp_ba_wrong_direction_node.h"
+
+namespace vp_nodes
+{
+
+    vp_ba_wrong_direction_node::vp_ba_wrong_direction_node(std::string node_name,
+                                                           std::map<int, std::vector<vp_objects::vp_point>> left_lines,
+                                                           std::map<int, std::vector<vp_objects::vp_point>> right_lines,
+                                                           int half_width,
+                                                           bool need_record_image,
+                                                           bool need_record_video) : vp_node(node_name), all_left_lines(left_lines), all_right_lines(right_lines), half_width(half_width),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_wrong_direction_node::~vp_ba_wrong_direction_node()
+    {
+        deinitialized();
+    }
+
+    std::string vp_ba_wrong_direction_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_left_lines)
+        {
+            ss << "[" << r.first << ":";
+            for (auto &p : r.second)
+            {
+                ss << " " << p.x << "," << p.y;
+            }
+            ss << "]";
+        }
+        return ss.str();
+    }
+
+    bool vp_ba_wrong_direction_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;
+    }
+
+    bool vp_ba_wrong_direction_node::check_wrong_direction(std::vector<vp_objects::vp_point> test_line, std::vector<vp_objects::vp_point> right_line, double angle_tolerance = 30.0)
+    {
+        if (test_line.size() != 2 || right_line.size() != 2)
+        {
+            // 绾挎蹇呴』鐢变袱涓偣缁勬垚
+            return false;
+        }
+
+        // 璁$畻 test_line 鐨勬柟鍚戝悜閲�
+        double dx_test = test_line[1].x - test_line[0].x;
+        double dy_test = test_line[1].y - test_line[0].y;
+
+        // 璁$畻 right_line 鐨勬柟鍚戝悜閲�
+        double dx_right = right_line[1].x - right_line[0].x;
+        double dy_right = right_line[1].y - right_line[0].y;
+
+        // 璁$畻涓や釜鍚戦噺鐨勬ā
+        double magnitude_test = std::sqrt(dx_test * dx_test + dy_test * dy_test);
+        double magnitude_right = std::sqrt(dx_right * dx_right + dy_right * dy_right);
+
+        if (magnitude_test == 0 || magnitude_right == 0)
+        {
+            // 濡傛灉鏌愭潯绾挎鐨勯暱搴︿负闆讹紝鍒欐棤娉曟瘮杈冩柟鍚�
+            return false;
+        }
+
+        // 褰掍竴鍖栨柟鍚戝悜閲�
+        dx_test /= magnitude_test;
+        dy_test /= magnitude_test;
+
+        dx_right /= magnitude_right;
+        dy_right /= magnitude_right;
+
+        // 璁$畻涓や釜鍚戦噺鐨勫す瑙掍綑寮﹀��
+        double dot_product = dx_test * dx_right + dy_test * dy_right;
+
+        // 灏嗕綑寮﹀�奸檺鍒跺湪 -1 鍒� 1 鐨勮寖鍥村唴锛堥槻姝㈣绠楄宸級
+        dot_product = std::max(-1.0, std::min(1.0, dot_product));
+
+        // 璁$畻澶硅锛堝姬搴﹀埗锛�
+        double angle_rad = std::acos(dot_product);
+
+        // 灏嗗す瑙掕浆鎹负瑙掑害鍒�
+        double angle_deg = angle_rad * 180.0 / 3.1415926;
+
+        // 鍒ゆ柇澶硅鏄惁鍦ㄥ厑璁哥殑鑼冨洿鍐�
+        return angle_deg > angle_tolerance;
+    }
+
+    std::shared_ptr<vp_objects::vp_meta> vp_ba_wrong_direction_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta)
+    {
+        // if need applied on current channel or not
+        if (all_left_lines.count(meta->channel_index) == 0 || all_right_lines.count(meta->channel_index) == 0)
+        {
+            return meta;
+        }
+
+        // for current channel
+        // auto &jam_region = all_jam_regions[meta->channel_index];
+        auto &left_line = all_left_lines[meta->channel_index];
+        auto &right_line = all_right_lines[meta->channel_index];
+
+        auto &wrong_direction_checking_status = all_wrong_direction_checking_status[meta->channel_index];
+        auto &wrong_direction_result = all_wrong_direction_results[meta->channel_index];
+        auto &last_notify = all_last_notifys[meta->channel_index];
+
+        // for vp_frame_target only
+        // for vp_frame_target only
+        std::vector<int> hit_traget_ids;
+        for (auto &target : meta->targets)
+        {
+            if (target->primary_label != target->class_label_of_person)
+            {
+                auto len = target->tracks.size();
+
+                // 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;
+                //}
+                if (len > 2 && 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 鑷姩鎺ㄥ绫诲瀷
+                    auto test_line = {p2, p1};
+
+                    auto is_wrong_direction = (p1.x < half_width) ? check_wrong_direction(test_line, left_line) : check_wrong_direction(test_line, right_line);
+
+                    if (is_wrong_direction)
+                    {
+                        wrong_direction_checking_status[target->track_id]++;
+                        hit_traget_ids.push_back(target->track_id);
+                    }
+                }
+            }
+        }
+        std::vector<int> involve_targets;
+        for (auto i = wrong_direction_checking_status.begin(); i != wrong_direction_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 = wrong_direction_checking_status.erase(i);
+                continue;
+            }
+            if (i->second >= check_min_hit_frames)
+            {
+                involve_targets.push_back(i->first);
+            }
+            i++;
+        }
+        if (involve_targets.size() > 0 && (meta->frame_index - last_notify) > (check_notify_interval * meta->fps))
+        {
+            wrong_direction_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, "wrong_direction_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, "wrong_direction_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::WRONGDIRECTION,
+                                                                        meta->channel_index,
+                                                                        meta->frame_index,
+                                                                        involve_targets,
+                                                                        // involve_region,
+                                                                        left_line,
+                                                                        "wrong_direction", // 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 wrong direction.", 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()));
+            }
+        }
+        if (involve_targets.size() == 0 && wrong_direction_result)
+        {
+            wrong_direction_result = false;
+            last_notify = meta->frame_index;
+        }
+        return meta;
+    }
+}
\ No newline at end of file
diff --git a/nodes/ba/vp_ba_wrong_direction_node.h b/nodes/ba/vp_ba_wrong_direction_node.h
new file mode 100644
index 0000000..b7b0a7c
--- /dev/null
+++ b/nodes/ba/vp_ba_wrong_direction_node.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <map>
+#include <algorithm>
+#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_wrong_direction_node: public vp_node 
+    {
+    private:
+        // channel -> vertexs of line, 1 channel supports only 1 left line at most (can be 0, which means no jam check on this channel)
+        std::map<int, std::vector<vp_objects::vp_point>> all_left_lines;
+
+        // channel -> vertexs of region, 1 channel supports only 1 right line at most (can be 0, which means no jam check on this channel)
+        std::map<int, std::vector<vp_objects::vp_point>> all_right_lines;
+
+        // channel -> status of targets (id -> num of hit frames)
+        std::map<int, std::map<int, int>> all_wrong_direction_checking_status;
+
+        // channel -> jam status of channel (jam or not)
+        std::map<int, bool> all_wrong_direction_results;
+
+        // channel -> last frame index to notify jam
+        std::map<int, int> all_last_notifys;
+
+        int half_width = 320;
+
+        // 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);
+
+        // check if direction is in right direction
+        bool check_wrong_direction(std::vector<vp_objects::vp_point> test_line, std::vector<vp_objects::vp_point> right_line,double angle_tolerance);
+
+        // jam checking logic parameters which may be configed by constructor passed in by user
+        const int check_interval_frames = 5;
+        const int check_min_hit_frames = 25 * 1;  // 25 fps * 2 seconds
+  
+        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_wrong_direction_node(std::string node_name, 
+                            std::map<int, std::vector<vp_objects::vp_point>> all_left_lines,
+                            std::map<int, std::vector<vp_objects::vp_point>> all_right_lines,
+                            int half_width,
+                            bool need_record_image = true,
+                            bool need_record_video = true);
+        ~vp_ba_wrong_direction_node();
+        std::string to_string() override;
+    };
+}
\ No newline at end of file
diff --git a/nodes/vp_infer_node.cpp b/nodes/vp_infer_node.cpp
index cc86d8e..099f392 100644
--- a/nodes/vp_infer_node.cpp
+++ b/nodes/vp_infer_node.cpp
@@ -1,6 +1,6 @@
 
 #include <fstream>
-
+#include <opencv2/core/cuda.hpp>
 #include "vp_infer_node.h"
 
 namespace vp_nodes {
@@ -35,8 +35,23 @@
         try {
             net = cv::dnn::readNet(model_path, model_config_path);
             #ifdef VP_WITH_CUDA
-            net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
-            net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
+            // net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
+            // net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
+            // 妫�鏌ュ彲鐢ㄧ殑 GPU 鏁伴噺
+            int gpu_count = cv::cuda::getCudaEnabledDeviceCount();
+            if (gpu_count > 0) {
+                // 鍒濆鍖栭殢鏈烘暟绉嶅瓙骞堕殢鏈洪�夋嫨涓�涓� GPU
+                std::srand(static_cast<unsigned>(std::time(nullptr)));
+                int selected_gpu = std::rand() % gpu_count;
+                // 璁剧疆 CUDA 璁惧骞堕厤缃负浣跨敤鎸囧畾 GPU
+                cv::cuda::setDevice(selected_gpu);
+                net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
+                net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
+
+                VP_INFO(vp_utils::string_format("[%s] Using CUDA on GPU %d", node_name.c_str(), selected_gpu));
+            } else {
+                VP_WARN(vp_utils::string_format("[%s] No CUDA-enabled GPUs detected. Running on CPU.", node_name.c_str()));
+            }
             #endif
         }
         catch(const std::exception& e) {
diff --git a/nodes/vp_infer_node.h b/nodes/vp_infer_node.h
index a05c21b..cc2bfb4 100644
--- a/nodes/vp_infer_node.h
+++ b/nodes/vp_infer_node.h
@@ -2,6 +2,7 @@
 
 #pragma once
 #include <sstream>
+#include <opencv2/core/cuda.hpp>
 #include <opencv2/dnn.hpp>
 #include "vp_node.h"
 
diff --git a/nodes/vp_rtsp_src_node.h b/nodes/vp_rtsp_src_node.h
index 15f9e18..89f0854 100644
--- a/nodes/vp_rtsp_src_node.h
+++ b/nodes/vp_rtsp_src_node.h
@@ -11,8 +11,9 @@
     class vp_rtsp_src_node: public vp_src_node {
     private:
         /* data */
-        std::string gst_template = "rtspsrc location=%s ! application/x-rtp,media=video ! rtph264depay ! h264parse ! %s ! videoconvert ! appsink";
-        cv::VideoCapture rtsp_capture;
+        //std::string gst_template = "rtspsrc location=%s ! application/x-rtp,media=video ! rtph264depay ! h264parse ! %s ! videoconvert ! appsink";
+        std::string gst_template = "rtspsrc location=%s ! rtph264depay ! h264parse ! %s ! videoconvert ! appsink";
+       cv::VideoCapture rtsp_capture;
     protected:
         // re-implemetation
         virtual void handle_run() override;
diff --git a/objects/ba/vp_ba_result.h b/objects/ba/vp_ba_result.h
index 8a240ec..3d407f0 100644
--- a/objects/ba/vp_ba_result.h
+++ b/objects/ba/vp_ba_result.h
@@ -14,7 +14,10 @@
         STOP = 0b00000010,       // enter stop status
         UNSTOP = 0b00000100,     // leave stop status
         JAM = 0b00001000,        // enter jam status
-        UNJAM = 0b00010000       // leave jam status
+        UNJAM = 0b00010000,      // leave jam status
+        GATHERING = 0b00100000,
+        FALLDOWN = 0b01000000,
+        WRONGDIRECTION =0b10000000
         /* more */
     };
 
diff --git a/objects/vp_frame_target.h b/objects/vp_frame_target.h
index 507239e..5dd262b 100644
--- a/objects/vp_frame_target.h
+++ b/objects/vp_frame_target.h
@@ -44,6 +44,8 @@
         float primary_score;
         // label created by primary infer nodes
         std::string primary_label;
+        // class id of person
+        std::string class_label_of_person = "person";
 
         // frame the target belongs to
         int frame_index;
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index 65ac10a..312ee6b 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -109,6 +109,24 @@
 add_executable(vp_test "vp_test.cpp")
 target_link_libraries(vp_test ${PROJECT_NAME})
 
+add_executable(from_argv_ba_wrong_direction "from_argv_ba_wrong_direction.cpp")
+target_link_libraries(from_argv_ba_wrong_direction ${PROJECT_NAME})
+
+add_executable(from_argv_ba_person "from_argv_ba_person.cpp")
+target_link_libraries(from_argv_ba_person ${PROJECT_NAME})
+
+add_executable(from_argv_ba_jam_rtsp "from_argv_ba_jam_rtsp.cpp")
+target_link_libraries(from_argv_ba_jam_rtsp ${PROJECT_NAME})
+
+add_executable(from_argv_ba_stop_rtsp "from_argv_ba_stop_rtsp.cpp")
+target_link_libraries(from_argv_ba_stop_rtsp ${PROJECT_NAME})
+
+add_executable(from_argv_ba_jam_rtsp_d "from_argv_ba_jam_rtsp_d.cpp")
+target_link_libraries(from_argv_ba_jam_rtsp_d ${PROJECT_NAME})
+
+add_executable(from_argv_ba_stop_rtsp_d "from_argv_ba_stop_rtsp_d.cpp")
+target_link_libraries(from_argv_ba_stop_rtsp_d ${PROJECT_NAME})
+
 # samples depend on Kafka
 if(VP_WITH_KAFKA)
     add_executable(message_broker_kafka_sample "message_broker_kafka_sample.cpp")
diff --git a/samples/ba_stop_sample_rtsp.cpp b/samples/ba_stop_sample_rtsp.cpp
new file mode 100644
index 0000000..5df3d36
--- /dev/null
+++ b/samples/ba_stop_sample_rtsp.cpp
@@ -0,0 +1,52 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/infers/vp_trt_vehicle_detector.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_stop_node.h"
+#include "../nodes/osd/vp_ba_stop_osd_node.h"
+#include "../nodes/vp_split_node.h"
+#include "../nodes/vp_screen_des_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+/*
+* ## ba stop sample ##
+* behaviour analysis for stop, single instance of ba node work on 2 channels.
+*/
+
+int main() {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+
+    // create nodes
+    auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, "./vp_data/test_video/vehicle_stop.mp4", 0.6);
+    auto file_src_1 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_1", 1, "./vp_data/test_video/vehicle_stop.mp4", 0.6);
+    auto trt_vehicle_detector = std::make_shared<vp_nodes::vp_trt_vehicle_detector>("vehicle_detector", "./vp_data//models/trt/vehicle/vehicle_detection.trt");
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+    
+    // define a region in frame for every channel (value MUST in the scope of frame'size)
+    std::map<int, std::vector<vp_objects::vp_point>> regions = {
+        {0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(20, 30), vp_objects::vp_point(600, 40), vp_objects::vp_point(600, 300), vp_objects::vp_point(10, 300)}},  // channel0 -> region
+        {1, std::vector<vp_objects::vp_point>{vp_objects::vp_point(20, 30), vp_objects::vp_point(1000, 40), vp_objects::vp_point(1000, 600), vp_objects::vp_point(10, 600)}}   // channel1 -> region
+    };
+    auto ba_stop = std::make_shared<vp_nodes::vp_ba_stop_node>("ba_stop", regions);
+    auto osd = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd");
+    auto split = std::make_shared<vp_nodes::vp_split_node>("split", true);
+    auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
+    auto screen_des_1 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_1", 1);
+    
+    // construct pipeline
+    trt_vehicle_detector->attach_to({file_src_0, file_src_1});
+    tracker->attach_to({trt_vehicle_detector});
+    ba_stop->attach_to({tracker});
+    osd->attach_to({ba_stop});
+    split->attach_to({osd});
+    screen_des_0->attach_to({split});
+    screen_des_1->attach_to({split});
+
+    file_src_0->start();
+    file_src_1->start();
+
+    // for debug purpose
+    vp_utils::vp_analysis_board board({file_src_0, file_src_1});
+    board.display();
+}
\ No newline at end of file
diff --git a/samples/config.json b/samples/config.json
new file mode 100644
index 0000000..e1164ae
--- /dev/null
+++ b/samples/config.json
@@ -0,0 +1,28 @@
+{
+    "rtsp_sources": {
+        "1": "rtsp://192.168.1.24:8554/demo",
+        "2": "rtsp://192.168.1.24:8554/demo",
+        "3": "rtsp://192.168.1.24:8554/demo",
+        "4": "rtsp://192.168.1.24:8554/demo",
+        "5": "rtsp://192.168.1.24:8554/demo",
+        "6": "rtsp://192.168.1.24:8554/demo",
+        "7": "rtsp://192.168.1.24:8554/demo",
+        "8": "rtsp://192.168.1.24:8554/demo",
+        "9": "rtsp://192.168.1.24:8554/demo",
+        "10": "rtsp://192.168.1.24:8554/demo"
+    },
+    "resize_ratio": 0.4,
+    "kafka_server": "192.168.0.85:9092",
+    "region_points": {
+        "1": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "2": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "3": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "4": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "5": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "6": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "7": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "8": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "9": [[0, 520], [450, 50], [650, 50], [1000, 520]],
+        "10": [[0, 520], [450, 50], [650, 50], [1000, 520]]
+    }
+}
\ No newline at end of file
diff --git a/samples/face_recognize/face_recognize_pipeline b/samples/face_recognize/face_recognize_pipeline
index f72a091..15f7969 100755
--- a/samples/face_recognize/face_recognize_pipeline
+++ b/samples/face_recognize/face_recognize_pipeline
Binary files differ
diff --git a/samples/from_argv_ba_jam_rtsp.cpp b/samples/from_argv_ba_jam_rtsp.cpp
new file mode 100644
index 0000000..7f4aa05
--- /dev/null
+++ b/samples/from_argv_ba_jam_rtsp.cpp
@@ -0,0 +1,120 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+#include "../nodes/infers/vp_yolo_detector_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_jam_node.h"
+#include "../nodes/osd/vp_ba_jam_osd_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/vp_rtmp_des_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/vp_file_des_node.h"
+#include "../nodes/vp_split_node.h"
+#include "../nodes/record/vp_record_node.h"
+#include "../nodes/vp_fake_des_node.h"
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+#include <vector>
+#include <string>
+#include <iostream>
+#include <map>
+#include <memory>
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::WARN);
+    VP_LOGGER_INIT();
+
+    std::vector<std::string> args(argv + 1, argv + argc);
+
+    // 榛樿鐨勫懡浠よ鍙傛暟
+    std::string rtsp_base_url = "rtsp://192.168.1.24:8554/demo";
+    std::string kafka_server_point = "192.168.0.85:9092";
+    float resize_ratio = 0.4;
+
+    std::vector<std::string> rtsp_urls; 
+
+
+    // 瑙f瀽鍛戒护琛屽弬鏁�
+    if (args.size() >= 22) {
+        for (int i = 0; i < 20; ++i) {
+            rtsp_urls.push_back(args[i]); 
+        }
+        resize_ratio = std::stof(args[20]);
+        kafka_server_point = args[21];
+    } else {
+        std::cout << "Usage: " << argv[0] << " <rtsp_path_1> ... <rtsp_path_20> <resize_ratio> <kafka_server_point>\n";
+        std::cout << "Example: " << argv[0] << " rtsp://192.168.1.24:8554/demo 0.4 192.168.0.85:9092\n";
+        return -1;
+    }
+
+    // Create RTSP source nodes
+    std::vector<std::shared_ptr<vp_nodes::vp_rtsp_src_node>> rtsp_sources;
+    for (int i = 0; i < 20; ++i) {
+        rtsp_sources.push_back(std::make_shared<vp_nodes::vp_rtsp_src_node>(
+            "rtsp_src_" + std::to_string(i + 1), i + 1, rtsp_urls[i], resize_ratio, "avdec_h264"));
+    }
+    
+    auto yolo_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("yolo_detector",
+        "./vp_data/models/det_cls/yolov3-tiny-2022-0721_best.weights",
+        "./vp_data/models/det_cls/yolov3-tiny-2022-0721.cfg",
+        "./vp_data/models/det_cls/yolov3_tiny_5classes.txt");
+
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+
+    // Define regions for every channel
+    auto define_regions = [](int num_sources) {
+        std::map<int, std::vector<vp_objects::vp_point>> regions;
+        for (int i = 1; i <= num_sources; ++i) {
+            regions[i] = std::vector<vp_objects::vp_point>{
+                vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50),
+                vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)};
+        }
+        return regions;
+    };
+
+    auto ba_jam = std::make_shared<vp_nodes::vp_ba_jam_node>("ba_jam", define_regions(20));
+
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>(
+        "json_kafka_broker_0", kafka_server_point, "vp_ba_jam", vp_nodes::vp_broke_for::BARESULT);
+
+    auto osd = std::make_shared<vp_nodes::vp_ba_jam_osd_node>("osd");
+    auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
+    auto split = std::make_shared<vp_nodes::vp_split_node>("split", true);
+    // Create 20 fake destination nodes, one for each channel
+    std::vector<std::shared_ptr<vp_nodes::vp_fake_des_node>> fake_des_nodes;
+    for (int i = 1; i <= 20; ++i) {
+        fake_des_nodes.push_back(std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_" + std::to_string(i), i));
+    }
+
+    // Construct pipeline
+    for (auto& rtsp_source : rtsp_sources) {
+        yolo_detector->attach_to({rtsp_source});
+    }
+
+    tracker->attach_to({yolo_detector});
+    ba_jam->attach_to({tracker});
+
+    json_kafka_broker_0->attach_to({ba_jam});
+    osd->attach_to({json_kafka_broker_0});
+    recorder->attach_to({osd});
+    split->attach_to({recorder});
+
+    // Attach fake destination nodes (one for each channel)
+    for (auto& fake_des_node : fake_des_nodes) {
+        fake_des_node->attach_to({split});
+    }
+
+    // Start RTSP sources
+    for (auto& rtsp_source : rtsp_sources) {
+        rtsp_source->start();
+    }
+
+    std::string wait;
+    std::getline(std::cin, wait);
+
+    // Cleanup
+    for (auto& rtsp_source : rtsp_sources) {
+        rtsp_source->detach_recursively();
+    }
+
+    return 0;
+}
diff --git a/samples/from_argv_ba_jam_rtsp_bak.cpp b/samples/from_argv_ba_jam_rtsp_bak.cpp
new file mode 100644
index 0000000..202329d
--- /dev/null
+++ b/samples/from_argv_ba_jam_rtsp_bak.cpp
@@ -0,0 +1,127 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+
+#include "../nodes/infers/vp_yolo_detector_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_jam_node.h"
+#include "../nodes/osd/vp_ba_jam_osd_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/vp_rtmp_des_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/vp_file_des_node.h"
+#include "../nodes/record/vp_record_node.h"
+#include "../nodes/vp_fake_des_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+/*
+* ## ba crossline sample ##
+* behaviour analysis for crossline.
+*/
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+
+    std::vector<std::string> args(argv + 1, argv + argc);
+    // 榛樿鐨勫懡浠よ鍙傛暟
+    std::string rtsp_path_1 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_2 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_3 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_4 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_5 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_6 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_7 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_8 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_9 = "rtsp://192.168.1.24:8554/demo";
+    std::string rtsp_path_10 = "rtsp://192.168.1.24:8554/demo";
+
+    std::string kafka_server_point = "192.168.0.85:9092";
+
+    float resize_ratio = 0.4;
+
+    // 濡傛灉鎻愪緵浜嗙涓�涓拰绗簩涓弬鏁帮紝鍒欒鐩栭粯璁ょ殑璺緞
+    if (args.size() >= 3) {
+        rtsp_path_1 = args[0];
+        rtsp_path_2 = args[1];
+        rtsp_path_3 = args[2];
+        rtsp_path_4 = args[3];
+        rtsp_path_5 = args[4];
+        rtsp_path_6 = args[5];
+        rtsp_path_7 = args[6];
+        rtsp_path_8 = args[7];
+        rtsp_path_9 = args[8];
+        rtsp_path_10 = args[9];                                                                        
+        resize_ratio = std::stof(args[10]);
+        kafka_server_point = args[11];
+        
+    } else {
+        std::cout << "Usage: " << argv[0] << " <rtsp_path> <resize_ratio> <kafka_server_point>\n";
+        std::cout << "Example: " << argv[0] << " rtsp://192.168.1.24:8554/demo 0.4 192.168.0.85:9092\n";
+        return -1;
+    }
+
+
+    // create nodes
+    //auto rtsp_src_1 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, rtsp_path, resize_ratio);
+    auto rtsp_src_1 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_1", 1, rtsp_path_1, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_2 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_2", 2, rtsp_path_2, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_3 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_3", 3, rtsp_path_3, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_4 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_4", 4, rtsp_path_4, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_5 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_5", 5, rtsp_path_5, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_6 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_6", 6, rtsp_path_6, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_7 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_7", 7, rtsp_path_7, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_8 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_8", 8, rtsp_path_8, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_9 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_9", 9, rtsp_path_9, resize_ratio, "avdec_h264"); 
+    auto rtsp_src_10 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_10", 10, rtsp_path_10, resize_ratio, "avdec_h264");                                         
+    auto yolo_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("yolo_detector", "./vp_data/models/det_cls/yolov3-tiny-2022-0721_best.weights", "./vp_data/models/det_cls/yolov3-tiny-2022-0721.cfg", "./vp_data/models/det_cls/yolov3_tiny_5classes.txt");
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+    
+    // define a region in frame for every channel (value MUST in the scope of frame'size)
+    std::map<int, std::vector<vp_objects::vp_point>> regions = {
+        //{0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(641, 58), vp_objects::vp_point(747, 51), vp_objects::vp_point(1132, 267), vp_objects::vp_point(366, 678)}}
+        {1, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {2, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {3, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {4, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {5, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {6, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {7, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {8, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {9, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}},
+        {10, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}}
+
+    };
+    auto ba_jam = std::make_shared<vp_nodes::vp_ba_jam_node>("ba_jam", regions);
+
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", kafka_server_point, "vp_ba_jam", vp_nodes::vp_broke_for::BARESULT);
+    auto osd = std::make_shared<vp_nodes::vp_ba_jam_osd_node>("osd");
+    auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
+    auto fake_des_0 = std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_0", 2);
+    
+    // construct pipeline
+    yolo_detector->attach_to({rtsp_src_1,rtsp_src_2,rtsp_src_3,rtsp_src_4,rtsp_src_5,rtsp_src_6,rtsp_src_7,rtsp_src_8,rtsp_src_9,rtsp_src_10});
+    tracker->attach_to({yolo_detector});
+    ba_jam->attach_to({tracker});
+
+    json_kafka_broker_0->attach_to({ba_jam});
+    osd->attach_to({json_kafka_broker_0});
+    recorder->attach_to({osd});
+
+    fake_des_0->attach_to({recorder});
+
+    rtsp_src_1->start();
+    rtsp_src_2->start();
+    rtsp_src_3->start();
+    rtsp_src_4->start();
+    rtsp_src_5->start();
+    rtsp_src_6->start();
+    rtsp_src_7->start();
+    rtsp_src_8->start();
+    rtsp_src_9->start();
+    rtsp_src_10->start();                     
+
+    std::string wait;
+    std::getline(std::cin, wait);
+    rtsp_src_1->detach_recursively();
+}
\ No newline at end of file
diff --git a/samples/from_argv_ba_jam_rtsp_d.cpp b/samples/from_argv_ba_jam_rtsp_d.cpp
new file mode 100644
index 0000000..dcc9931
--- /dev/null
+++ b/samples/from_argv_ba_jam_rtsp_d.cpp
@@ -0,0 +1,82 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+
+#include "../nodes/infers/vp_yolo_detector_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_jam_node.h"
+#include "../nodes/osd/vp_ba_jam_osd_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/vp_rtmp_des_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/vp_file_des_node.h"
+#include "../nodes/record/vp_record_node.h"
+#include "../nodes/vp_fake_des_node.h"
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+/*
+* ## ba crossline sample ##
+* behaviour analysis for crossline.
+*/
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+
+    std::vector<std::string> args(argv + 1, argv + argc);
+    // 榛樿鐨勫懡浠よ鍙傛暟
+    std::string rtsp_path = "rtsp://192.168.1.24:8554/demo";
+    std::string kafka_server_point = "192.168.0.85:9092";
+
+    float resize_ratio = 0.4;
+    int skip_interval = 1;
+
+    // 濡傛灉鎻愪緵浜嗙涓�涓拰绗簩涓弬鏁帮紝鍒欒鐩栭粯璁ょ殑璺緞
+    if (args.size() >= 4) {
+        rtsp_path = args[0];
+        resize_ratio = std::stof(args[1]);
+        kafka_server_point = args[2];
+        skip_interval = std::stoi(args[3]);
+    } else {
+        std::cout << "Usage: " << argv[0] << " <rtsp_path> <resize_ratio> <kafka_server_point> <skip_interval>\n";
+        std::cout << "Example: " << argv[0] << " rtsp://192.168.1.24:8554/demo 0.4 192.168.0.85:9092 5 \n";
+        return -1;
+    }
+
+
+    // create nodes
+    // auto rtsp_src_1 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, rtsp_path, resize_ratio, skip_interval);
+    auto rtsp_src_1 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_1", 0, rtsp_path, resize_ratio, "avdec_h264", skip_interval); 
+    auto yolo_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("yolo_detector", "./vp_data/models/det_cls/yolov3-tiny-2022-0721_best.weights", "./vp_data/models/det_cls/yolov3-tiny-2022-0721.cfg", "./vp_data/models/det_cls/yolov3_tiny_5classes.txt");
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+    
+    // define a region in frame for every channel (value MUST in the scope of frame'size)
+    std::map<int, std::vector<vp_objects::vp_point>> regions = {
+        //{0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(641, 58), vp_objects::vp_point(747, 51), vp_objects::vp_point(1132, 267), vp_objects::vp_point(366, 678)}}
+        {0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}}
+    };
+    auto ba_jam = std::make_shared<vp_nodes::vp_ba_jam_node>("ba_jam", regions);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", kafka_server_point, "vp_ba_jam", vp_nodes::vp_broke_for::BARESULT);
+    auto osd = std::make_shared<vp_nodes::vp_ba_jam_osd_node>("osd");
+    auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
+    auto fake_des_2 = std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_2", 0);
+    
+    // construct pipeline
+    yolo_detector->attach_to({rtsp_src_1});
+    tracker->attach_to({yolo_detector});
+    ba_jam->attach_to({tracker});
+    json_kafka_broker_0->attach_to({ba_jam});
+    osd->attach_to({json_kafka_broker_0});
+    recorder->attach_to({osd});
+    fake_des_2->attach_to({recorder});
+
+
+    rtsp_src_1->start();
+
+    // for debug purpose
+    vp_utils::vp_analysis_board board({rtsp_src_1});
+    board.display(1, false);
+
+    std::string wait;
+    std::getline(std::cin, wait);
+    rtsp_src_1->detach_recursively();
+}
\ No newline at end of file
diff --git a/samples/from_argv_ba_person.cpp b/samples/from_argv_ba_person.cpp
new file mode 100644
index 0000000..1a73b87
--- /dev/null
+++ b/samples/from_argv_ba_person.cpp
@@ -0,0 +1,74 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/infers/vp_yolo_detector_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_person_gathering_node.h"
+#include "../nodes/ba/vp_ba_person_falldown_node.h"
+#include "../nodes/osd/vp_ba_stop_osd_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/record/vp_record_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+/*
+* ## ba crossline sample ##
+* behaviour analysis for crossline.
+*/
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+
+    std::vector<std::string> args(argv + 1, argv + argc);
+    // 榛樿鐨勫懡浠よ鍙傛暟
+    std::string video_path = "./vp_data/test_video/gathering.mp4";
+
+    float resize_ratio = 1.0;
+
+    // 濡傛灉鎻愪緵浜嗙涓�涓拰绗簩涓弬鏁帮紝鍒欒鐩栭粯璁ょ殑璺緞
+    if (args.size() >= 1) {
+        video_path = args[0];
+        if (args.size() >= 2){
+            resize_ratio = std::stof(args[1]);
+        }
+    } else {
+        std::cout << "Usage: " << argv[0] << " <video_path> [resize_ratio]\n";
+        std::cout << "Example: " << argv[0] << " ./vp_data/test_video/gathering.mp4 1.0\n";
+        return -1;
+    }
+
+
+    // create nodes
+    auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, video_path, resize_ratio);
+    auto yolo_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("yolo_detector", "./vp_data/models/det_cls/yolov3-tiny-2022-0721_best.weights", "./vp_data/models/det_cls/yolov3-tiny-2022-0721.cfg", "./vp_data/models/det_cls/yolov3_tiny_5classes.txt");
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+    
+    int min_gathering_count = 2;
+    auto ba_person_gathering = std::make_shared<vp_nodes::vp_ba_person_gathering_node>("vp_ba_person_gathering_node", min_gathering_count,true,true);
+    auto ba_person_falldown = std::make_shared<vp_nodes::vp_ba_person_falldown_node>("vp_ba_person_falldown_node", true,true);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", "192.168.0.85:9092", "vp_ba_person", vp_nodes::vp_broke_for::BARESULT);
+    auto osd = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd");
+    auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
+    auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
+    
+    // construct pipeline
+    yolo_detector->attach_to({file_src_0});
+    tracker->attach_to({yolo_detector});
+    ba_person_gathering->attach_to({tracker});
+    ba_person_falldown->attach_to({ba_person_gathering});
+    json_kafka_broker_0->attach_to({ba_person_falldown});
+    osd->attach_to({json_kafka_broker_0});
+    recorder->attach_to({osd});
+    screen_des_0->attach_to({recorder});
+
+
+    file_src_0->start();
+
+    // for debug purpose
+    vp_utils::vp_analysis_board board({file_src_0});
+    board.display(1, false);
+
+    std::string wait;
+    std::getline(std::cin, wait);
+    file_src_0->detach_recursively();
+}
\ No newline at end of file
diff --git a/samples/from_argv_ba_stop_rtsp.cpp b/samples/from_argv_ba_stop_rtsp.cpp
new file mode 100644
index 0000000..e2a3ec3
--- /dev/null
+++ b/samples/from_argv_ba_stop_rtsp.cpp
@@ -0,0 +1,82 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+#include "../nodes/infers/vp_trt_vehicle_detector.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_stop_node.h"
+#include "../nodes/osd/vp_ba_stop_osd_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/vp_file_des_node.h"
+#include "../nodes/record/vp_record_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+/*
+* ## ba stop sample ##
+* behaviour analysis for stop, single instance of ba node work on 2 channels.
+*/
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+
+    std::vector<std::string> args(argv + 1, argv + argc);
+    // 榛樿鐨勫懡浠よ鍙傛暟
+    std::string rtsp_path = "rtsp://192.168.1.24:8554/demo";
+    std::string kafka_server_point = "192.168.0.85:9092";
+
+    float resize_ratio = 0.4;
+
+    // 濡傛灉鎻愪緵浜嗙涓�涓拰绗簩涓弬鏁帮紝鍒欒鐩栭粯璁ょ殑璺緞
+    if (args.size() >= 3) {
+        rtsp_path = args[0];
+        resize_ratio = std::stof(args[1]);
+        kafka_server_point = args[2];
+        
+    } else {
+        std::cout << "Usage: " << argv[0] << " <rtsp_path> <resize_ratio> <kafka_server_point>\n";
+        std::cout << "Example: " << argv[0] << " rtsp://192.168.1.24:8554/demo 0.4 192.168.0.85:9092\n";
+        return -1;
+    }
+
+
+    // create nodes
+    //auto rtsp_src_1 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, rtsp_path, resize_ratio);
+    auto rtsp_src_1 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_1", 0, rtsp_path, resize_ratio, "avdec_h264"); 
+    auto trt_vehicle_detector = std::make_shared<vp_nodes::vp_trt_vehicle_detector>("vehicle_detector", "./vp_data//models/trt/vehicle/vehicle_detection.trt");
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+    
+    // define a region in frame for every channel (value MUST in the scope of frame'size)
+    std::map<int, std::vector<vp_objects::vp_point>> regions = {
+        //{0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(641, 58), vp_objects::vp_point(747, 51), vp_objects::vp_point(1132, 267), vp_objects::vp_point(366, 678)}}
+        {0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}}
+    };
+    auto ba_stop = std::make_shared<vp_nodes::vp_ba_stop_node>("ba_stop", regions);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", kafka_server_point, "vp_ba_stop", vp_nodes::vp_broke_for::BARESULT);
+    auto osd = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd");
+    auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
+    auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
+    auto file_des_node_0 = std::make_shared<vp_nodes::vp_file_des_node>("file_des_0", 0, "out-a-osd", "out-a-osd", 1);
+    
+    // construct pipeline
+    trt_vehicle_detector->attach_to({rtsp_src_1});
+    tracker->attach_to({trt_vehicle_detector});
+    ba_stop->attach_to({tracker});
+    json_kafka_broker_0->attach_to({ba_stop});
+    osd->attach_to({json_kafka_broker_0});
+    recorder->attach_to({osd});
+
+    screen_des_0->attach_to({recorder});
+    file_des_node_0->attach_to({recorder});
+
+    rtsp_src_1->start();
+
+    // for debug purpose
+    vp_utils::vp_analysis_board board({rtsp_src_1});
+    board.display();
+
+    std::string wait;
+    std::getline(std::cin, wait);
+    rtsp_src_1->detach_recursively();
+
+}
\ No newline at end of file
diff --git a/samples/from_argv_ba_stop_rtsp_d.cpp b/samples/from_argv_ba_stop_rtsp_d.cpp
new file mode 100644
index 0000000..e2a3ec3
--- /dev/null
+++ b/samples/from_argv_ba_stop_rtsp_d.cpp
@@ -0,0 +1,82 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+#include "../nodes/infers/vp_trt_vehicle_detector.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_stop_node.h"
+#include "../nodes/osd/vp_ba_stop_osd_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/vp_file_des_node.h"
+#include "../nodes/record/vp_record_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+/*
+* ## ba stop sample ##
+* behaviour analysis for stop, single instance of ba node work on 2 channels.
+*/
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+
+    std::vector<std::string> args(argv + 1, argv + argc);
+    // 榛樿鐨勫懡浠よ鍙傛暟
+    std::string rtsp_path = "rtsp://192.168.1.24:8554/demo";
+    std::string kafka_server_point = "192.168.0.85:9092";
+
+    float resize_ratio = 0.4;
+
+    // 濡傛灉鎻愪緵浜嗙涓�涓拰绗簩涓弬鏁帮紝鍒欒鐩栭粯璁ょ殑璺緞
+    if (args.size() >= 3) {
+        rtsp_path = args[0];
+        resize_ratio = std::stof(args[1]);
+        kafka_server_point = args[2];
+        
+    } else {
+        std::cout << "Usage: " << argv[0] << " <rtsp_path> <resize_ratio> <kafka_server_point>\n";
+        std::cout << "Example: " << argv[0] << " rtsp://192.168.1.24:8554/demo 0.4 192.168.0.85:9092\n";
+        return -1;
+    }
+
+
+    // create nodes
+    //auto rtsp_src_1 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, rtsp_path, resize_ratio);
+    auto rtsp_src_1 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_1", 0, rtsp_path, resize_ratio, "avdec_h264"); 
+    auto trt_vehicle_detector = std::make_shared<vp_nodes::vp_trt_vehicle_detector>("vehicle_detector", "./vp_data//models/trt/vehicle/vehicle_detection.trt");
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+    
+    // define a region in frame for every channel (value MUST in the scope of frame'size)
+    std::map<int, std::vector<vp_objects::vp_point>> regions = {
+        //{0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(641, 58), vp_objects::vp_point(747, 51), vp_objects::vp_point(1132, 267), vp_objects::vp_point(366, 678)}}
+        {0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(0, 520), vp_objects::vp_point(450, 50), vp_objects::vp_point(650, 50), vp_objects::vp_point(1000, 520)}}
+    };
+    auto ba_stop = std::make_shared<vp_nodes::vp_ba_stop_node>("ba_stop", regions);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", kafka_server_point, "vp_ba_stop", vp_nodes::vp_broke_for::BARESULT);
+    auto osd = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd");
+    auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
+    auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
+    auto file_des_node_0 = std::make_shared<vp_nodes::vp_file_des_node>("file_des_0", 0, "out-a-osd", "out-a-osd", 1);
+    
+    // construct pipeline
+    trt_vehicle_detector->attach_to({rtsp_src_1});
+    tracker->attach_to({trt_vehicle_detector});
+    ba_stop->attach_to({tracker});
+    json_kafka_broker_0->attach_to({ba_stop});
+    osd->attach_to({json_kafka_broker_0});
+    recorder->attach_to({osd});
+
+    screen_des_0->attach_to({recorder});
+    file_des_node_0->attach_to({recorder});
+
+    rtsp_src_1->start();
+
+    // for debug purpose
+    vp_utils::vp_analysis_board board({rtsp_src_1});
+    board.display();
+
+    std::string wait;
+    std::getline(std::cin, wait);
+    rtsp_src_1->detach_recursively();
+
+}
\ No newline at end of file
diff --git a/samples/from_argv_ba_wrong_direction.cpp b/samples/from_argv_ba_wrong_direction.cpp
new file mode 100644
index 0000000..e34cd13
--- /dev/null
+++ b/samples/from_argv_ba_wrong_direction.cpp
@@ -0,0 +1,78 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/infers/vp_yolo_detector_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_wrong_direction_node.h"
+#include "../nodes/osd/vp_ba_stop_osd_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/record/vp_record_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+/*
+* ## ba crossline sample ##
+* behaviour analysis for crossline.
+*/
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+
+    std::vector<std::string> args(argv + 1, argv + argc);
+    // 榛樿鐨勫懡浠よ鍙傛暟
+    std::string video_path = "./vp_data/test_video/vehicle_count.mp4";
+
+    float resize_ratio = 0.4;
+
+    // 濡傛灉鎻愪緵浜嗙涓�涓拰绗簩涓弬鏁帮紝鍒欒鐩栭粯璁ょ殑璺緞
+    if (args.size() >= 1) {
+        video_path = args[0];
+        if (args.size() >= 2){
+            resize_ratio = std::stof(args[1]);
+        }
+    } else {
+        std::cout << "Usage: " << argv[0] << " <video_path> [resize_ratio]\n";
+        std::cout << "Example: " << argv[0] << " ./vp_data/test_video/vehicle_count.mp4 0.4\n";
+        return -1;
+    }
+
+
+    // create nodes
+    auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, video_path, resize_ratio);
+    auto yolo_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("yolo_detector", "./vp_data/models/det_cls/yolov3-tiny-2022-0721_best.weights", "./vp_data/models/det_cls/yolov3-tiny-2022-0721.cfg", "./vp_data/models/det_cls/yolov3_tiny_5classes.txt");
+    auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+    
+    // define a line in frame for every channel (value MUST in the scope of frame'size)
+    vp_objects::vp_point left_start(10, 10);  // change to proper value
+    vp_objects::vp_point left_end(10, 20);  // change to proper value
+    vp_objects::vp_point right_start(10, 20);  // change to proper value
+    vp_objects::vp_point right_end(10, 10);  // change to proper value
+    std::map<int, std::vector<vp_objects::vp_point>> left_lines = {{0, {left_start, left_end}}};  // channel0 -> point vector
+    std::map<int, std::vector<vp_objects::vp_point>> right_lines = {{0, {right_start, right_end}}};  // channel0 -> point vector
+    int half_screen_width = 384;
+    auto ba_wrong_direction = std::make_shared<vp_nodes::vp_ba_wrong_direction_node>("vp_ba_wrong_direction_node", left_lines,right_lines,half_screen_width,true,true);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", "192.168.0.85:9092", "vp_ba_wrong_direction", vp_nodes::vp_broke_for::BARESULT);
+    auto osd = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd");
+    auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
+    auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
+    
+    // construct pipeline
+    yolo_detector->attach_to({file_src_0});
+    tracker->attach_to({yolo_detector});
+    ba_wrong_direction->attach_to({tracker});
+    json_kafka_broker_0->attach_to({ba_wrong_direction});
+    osd->attach_to({json_kafka_broker_0});
+    recorder->attach_to({osd});
+    screen_des_0->attach_to({recorder});
+
+
+    file_src_0->start();
+
+    // for debug purpose
+    vp_utils::vp_analysis_board board({file_src_0});
+    board.display(1, false);
+
+    std::string wait;
+    std::getline(std::cin, wait);
+    file_src_0->detach_recursively();
+}
\ No newline at end of file
diff --git a/samples/lpr_camera/plate_recognize_pipeline b/samples/lpr_camera/plate_recognize_pipeline
index 1969b55..509ec72 100755
--- a/samples/lpr_camera/plate_recognize_pipeline
+++ b/samples/lpr_camera/plate_recognize_pipeline
Binary files differ
diff --git a/samples/similiarity_search/face_encoding_pipeline b/samples/similiarity_search/face_encoding_pipeline
index e1a38f6..88232bc 100755
--- a/samples/similiarity_search/face_encoding_pipeline
+++ b/samples/similiarity_search/face_encoding_pipeline
Binary files differ
diff --git a/samples/similiarity_search/vehicle_encoding_pipeline b/samples/similiarity_search/vehicle_encoding_pipeline
index 21e2fed..59137cf 100755
--- a/samples/similiarity_search/vehicle_encoding_pipeline
+++ b/samples/similiarity_search/vehicle_encoding_pipeline
Binary files differ
diff --git a/samples/vehicle_behaviour_analysis/vehicle_ba_pipeline b/samples/vehicle_behaviour_analysis/vehicle_ba_pipeline
index 0bbcf37..7a686bf 100755
--- a/samples/vehicle_behaviour_analysis/vehicle_ba_pipeline
+++ b/samples/vehicle_behaviour_analysis/vehicle_ba_pipeline
Binary files differ
diff --git a/samples/vehicle_property_and_similiarity_search/vehicle_encoding_classify_pipeline b/samples/vehicle_property_and_similiarity_search/vehicle_encoding_classify_pipeline
index c24ed88..ea9454f 100755
--- a/samples/vehicle_property_and_similiarity_search/vehicle_encoding_classify_pipeline
+++ b/samples/vehicle_property_and_similiarity_search/vehicle_encoding_classify_pipeline
Binary files differ

--
Gitblit v1.9.1