From 291afb9c81aae1d15d9e3edcea618d0a2e1fc5a6 Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期三, 19 三月 2025 17:51:38 +0800
Subject: [PATCH] add samples

---
 nodes/ba/vp_ba_jam_node.h                                                          |   10 
 samples/from_argv_ba_jam_rtsp_m.cpp                                                |   11 
 samples/from_argv_width_calibration.cpp                                            |  199 +++++++++
 nodes/ba/vp_ba_jam_node.cpp                                                        |   34 
 nodes/vp_infer_node.cpp                                                            |    3 
 samples/from_argv_ba_crossline_rtsp_mr.cpp                                         |  200 +++++++++
 samples/similiarity_search/face_encoding_pipeline                                  |    0 
 samples/lpr_camera/plate_recognize_pipeline                                        |    0 
 nodes/infers/vp_yolo_detector_node.h                                               |    2 
 samples/vehicle_behaviour_analysis/vehicle_ba_pipeline                             |    0 
 nodes/ba/vp_ba_stop_node.h                                                         |    6 
 samples/from_argv_test_width.cpp                                                   |  140 ++++++
 objects/vp_frame_target.h                                                          |    4 
 nodes/ba/vp_ba_width_calibration_node.cpp                                          |  182 ++++++++
 nodes/osd/vp_ba_stop_osd_node.cpp                                                  |    3 
 samples/vehicle_property_and_similiarity_search/vehicle_encoding_classify_pipeline |    0 
 samples/face_recognize/face_recognize_pipeline                                     |    0 
 samples/from_argv_ba_crossline_rtsp.cpp                                            |   40 -
 samples/CMakeLists.txt                                                             |   27 +
 nodes/ba/vp_ba_stop_node.cpp                                                       |   31 
 samples/from_argv_ba_crossline.cpp                                                 |    9 
 samples/from_argv_all_in_one_sample.cpp                                            |   22 
 nodes/ba/vp_ba_crossline_node.cpp                                                  |    9 
 samples/from_argv_ba_crossline_bak.cpp                                             |   71 +++
 samples/from_argv_ba_jam_rtsp_mr.cpp                                               |  206 +++++++++
 nodes/vp_rtsp_ffmpeg_src_node.cpp                                                  |    4 
 samples/similiarity_search/vehicle_encoding_pipeline                               |    0 
 nodes/ba/vp_ba_width_calibration_node.h                                            |   46 ++
 28 files changed, 1,170 insertions(+), 89 deletions(-)

diff --git a/nodes/ba/vp_ba_crossline_node.cpp b/nodes/ba/vp_ba_crossline_node.cpp
index c10721d..afaa38b 100644
--- a/nodes/ba/vp_ba_crossline_node.cpp
+++ b/nodes/ba/vp_ba_crossline_node.cpp
@@ -42,6 +42,9 @@
         // for vp_frame_target only
         for (auto& target : meta->targets) {
             auto len = target->tracks.size();
+            if (target->primary_label != target->class_label_of_car) {
+                continue;
+            }
             std::vector<int> involve_targets;
             if (len > 1 && target->track_id >= 0) {
                 // check the last 2 points in tracks
@@ -54,11 +57,11 @@
                 // `true and false`  or `false and true`
                 // means target passed the line in current frame
                 if (check1 ^ check2) {
-                    total_crossline++;
                     involve_targets.push_back(target->track_id);
-
                     // not empty need fill ba result back to frame meta
                     if (involve_targets.size() > 0) {
+                        bool is_entering = p1.y > p2.y;
+                        total_crossline += (is_entering ? 1 : -1);                        
                         // 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
@@ -82,7 +85,7 @@
                                                                                     meta->frame_index, 
                                                                                     involve_targets, 
                                                                                     involve_region,
-                                                                                    "cross_line",   // meaningful label
+                                                                                    is_entering ? "cross_line_in" : "cross_line_out",   // meaningful label
                                                                                     image_file_name_without_ext, 
                                                                                     video_file_name_without_ext);
                         // fill back to frame meta
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..22e287c 100644
--- a/nodes/ba/vp_ba_jam_node.h
+++ b/nodes/ba/vp_ba_jam_node.h
@@ -32,11 +32,11 @@
         bool point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region);
 
         // jam checking logic parameters which may be configed by constructor passed in by user
-        const int check_interval_frames = 20;
-        const int check_min_hit_frames = 25 * 2;  // 25 fps * 2 seconds
-        const int check_max_distance = 8;
-        const int check_min_stops = 8;
-        const int check_notify_interval = 10;  // interval time (seconds) to notify (ensure not frequently)
+        const int check_interval_frames = 70;
+        const int check_min_hit_frames = 20 * 60 /3;  // 25 fps * 2 seconds
+        const int check_max_distance = 10; //The closer the camera, the larger the pixel distance.
+        const int check_min_stops = 2;
+        const int check_notify_interval = 30;  // 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_stop_node.cpp b/nodes/ba/vp_ba_stop_node.cpp
index e633d29..9ae20af 100644
--- a/nodes/ba/vp_ba_stop_node.cpp
+++ b/nodes/ba/vp_ba_stop_node.cpp
@@ -59,22 +59,25 @@
         // 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();
+            if (target->primary_label == target->class_label_of_car)
+            {
+                auto len = target->tracks.size();
+                auto loc = target->get_rect().track_point();
 
-            // target has been tracked AND tracked enough frames
-            if (len < check_interval_frames || target->track_id < 0) {
-                continue;
-            }
-            // if target inside of stop region or not
-            if (!point_in_poly(loc, stop_region)) {
-                continue;
-            }
+                // target has been tracked AND tracked enough frames
+                if (len < check_interval_frames || target->track_id < 0) {
+                    continue;
+                }
+                // if target inside of stop region or not
+                if (!point_in_poly(loc, stop_region)) {
+                    continue;
+                }
 
-            auto pre_loc = target->tracks[len - check_interval_frames].track_point();
-            if (pre_loc.distance_with(loc) <= check_max_distance) {
-                stop_checking_status[target->track_id]++;
-                hit_traget_ids.push_back(target->track_id);
+                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_stop_node.h b/nodes/ba/vp_ba_stop_node.h
index 7c0eafc..c49d225 100644
--- a/nodes/ba/vp_ba_stop_node.h
+++ b/nodes/ba/vp_ba_stop_node.h
@@ -26,9 +26,9 @@
         bool point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region);
 
         // stop checking logic parameters which may be configed by constructor passed in by user
-        const int check_interval_frames = 20;
-        const int check_min_hit_frames = 25 * 2;  // 25 fps * 2 seconds
-        const int check_max_distance = 5;
+        const int check_interval_frames = 70;
+        const int check_min_hit_frames = 20/3 * 60;  // 25 fps * 2 seconds
+        const int check_max_distance = 15; //The closer the camera, the larger the pixel distance.
     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_width_calibration_node.cpp b/nodes/ba/vp_ba_width_calibration_node.cpp
new file mode 100644
index 0000000..98d0165
--- /dev/null
+++ b/nodes/ba/vp_ba_width_calibration_node.cpp
@@ -0,0 +1,182 @@
+
+
+#include "vp_ba_stop_node.h"
+
+namespace vp_nodes {
+    
+    vp_ba_stop_node::vp_ba_stop_node(std::string node_name, 
+                                    std::map<int, std::vector<vp_objects::vp_point>> stop_regions,
+                                    bool need_record_image,
+                                    bool need_record_video):
+                                    vp_node(node_name), all_stop_regions(stop_regions), need_record_image(need_record_image), need_record_video(need_record_video) {
+        VP_INFO(vp_utils::string_format("[%s] %s", node_name.c_str(), to_string().c_str()));
+        this->initialized();
+    }
+    
+    vp_ba_stop_node::~vp_ba_stop_node() {
+        deinitialized();
+    }
+
+    std::string vp_ba_stop_node::to_string() {
+        /*
+        * return vertexs of all stop regions
+        * [channel0: x1,y1 x2,y2 ...][channel1: x1,y1 x2,y2 ...]...
+        */
+        std::stringstream ss;
+        for(auto& r: all_stop_regions) {
+            ss << "[channel" << r.first << ":";
+            for(auto& p: r.second) {
+                ss << " " << p.x << "," << p.y;
+            }
+            ss << "]";
+        }
+        return ss.str();
+    }
+
+    bool vp_ba_stop_node::point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region) {
+        int i, j, c = 0;
+        int nvert = region.size();
+
+        for (i = 0, j = nvert-1; i < nvert; j = i++) {
+            if (((region[i].y > p.y) != (region[j].y > p.y)) &&
+            (p.x < (region[j].x - region[i].x) * (p.y - region[i].y) 
+                / (region[j].y - region[i].y) + region[i].x))
+            c = !c;
+        }
+        return c;
+    }
+
+    std::shared_ptr<vp_objects::vp_meta> vp_ba_stop_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
+        // if need applied on current channel or not
+        if (all_stop_regions.count(meta->channel_index) == 0) {
+            return meta;
+        }
+        
+        // for current channel
+        auto& stop_region = all_stop_regions[meta->channel_index];
+        auto& stop_checking_status = all_stop_checking_status[meta->channel_index];
+
+        // for vp_frame_target only
+        std::vector<int> hit_traget_ids;
+        for (auto& target : meta->targets) {
+            auto rect = target->get_rect();
+            // VP_INFO(vp_utils::string_format("Target ID: %d, %d, %d, %d, %d, %s ", 
+            //     target->track_id, rect.x, rect.y, rect.width, rect.height, target->primary_label));            
+
+            if (target->primary_label == target->class_label_of_car)
+            {            
+                auto len = target->tracks.size();
+                auto loc = target->get_rect().track_point();
+
+                // target has been tracked AND tracked enough frames
+                if (len < check_interval_frames || target->track_id < 0) {
+                    continue;
+                }
+                // if target inside of stop region or not
+                if (!point_in_poly(loc, stop_region)) {
+                    continue;
+                }
+                
+                VP_INFO(vp_utils::string_format("Target ID: %d, %d, %d, %d, %d, %s ", 
+                    target->track_id, rect.x, rect.y, rect.width, rect.height, target->primary_label));                
+
+                auto pre_loc = target->tracks[len - check_interval_frames].track_point();
+                if (pre_loc.distance_with(loc) <= check_max_distance) {
+                    stop_checking_status[target->track_id]++;
+                    hit_traget_ids.push_back(target->track_id);
+                }
+            }
+        }
+
+        for (auto i = stop_checking_status.begin(); i != stop_checking_status.end();) {
+            if (std::find(hit_traget_ids.begin(), hit_traget_ids.end(), i->first) == hit_traget_ids.end()) {
+                // statisfy unstop condition
+                if (i->second >= check_min_hit_frames) {
+                    std::vector<int> involve_targets;
+                    involve_targets.push_back(i->first);
+
+                    // send record image and record video signal, recording actions would occur if record nodes exist in pipeline
+                    std::string image_file_name_without_ext = "";    // empty means no recording image
+                    std::string video_file_name_without_ext = "";    // empty means no recording video
+
+                    // send image record control meta
+                    if (need_record_image) {
+                        image_file_name_without_ext = vp_utils::time_format(NOW, "unstop_image__<year><mon><day><hour><min><sec><mili>");
+                        auto image_record_control_meta = std::make_shared<vp_objects::vp_image_record_control_meta>(meta->channel_index, image_file_name_without_ext, true);
+                        pendding_meta(image_record_control_meta);
+                    }
+                    // send video record control meta
+                    if (need_record_video) {
+                        video_file_name_without_ext = vp_utils::time_format(NOW, "unstop_video__<year><mon><day><hour><min><sec><mili>");        
+                        auto video_record_control_meta = std::make_shared<vp_objects::vp_video_record_control_meta>(meta->channel_index, video_file_name_without_ext);
+                        pendding_meta(video_record_control_meta);
+                    }
+
+                    std::vector<vp_objects::vp_point> involve_region = stop_region;
+                    auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::UNSTOP, 
+                                                                                meta->channel_index, 
+                                                                                meta->frame_index, 
+                                                                                involve_targets, 
+                                                                                involve_region,
+                                                                                "unstop",   // meaningful label
+                                                                                image_file_name_without_ext, 
+                                                                                video_file_name_without_ext);
+                    // fill back to frame meta
+                    meta->ba_results.push_back(ba_result);
+                    // info log
+                    VP_INFO(vp_utils::string_format("[%s] [channel %d] has found target unstop", node_name.c_str(), meta->channel_index));
+                    if (need_record_image || need_record_video) {
+                        VP_INFO(vp_utils::string_format("[%s] [channel %d] image & video record file names are: [%s & %s]", node_name.c_str(), meta->channel_index, image_file_name_without_ext.c_str(), video_file_name_without_ext.c_str()));
+                    }
+                }
+                
+                // remove since it not satisfy stop condition
+                i = stop_checking_status.erase(i);
+                continue;
+            }
+
+            // equal means first time to satisfy stop condition
+            if (i->second == check_min_hit_frames) {
+                std::vector<int> involve_targets;
+                involve_targets.push_back(i->first);
+
+                // send record image and record video signal, recording actions would occur if record nodes exist in pipeline
+                std::string image_file_name_without_ext = "";    // empty means no recording image
+                std::string video_file_name_without_ext = "";    // empty means no recording video
+
+                // send image record control meta
+                if (need_record_image) {
+                    image_file_name_without_ext = vp_utils::time_format(NOW, "stop_image__<year><mon><day><hour><min><sec><mili>");
+                    auto image_record_control_meta = std::make_shared<vp_objects::vp_image_record_control_meta>(meta->channel_index, image_file_name_without_ext, true);
+                    pendding_meta(image_record_control_meta);
+                }
+                // send video record control meta
+                if (need_record_video) {
+                    video_file_name_without_ext = vp_utils::time_format(NOW, "stop_video__<year><mon><day><hour><min><sec><mili>");        
+                    auto video_record_control_meta = std::make_shared<vp_objects::vp_video_record_control_meta>(meta->channel_index, video_file_name_without_ext);
+                    pendding_meta(video_record_control_meta);
+                }
+
+                std::vector<vp_objects::vp_point> involve_region = stop_region;
+                auto ba_result = std::make_shared<vp_objects::vp_ba_result>(vp_objects::vp_ba_type::STOP, 
+                                                                            meta->channel_index, 
+                                                                            meta->frame_index, 
+                                                                            involve_targets, 
+                                                                            involve_region,
+                                                                            "stop",   // meaningful label
+                                                                            image_file_name_without_ext, 
+                                                                            video_file_name_without_ext);
+                // fill back to frame meta
+                meta->ba_results.push_back(ba_result);
+                // info log
+                VP_INFO(vp_utils::string_format("[%s] [channel %d] has found target stop", node_name.c_str(), meta->channel_index));
+                if (need_record_image || need_record_video) {
+                    VP_INFO(vp_utils::string_format("[%s] [channel %d] image & video record file names are: [%s & %s]", node_name.c_str(), meta->channel_index, image_file_name_without_ext.c_str(), video_file_name_without_ext.c_str()));
+                }
+            }
+            i++;
+        }
+        
+        return meta;
+    }
+}
\ No newline at end of file
diff --git a/nodes/ba/vp_ba_width_calibration_node.h b/nodes/ba/vp_ba_width_calibration_node.h
new file mode 100644
index 0000000..d7ad198
--- /dev/null
+++ b/nodes/ba/vp_ba_width_calibration_node.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <map>
+#include "../vp_node.h"
+#include "../../objects/shapes/vp_point.h"
+#include "../../objects/shapes/vp_line.h"
+#include "../../objects/vp_image_record_control_meta.h"
+#include "../../objects/vp_video_record_control_meta.h"
+
+namespace vp_nodes {
+    // behaviour analysis node for stop (support multi channels)
+    class vp_ba_stop_node: public vp_node 
+    {
+    private:
+        // channel -> vertexs of region, 1 channel supports only 1 region at most (can be 0, which means no stop check on this channel)
+        std::map<int, std::vector<vp_objects::vp_point>> all_stop_regions;
+
+        // channel -> status of targets (id -> num of hit frames)
+        std::map<int, std::map<int, int>> all_stop_checking_status;
+        std::ofstream record_file;  // File stream for recording   
+
+        // record params
+        bool need_record_image;
+        bool need_record_video;
+
+        // check if point inside of polygon
+        bool point_in_poly(vp_objects::vp_point p, std::vector<vp_objects::vp_point> region);
+
+        // stop checking logic parameters which may be configed by constructor passed in by user
+        const int check_interval_frames = 70;
+        const int check_min_hit_frames = 20/3 * 60;  // 25 fps * 2 seconds
+        const int check_max_distance = 15; //The closer the camera, the larger the pixel distance
+    
+        void open_record_file();
+        void close_record_file();        
+    protected:
+        virtual std::shared_ptr<vp_objects::vp_meta> handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) override;
+    public:
+        vp_ba_stop_node(std::string node_name, 
+                            std::map<int, std::vector<vp_objects::vp_point>> stop_regions,
+                            bool need_record_image = true,
+                            bool need_record_video = true);
+        ~vp_ba_stop_node();
+        std::string to_string() override;
+    };
+}
\ No newline at end of file
diff --git a/nodes/infers/vp_yolo_detector_node.h b/nodes/infers/vp_yolo_detector_node.h
index dceb606..267eb3b 100644
--- a/nodes/infers/vp_yolo_detector_node.h
+++ b/nodes/infers/vp_yolo_detector_node.h
@@ -23,7 +23,7 @@
                             int input_height = 416, 
                             int batch_size = 1,
                             int class_id_offset = 0,
-                            float score_threshold = 0.5,
+                            float score_threshold = 0.7,
                             float confidence_threshold = 0.5,
                             float nms_threshold = 0.5,
                             float scale = 1 / 255.0,
diff --git a/nodes/osd/vp_ba_stop_osd_node.cpp b/nodes/osd/vp_ba_stop_osd_node.cpp
index 8b6b8d7..02108ca 100644
--- a/nodes/osd/vp_ba_stop_osd_node.cpp
+++ b/nodes/osd/vp_ba_stop_osd_node.cpp
@@ -27,6 +27,7 @@
             // track_id
             auto id = std::to_string(i->track_id);
             auto labels_to_display = i->primary_label;
+            auto primary_score_ = std::to_string(i->primary_score);
 
             // tracked
             if (i->track_id != -1) {
@@ -34,7 +35,7 @@
             }
             
             for (auto& label : i->secondary_labels) {
-                labels_to_display += "|" + label;
+                labels_to_display += "|" + label + "|" + primary_score_;
             }
             
             // draw tracks if size>=2
diff --git a/nodes/vp_infer_node.cpp b/nodes/vp_infer_node.cpp
index cc86d8e..96f6ed4 100644
--- a/nodes/vp_infer_node.cpp
+++ b/nodes/vp_infer_node.cpp
@@ -1,5 +1,6 @@
 
 #include <fstream>
+#include <iostream>
 
 #include "vp_infer_node.h"
 
@@ -33,6 +34,8 @@
         // try to load network from file,
         // failing means maybe it has a custom implementation for model loading in derived class such as using other backends other than opencv::dnn.
         try {
+            std::cout << "Model path: " << model_path << std::endl;
+            std::cout << "Model config path: " << model_config_path << std::endl;
             net = cv::dnn::readNet(model_path, model_config_path);
             #ifdef VP_WITH_CUDA
             net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
diff --git a/nodes/vp_rtsp_ffmpeg_src_node.cpp b/nodes/vp_rtsp_ffmpeg_src_node.cpp
index 10e5020..638378e 100644
--- a/nodes/vp_rtsp_ffmpeg_src_node.cpp
+++ b/nodes/vp_rtsp_ffmpeg_src_node.cpp
@@ -59,7 +59,7 @@
                 result += buffer;
             }
             pclose(pipe);
-            VP_INFO(vp_utils::string_format("FFPROBE RESULT:%s ", result));
+            VP_INFO(vp_utils::string_format("FFPROBE RESULT:%s url: %s", result, rtsp_url.c_str()));
 
             // Parse the output (expected format: width,height,r_frame_rate)
             std::stringstream ss(result);
@@ -364,4 +364,4 @@
     {
         return rtsp_url;
     }
-}
+}
\ No newline at end of file
diff --git a/objects/vp_frame_target.h b/objects/vp_frame_target.h
index ea15e50..ac5937e 100644
--- a/objects/vp_frame_target.h
+++ b/objects/vp_frame_target.h
@@ -30,6 +30,10 @@
     public:
         // default person label
         std::string class_label_of_person = "person";
+        // default car label
+        std::string class_label_of_car = "car";
+        // default trush label
+        std::string class_label_of_trush = "trush"; 
         // x of top left
         int x;
         // y of top left
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index 39b7238..a0974a7 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -3,6 +3,29 @@
     message(FATAL_ERROR "can ONLY be called by parent CMakeLists.txt.")
 endif()
 
+# 鏌ユ壘 pkg-config 鍖�
+find_package(PkgConfig REQUIRED)
+
+# 浣跨敤 pkg-config 鏌ユ壘 GStreamer 鍜� gstreamer-rtsp-server
+pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
+pkg_check_modules(GSTREAMER_RTSP_SERVER REQUIRED gstreamer-rtsp-server-1.0)
+
+# 灏� GStreamer 鍜� RTSP 澶存枃浠惰矾寰勬坊鍔犲埌 include 鐩綍涓�
+include_directories(${GSTREAMER_INCLUDE_DIRS} ${GSTREAMER_RTSP_SERVER_INCLUDE_DIRS})
+
+# 灏嗗簱璺緞娣诲姞鍒伴摼鎺ョ洰褰�
+link_directories(${GSTREAMER_LIBRARY_DIRS} ${GSTREAMER_RTSP_SERVER_LIBRARY_DIRS})
+
+# 閫氳繃 pkg-config 鎻愪緵鐨� flags锛岃缃紪璇戝拰閾炬帴鐨� flags
+add_definitions(${GSTREAMER_DEFINITIONS} ${GSTREAMER_RTSP_SERVER_DEFINITIONS})
+
+# 鍦ㄧ紪璇戞椂閾炬帴 GStreamer 鍜� RTSP 鐩稿叧鐨勫簱
+#target_link_libraries(your_target_name 
+#    ${GSTREAMER_LIBRARIES} 
+#    ${GSTREAMER_RTSP_SERVER_LIBRARIES}
+#)
+
+
 message("start build for simple samples...")
 # save all exe to 'build/bin'
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
@@ -167,7 +190,9 @@
 
     add_executable(from_argv_ba_jam_rtsp_m "from_argv_ba_jam_rtsp_m.cpp")
     target_link_libraries(from_argv_ba_jam_rtsp_m ${PROJECT_NAME})
-
+    
+    add_executable(from_argv_ba_jam_rtsp_mr "from_argv_ba_jam_rtsp_mr.cpp")
+    target_link_libraries(from_argv_ba_jam_rtsp_mr ${PROJECT_NAME})
 
     add_executable(from_argv_ba_stop "from_argv_ba_stop.cpp")
     target_link_libraries(from_argv_ba_stop ${PROJECT_NAME})
diff --git a/samples/face_recognize/face_recognize_pipeline b/samples/face_recognize/face_recognize_pipeline
index 45dca69..5103b09 100755
--- a/samples/face_recognize/face_recognize_pipeline
+++ b/samples/face_recognize/face_recognize_pipeline
Binary files differ
diff --git a/samples/from_argv_all_in_one_sample.cpp b/samples/from_argv_all_in_one_sample.cpp
index 4a9a54a..1ecb826 100644
--- a/samples/from_argv_all_in_one_sample.cpp
+++ b/samples/from_argv_all_in_one_sample.cpp
@@ -51,8 +51,8 @@
         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);
+    // create nodes bool cycle = true,  std::string gst_decoder_name = "avdec_h264",  int skip_interval = 0
+    auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, video_path, resize_ratio, true, "avdec_h264",3);
     //auto file_src_1 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_1", 1, "./vp_data/test_video/falldown.mp4", 0.5);
     //auto split = std::make_shared<vp_nodes::vp_split_node>("split", false, true);  // split by deep-copy not by channel!
     
@@ -64,11 +64,13 @@
     
     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)
+    // define a region in frame for every channel (value MUST in the scope of frame'size) (224,74),(346,64),(486,342),(9,342) vp_point(450, 100), vp_objects::vp_point(792, 80), vp_objects::vp_point(1100, 684), vp_objects::vp_point(18, 682)
     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
-    };
+        {0, std::vector<vp_objects::vp_point>{vp_objects::vp_point(int(616*resize_ratio), int(13*resize_ratio)), 
+            vp_objects::vp_point(int(670*resize_ratio), int(11*resize_ratio)), 
+            vp_objects::vp_point(int(1100*resize_ratio), int(684*resize_ratio)), 
+            vp_objects::vp_point(int(18*resize_ratio), int(610*resize_ratio))}},  // channel0 -> region
+     };
     auto ba_jam = std::make_shared<vp_nodes::vp_ba_jam_node>("ba_jam", regions);
     auto ba_stop = std::make_shared<vp_nodes::vp_ba_stop_node>("ba_stop", regions);
     
@@ -79,7 +81,7 @@
     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;
+    int half_screen_width = 640;
     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);
        
     int min_gathering_count = 2;
@@ -90,7 +92,7 @@
     auto ba_report_detect = std::make_shared<vp_nodes::vp_ba_report_detect_node>("ba_report_detect_node","fire_smoke",std::vector<int>{1000,1001,1002}, 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_vehicle", vp_nodes::vp_broke_for::BARESULT);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", "172.18.0.247:9092", "vp_ba_result", vp_nodes::vp_broke_for::BARESULT);
     auto osd_0 = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd_0");
     auto recorder = std::make_shared<vp_nodes::vp_record_node>("recorder", "./record", "./record");
     
@@ -119,8 +121,8 @@
     file_src_0->start();
 
     // for debug purpose
-    vp_utils::vp_analysis_board board({file_src_0});
-    board.display(1, false);
+    // vp_utils::vp_analysis_board board({file_src_0});
+    // board.display(1, false);
 
     std::string wait;
     std::getline(std::cin, wait);
diff --git a/samples/from_argv_ba_crossline.cpp b/samples/from_argv_ba_crossline.cpp
index 5d3cfa8..e008fb2 100644
--- a/samples/from_argv_ba_crossline.cpp
+++ b/samples/from_argv_ba_crossline.cpp
@@ -38,16 +38,17 @@
 
 
     // create nodes
-    auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, video_path, resize_ratio);
+    //auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, video_path, resize_ratio);
+    auto file_src_0 = std::make_shared<vp_nodes::vp_rtsp_ffmpeg_src_node>("rtsp_src_1", 0, video_path, resize_ratio, 3, false); 
     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 start(0, 250);  // change to proper value
-    vp_objects::vp_point end(700, 220);  // change to proper value
+    vp_objects::vp_point start(30, 140);  // change to proper value     0,250
+    vp_objects::vp_point end(610, 110);  // change to proper value     700,220
     std::map<int, vp_objects::vp_line> lines = {{0, vp_objects::vp_line(start, end)}};  // channel0 -> line
     auto ba_crossline = std::make_shared<vp_nodes::vp_ba_crossline_node>("ba_crossline", lines);
-    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", "192.168.130.228:9092", "vp_ba_crossline", vp_nodes::vp_broke_for::BARESULT);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", "172.18.0.247:9092", "vp_ba_result", vp_nodes::vp_broke_for::BARESULT);
     auto osd = std::make_shared<vp_nodes::vp_ba_crossline_osd_node>("osd");
     auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
     
diff --git a/samples/from_argv_ba_crossline_bak.cpp b/samples/from_argv_ba_crossline_bak.cpp
new file mode 100644
index 0000000..5d3cfa8
--- /dev/null
+++ b/samples/from_argv_ba_crossline_bak.cpp
@@ -0,0 +1,71 @@
+#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_crossline_node.h"
+#include "../nodes/osd/vp_ba_crossline_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 "../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 start(0, 250);  // change to proper value
+    vp_objects::vp_point end(700, 220);  // change to proper value
+    std::map<int, vp_objects::vp_line> lines = {{0, vp_objects::vp_line(start, end)}};  // channel0 -> line
+    auto ba_crossline = std::make_shared<vp_nodes::vp_ba_crossline_node>("ba_crossline", lines);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", "192.168.130.228:9092", "vp_ba_crossline", vp_nodes::vp_broke_for::BARESULT);
+    auto osd = std::make_shared<vp_nodes::vp_ba_crossline_osd_node>("osd");
+    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_crossline->attach_to({tracker});
+    json_kafka_broker_0->attach_to({ba_crossline});
+    osd->attach_to({json_kafka_broker_0});
+    screen_des_0->attach_to({osd});
+
+    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_crossline_rtsp.cpp b/samples/from_argv_ba_crossline_rtsp.cpp
index 2f529a1..6cf07f1 100644
--- a/samples/from_argv_ba_crossline_rtsp.cpp
+++ b/samples/from_argv_ba_crossline_rtsp.cpp
@@ -1,6 +1,5 @@
 #include "../nodes/vp_file_src_node.h"
-#include "../nodes/vp_rtsp_src_node.h"
-
+#include "../nodes/vp_rtsp_ffmpeg_src_node.h"
 #include "../nodes/infers/vp_yolo_detector_node.h"
 #include "../nodes/track/vp_sort_track_node.h"
 #include "../nodes/ba/vp_ba_crossline_node.h"
@@ -8,7 +7,6 @@
 #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 "../utils/analysis_board/vp_analysis_board.h"
 
@@ -23,56 +21,54 @@
 
     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.130.228:9092";
+    std::string video_path = "./vp_data/test_video/vehicle_count.mp4";
 
     float resize_ratio = 0.4;
-
+    int channel_index = 0;
+    int skip_interval = 4;
     // 濡傛灉鎻愪緵浜嗙涓�涓拰绗簩涓弬鏁帮紝鍒欒鐩栭粯璁ょ殑璺緞
-    if (args.size() >= 3) {
-        rtsp_path = args[0];
+    if (args.size() >= 4) {
+        video_path = args[0];
         resize_ratio = std::stof(args[1]);
-        kafka_server_point = args[2];
-        
+        channel_index = std::stof(args[2]);
+        skip_interval = std::stof(args[3]);
     } 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.130.228:9092\n";
+        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 rtsp_src_1 = std::make_shared<vp_nodes::vp_rtsp_src_node>("rtsp_src_1", 0, rtsp_path, resize_ratio, "avdec_h264"); 
+    auto file_src_0 = std::make_shared<vp_nodes::vp_rtsp_ffmpeg_src_node>("rtsp_src_"+channel_index, channel_index, video_path, resize_ratio, skip_interval, false); 
     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 start(30, 140);  // change to proper value     0,250
     vp_objects::vp_point end(610, 110);  // change to proper value     700,220
-    std::map<int, vp_objects::vp_line> lines = {{0, vp_objects::vp_line(start, end)}};  // channel0 -> line
+    std::map<int, vp_objects::vp_line> lines = {{channel_index, vp_objects::vp_line(start, end)}};  // channel0 -> line
     auto ba_crossline = std::make_shared<vp_nodes::vp_ba_crossline_node>("ba_crossline", lines);
-    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", kafka_server_point, "vp_ba_crossline", vp_nodes::vp_broke_for::BARESULT);
+    auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_"+channel_index, "172.18.0.247:9092", "vp_ba_result", vp_nodes::vp_broke_for::BARESULT);
     auto osd = std::make_shared<vp_nodes::vp_ba_crossline_osd_node>("osd");
-    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);
+    auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", channel_index);
     
     // construct pipeline
-    yolo_detector->attach_to({rtsp_src_1});
+    yolo_detector->attach_to({file_src_0});
     tracker->attach_to({yolo_detector});
     ba_crossline->attach_to({tracker});
     json_kafka_broker_0->attach_to({ba_crossline});
     osd->attach_to({json_kafka_broker_0});
     screen_des_0->attach_to({osd});
-    file_des_node_0->attach_to({osd});
 
-    rtsp_src_1->start();
+    file_src_0->start();
 
     // for debug purpose
-    vp_utils::vp_analysis_board board({rtsp_src_1});
+    vp_utils::vp_analysis_board board({file_src_0});
     board.display(1, false);
 
     std::string wait;
     std::getline(std::cin, wait);
-    rtsp_src_1->detach_recursively();
+    file_src_0->detach_recursively();
 }
\ No newline at end of file
diff --git a/samples/from_argv_ba_crossline_rtsp_mr.cpp b/samples/from_argv_ba_crossline_rtsp_mr.cpp
new file mode 100644
index 0000000..3a7e7d8
--- /dev/null
+++ b/samples/from_argv_ba_crossline_rtsp_mr.cpp
@@ -0,0 +1,200 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+#include "../nodes/vp_rtsp_ffmpeg_src_node.h"
+#include "../nodes/vp_split_node.h"
+#include "../nodes/infers/vp_trt_vehicle_detector.h"
+#include "../nodes/infers/vp_trt_vehicle_plate_detector.h"
+#include "../nodes/infers/vp_trt_vehicle_color_classifier.h"
+#include "../nodes/infers/vp_yolo_detector_node.h"
+
+#include "../nodes/osd/vp_osd_node.h"
+#include "../nodes/vp_sync_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_crossline_node.h"
+#include "../nodes/osd/vp_ba_crossline_osd_node.h"
+
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/record/vp_record_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/vp_fake_des_node.h"
+#include "../nodes/vp_placeholder_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include <map>
+#include <sstream>
+
+// Function to read configuration from a file
+std::vector<std::vector<std::string>> read_config_file(const std::string& file_path) {
+    std::vector<std::vector<std::string>> config_lines;
+    std::string line;
+    try {
+        std::ifstream infile(file_path);
+        while (std::getline(infile, line)) {
+            std::vector<std::string> params;
+            size_t start = 0;
+            size_t end = line.find(" ");
+            while (end != std::string::npos) {
+                params.push_back(line.substr(start, end - start));
+                start = end + 1;
+                end = line.find(" ", start);
+            }
+            params.push_back(line.substr(start, end));  // add the last parameter
+            config_lines.push_back(params);
+        }
+    } catch (const std::exception& e) {
+        std::cerr << "read config file ex: " << std::string(e.what()) << " <config_file>\n";
+    } catch (...) {
+        std::cerr << "read config file ex end1111\n";
+    }
+    return config_lines;
+}
+
+// Function to parse polygon coordinates from string
+std::vector<vp_objects::vp_point> parse_polygon(const std::string& polygon_str, float resize_ratio) {
+    std::vector<vp_objects::vp_point> polygon;
+    std::stringstream ss(polygon_str);
+    std::string point_str;
+    while (std::getline(ss, point_str, ')')) {
+        size_t start = point_str.find('(');
+        if (start != std::string::npos) {
+            std::string coordinates = point_str.substr(start + 1);
+            size_t comma_pos = coordinates.find(',');
+            if (comma_pos != std::string::npos) {
+                int x = std::stoi(coordinates.substr(0, comma_pos));
+                int y = std::stoi(coordinates.substr(comma_pos + 1));
+                x = static_cast<int>(std::round(x * resize_ratio));
+                y = static_cast<int>(std::round(y * resize_ratio));
+                polygon.push_back(vp_objects::vp_point(x, y));
+            }
+        }
+    }
+    return polygon;
+}
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+    // Read configuration file
+    if (argc < 2) {
+        std::cerr << "Usage: " << argv[0] << " <config_file>\n";
+        return -1;
+    }
+
+    try {
+        std::string config_file = argv[1];
+        auto configs = read_config_file(config_file);
+        VP_INFO(vp_utils::string_format("Launch a thread for each configuration  [%s]", config_file));
+
+        // Correct type declarations
+        std::string kafka_server_point = "";
+        std::vector<std::string> rtsp_srcs;
+        std::vector<int> channel_indexs;
+        std::vector<int> skip_intervals;
+        std::vector<bool> use_gpus;
+        std::vector<float> resize_ratios;
+
+        // Use shared pointers for nodes
+        std::vector<std::shared_ptr<vp_nodes::vp_node>> rtsp_nodes;
+        // std::vector<std::shared_ptr<vp_nodes::vp_src_node>> rtsp_nodes;
+        // Des鑺傜偣
+        std::vector<std::shared_ptr<vp_nodes::vp_des_node>> des_nodes;
+
+        // define a region in frame for every channel (value MUST in the scope of frame'size)
+        std::map<int, vp_objects::vp_line> lines = {};
+
+        for (const auto& config : configs) {
+            if (config.size() >= 5) {
+                float resize_ratio = std::stof(config[1]);
+                int skip_interval = std::stoi(config[3]);
+                int channel_index = std::stoi(config[4]);
+                bool usegpu = config.size() >= 6 && config[5] == "1";
+
+                rtsp_srcs.push_back(config[0]);
+                resize_ratios.push_back(resize_ratio);
+                kafka_server_point = config[2];
+                skip_intervals.push_back(skip_interval);
+                channel_indexs.push_back(channel_index);
+                use_gpus.push_back(usegpu);
+
+                // Read and parse the polygon coordinates
+                if (config.size() >= 7) {
+                    std::string polygon_str = config[6];  // Assuming the polygon coordinates are in the 7th column
+                    vp_objects::vp_point start(30, 140);  // change to proper value     0,250
+                    vp_objects::vp_point end(610, 110);  // change to proper value     700,220
+                    lines[channel_index] = vp_objects::vp_line(start, end);
+                } else {
+                    vp_objects::vp_point start(30, 140);  // change to proper value     0,250
+                    vp_objects::vp_point end(610, 110);  // change to proper value     700,220
+                    lines[channel_index] = vp_objects::vp_line(start, end);
+                }
+
+                rtsp_nodes.push_back(std::make_shared<vp_nodes::vp_rtsp_ffmpeg_src_node>(
+                    "rtsp_src_" + config[4], channel_index, config[0], resize_ratio, skip_interval, usegpu));
+
+                des_nodes.push_back(std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_" + config[4], channel_index));
+
+            } else {
+                std::cerr << "Invalid config line: ";
+                for (const auto& param : config) {
+                    std::cerr << param << " ";
+                }
+                std::cerr << "\n";
+            }
+        }
+
+        // branch 0
+        auto vehicle_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("vehicle_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");
+
+        // vp_objects::vp_point start(30, 140);  // change to proper value     0,250
+        // vp_objects::vp_point end(610, 110);  // change to proper value     700,220
+        // std::map<int, vp_objects::vp_line> lines = {{channel_index, vp_objects::vp_line(start, end)}};  // channel0 -> line
+        auto ba_crossline = std::make_shared<vp_nodes::vp_ba_crossline_node>("ba_crossline", lines);
+
+        auto json_kafka_broker_0 = std::make_shared<vp_nodes::vp_json_kafka_broker_node>("json_kafka_broker_0", kafka_server_point, "vp_ba_result", vp_nodes::vp_broke_for::BARESULT);
+        auto osd = std::make_shared<vp_nodes::vp_ba_crossline_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);
+
+        // for testing. USING fake_des node in production    
+        auto fake_des_0 = std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_0", 0);
+
+        // construct pipeline
+        vehicle_detector->attach_to(rtsp_nodes);
+        tracker->attach_to({vehicle_detector});
+        ba_crossline->attach_to({tracker});
+        json_kafka_broker_0->attach_to({ba_crossline});
+        osd->attach_to({json_kafka_broker_0});
+
+        recorder->attach_to({osd});
+        split->attach_to({recorder});  
+
+        for (size_t i = 0; i < des_nodes.size(); ++i) {
+            des_nodes[i]->attach_to({split});
+        }
+
+        for (auto node : rtsp_nodes) {
+            ((vp_nodes::vp_src_node*)node.get())->start();
+        }
+
+        std::string wait;
+        std::getline(std::cin, wait);
+
+        for (auto node : rtsp_nodes) {
+            ((vp_nodes::vp_src_node*)node.get())->detach_recursively();
+        }
+
+    } catch (const std::exception& e) {
+        std::cerr << "read config file ex: " << std::string(e.what()) << " <config_file>\n";
+    } catch (...) {
+        std::cerr << "read config file ex end\n";
+    }
+
+    return 0;
+}
\ No newline at end of file
diff --git a/samples/from_argv_ba_jam_rtsp_m.cpp b/samples/from_argv_ba_jam_rtsp_m.cpp
index 42941c0..2e2e692 100644
--- a/samples/from_argv_ba_jam_rtsp_m.cpp
+++ b/samples/from_argv_ba_jam_rtsp_m.cpp
@@ -110,7 +110,8 @@
                 rtsp_nodes.push_back(std::make_shared<vp_nodes::vp_rtsp_ffmpeg_src_node>(
                     "rtsp_src_" + config[4], channel_index, config[0], resize_ratio, skip_interval, usegpu));
 
-                des_nodes.push_back(std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_" + config[4], channel_index));
+                //des_nodes.push_back(std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_" + config[4], channel_index));
+                des_nodes.push_back(std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_" + config[4], channel_index));
 
             } else {
                 std::cerr << "Invalid config line: ";
@@ -136,9 +137,7 @@
         auto osd_0 = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd_0", "./vp_data/font/NotoSansCJKsc-Medium.otf");
         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);
-
-        // for testing. USING fake_des node in production    
-        auto fake_des_0 = std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_0", 0);
+      
 
         // construct pipeline
         vehicle_detector->attach_to(rtsp_nodes);
@@ -162,8 +161,8 @@
         }
 
         // for debug purpose
-        // vp_utils::vp_analysis_board board(rtsp_nodes);
-        // board.display(1, false);
+        vp_utils::vp_analysis_board board(rtsp_nodes);
+        board.display(1, true);
 
         std::string wait;
         std::getline(std::cin, wait);
diff --git a/samples/from_argv_ba_jam_rtsp_mr.cpp b/samples/from_argv_ba_jam_rtsp_mr.cpp
new file mode 100644
index 0000000..62a6a65
--- /dev/null
+++ b/samples/from_argv_ba_jam_rtsp_mr.cpp
@@ -0,0 +1,206 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+#include "../nodes/vp_rtsp_ffmpeg_src_node.h"
+#include "../nodes/vp_split_node.h"
+#include "../nodes/infers/vp_trt_vehicle_detector.h"
+#include "../nodes/infers/vp_trt_vehicle_plate_detector.h"
+#include "../nodes/infers/vp_trt_vehicle_color_classifier.h"
+#include "../nodes/infers/vp_yolo_detector_node.h"
+
+#include "../nodes/osd/vp_osd_node.h"
+#include "../nodes/vp_sync_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_jam_node.h"
+#include "../nodes/ba/vp_ba_stop_node.h"
+
+#include "../nodes/osd/vp_ba_stop_osd_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/record/vp_record_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/vp_fake_des_node.h"
+#include "../nodes/vp_placeholder_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include <map>
+#include <sstream>
+
+// Function to read configuration from a file
+std::vector<std::vector<std::string>> read_config_file(const std::string& file_path) {
+    std::vector<std::vector<std::string>> config_lines;
+    std::string line;
+    try {
+        std::ifstream infile(file_path);
+        while (std::getline(infile, line)) {
+            std::vector<std::string> params;
+            size_t start = 0;
+            size_t end = line.find(" ");
+            while (end != std::string::npos) {
+                params.push_back(line.substr(start, end - start));
+                start = end + 1;
+                end = line.find(" ", start);
+            }
+            params.push_back(line.substr(start, end));  // add the last parameter
+            config_lines.push_back(params);
+        }
+    } catch (const std::exception& e) {
+        std::cerr << "read config file ex: " << std::string(e.what()) << " <config_file>\n";
+    } catch (...) {
+        std::cerr << "read config file ex end1111\n";
+    }
+    return config_lines;
+}
+
+// Function to parse polygon coordinates from string
+std::vector<vp_objects::vp_point> parse_polygon(const std::string& polygon_str, float resize_ratio) {
+    std::vector<vp_objects::vp_point> polygon;
+    std::stringstream ss(polygon_str);
+    std::string point_str;
+    while (std::getline(ss, point_str, ')')) {
+        size_t start = point_str.find('(');
+        if (start != std::string::npos) {
+            std::string coordinates = point_str.substr(start + 1);
+            size_t comma_pos = coordinates.find(',');
+            if (comma_pos != std::string::npos) {
+                int x = std::stoi(coordinates.substr(0, comma_pos));
+                int y = std::stoi(coordinates.substr(comma_pos + 1));
+                x = static_cast<int>(std::round(x * resize_ratio));
+                y = static_cast<int>(std::round(y * resize_ratio));
+                polygon.push_back(vp_objects::vp_point(x, y));
+            }
+        }
+    }
+    return polygon;
+}
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+    // Read configuration file
+    if (argc < 2) {
+        std::cerr << "Usage: " << argv[0] << " <config_file>\n";
+        return -1;
+    }
+
+    try {
+        std::string config_file = argv[1];
+        auto configs = read_config_file(config_file);
+        VP_INFO(vp_utils::string_format("Launch a thread for each configuration  [%s]", config_file));
+
+        // Correct type declarations
+        std::string kafka_server_point = "";
+        std::vector<std::string> rtsp_srcs;
+        std::vector<int> channel_indexs;
+        std::vector<int> skip_intervals;
+        std::vector<bool> use_gpus;
+        std::vector<float> resize_ratios;
+
+        // Use shared pointers for nodes
+        std::vector<std::shared_ptr<vp_nodes::vp_node>> rtsp_nodes;
+        // std::vector<std::shared_ptr<vp_nodes::vp_src_node>> rtsp_nodes;
+        // Des鑺傜偣
+        std::vector<std::shared_ptr<vp_nodes::vp_des_node>> des_nodes;
+
+        // 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 = {};
+
+        for (const auto& config : configs) {
+            if (config.size() >= 5) {
+                float resize_ratio = std::stof(config[1]);
+                int skip_interval = std::stoi(config[3]);
+                int channel_index = std::stoi(config[4]);
+                bool usegpu = config.size() >= 6 && config[5] == "1";
+
+                rtsp_srcs.push_back(config[0]);
+                resize_ratios.push_back(resize_ratio);
+                kafka_server_point = config[2];
+                skip_intervals.push_back(skip_interval);
+                channel_indexs.push_back(channel_index);
+                use_gpus.push_back(usegpu);
+
+                // Read and parse the polygon coordinates
+                if (config.size() >= 7) {
+                    std::string polygon_str = config[6];  // Assuming the polygon coordinates are in the 7th column
+                    regions[channel_index] = parse_polygon(polygon_str,resize_ratio);
+                } else {
+                    // Default region if polygon is not provided
+                    regions[channel_index] = std::vector<vp_objects::vp_point>{
+                        vp_objects::vp_point(280, 30),
+                        vp_objects::vp_point(340, 30),
+                        vp_objects::vp_point(600, 330),
+                        vp_objects::vp_point(30, 350)
+                    };
+                }
+
+                rtsp_nodes.push_back(std::make_shared<vp_nodes::vp_rtsp_ffmpeg_src_node>(
+                    "rtsp_src_" + config[4], channel_index, config[0], resize_ratio, skip_interval, usegpu));
+
+                des_nodes.push_back(std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_" + config[4], channel_index));
+
+            } else {
+                std::cerr << "Invalid config line: ";
+                for (const auto& param : config) {
+                    std::cerr << param << " ";
+                }
+                std::cerr << "\n";
+            }
+        }
+
+        // branch 0
+        auto vehicle_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("vehicle_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 trt_vehicle_plate_detector = std::make_shared<vp_nodes::vp_trt_vehicle_plate_detector>("vehicle_plate_detector", "./vp_data/models/trt/plate/vehicle_plate_box_detection.trt", "./vp_data/models/trt/plate/vehicle_plate_text_recognition.trt");
+        auto trt_vehicle_color_classifier = std::make_shared<vp_nodes::vp_trt_vehicle_color_classifier>("color_cls", "./vp_data/models/trt/vehicle/vehicle_color_detection.trt", std::vector<int>{0, 1, 2});
+
+        auto tracker = std::make_shared<vp_nodes::vp_sort_track_node>("sort_tracker");
+
+        auto ba_jam = std::make_shared<vp_nodes::vp_ba_jam_node>("ba_jam", regions);
+        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_result", vp_nodes::vp_broke_for::BARESULT);
+        auto osd_0 = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd_0", "./vp_data/font/NotoSansCJKsc-Medium.otf");
+        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);
+
+        // for testing. USING fake_des node in production    
+        auto fake_des_0 = std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_0", 0);
+
+        // construct pipeline
+        vehicle_detector->attach_to(rtsp_nodes);
+        trt_vehicle_plate_detector->attach_to({vehicle_detector});
+        trt_vehicle_color_classifier->attach_to({trt_vehicle_plate_detector});
+        tracker->attach_to({trt_vehicle_color_classifier});
+        ba_jam->attach_to({tracker});
+        ba_stop->attach_to({ba_jam});
+        json_kafka_broker_0->attach_to({ba_stop});
+        osd_0->attach_to({json_kafka_broker_0});
+
+        recorder->attach_to({osd_0});
+        split->attach_to({recorder});  
+
+        for (size_t i = 0; i < des_nodes.size(); ++i) {
+            des_nodes[i]->attach_to({split});
+        }
+
+        for (auto node : rtsp_nodes) {
+            ((vp_nodes::vp_src_node*)node.get())->start();
+        }
+
+        std::string wait;
+        std::getline(std::cin, wait);
+
+        for (auto node : rtsp_nodes) {
+            ((vp_nodes::vp_src_node*)node.get())->detach_recursively();
+        }
+
+    } catch (const std::exception& e) {
+        std::cerr << "read config file ex: " << std::string(e.what()) << " <config_file>\n";
+    } catch (...) {
+        std::cerr << "read config file ex end\n";
+    }
+
+    return 0;
+}
\ No newline at end of file
diff --git a/samples/from_argv_test_width.cpp b/samples/from_argv_test_width.cpp
new file mode 100644
index 0000000..0e66103
--- /dev/null
+++ b/samples/from_argv_test_width.cpp
@@ -0,0 +1,140 @@
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <regex>
+#include <cmath>
+#include <limits>
+
+using namespace std;
+
+// 瀹氫箟涓�涓粨鏋勪綋鏉ヤ繚瀛樻瘡涓�琛岀殑鍊�
+struct TargetData {
+    int id;
+    double x, y, width, height;
+};
+
+// 璇诲彇鏃ュ織鏂囦欢骞舵彁鍙栫洰鏍囨暟鎹�
+vector<TargetData> readLogFile(const string& filepath) {
+    vector<TargetData> data;
+    ifstream file(filepath);
+    string line;
+
+    // 姝e垯琛ㄨ揪寮忔潵鍖归厤Target ID鍚庣殑浜斾釜鍊�
+    regex targetRegex("Target ID: (-?\\d+),\\s*(-?\\d+),\\s*(-?\\d+),\\s*(-?\\d+),\\s*(-?\\d+)");
+
+    while (getline(file, line)) {
+        smatch matches;
+        if (regex_search(line, matches, targetRegex)) {
+            TargetData target;
+            target.id = stoi(matches[1].str());
+            target.x = stod(matches[2].str());
+            target.y = stod(matches[3].str());
+            target.width = stod(matches[4].str());
+            target.height = stod(matches[5].str());
+
+            data.push_back(target);
+        }
+    }
+    return data;
+}
+
+// 娓呮礂鏁版嵁锛屽幓鎺夋í鍧愭爣灏忎簬100鎴栧ぇ浜�600鐨勬暟鎹紝浠ュ強鏋佺鍊�
+void cleanData(vector<TargetData>& data, double n) {
+    // 璁$畻骞冲潎鍊�
+    double sum = 0;
+    for (const auto& target : data) {
+        sum += target.width;
+    }
+    double mean = sum / data.size();
+
+    // 璁$畻鏍囧噯宸�
+    double variance = 0;
+    for (const auto& target : data) {
+        variance += pow(target.width - mean, 2);
+    }
+    double stddev = sqrt(variance / data.size());
+
+    // 鏍规嵁璇樊绯绘暟鑼冨洿n娓呮礂鏁版嵁
+    vector<TargetData> cleanedData;
+    for (const auto& target : data) {
+        // 娣诲姞鏉′欢锛屽幓鎺夋í鍧愭爣灏忎簬100鎴栧ぇ浜�600鐨勬暟鎹�
+        if (target.x >= 100 && target.x <= 600 &&
+            abs(target.width - mean) <= n * stddev) {
+            cleanedData.push_back(target);
+        }
+    }
+
+    data = cleanedData;
+}
+
+// 鐢ㄦ渶灏忎簩涔樻硶鏉ヨ绠楃嚎鎬у洖褰掔殑鍙傛暟 (width = a * y + b)
+void fitLinearModel(const vector<TargetData>& data, double& a, double& b) {
+    int n = data.size();
+    double sum_y = 0, sum_width = 0, sum_yy = 0, sum_yw = 0;
+
+    // 璁$畻鎵�闇�鐨勭疮鍔犲拰
+    for (const auto& target : data) {
+        sum_y += target.y;
+        sum_width += target.width;
+        sum_yy += target.y * target.y;
+        sum_yw += target.y * target.width;
+    }
+
+    // 璁$畻绾挎�у洖褰掔殑绯绘暟 a 鍜� b
+    double denominator = n * sum_yy - sum_y * sum_y;
+    if (denominator == 0) {
+        a = 0;
+        b = 0;
+        return;
+    }
+
+    a = (n * sum_yw - sum_y * sum_width) / denominator;
+    b = (sum_yy * sum_width - sum_y * sum_yw) / denominator;
+}
+
+// 杈撳嚭鎷熷悎缁撴灉
+void printFitEquation(double a, double b) {
+    cout << "鎷熷悎缁撴灉: width = " << a << " * y + " << b << endl;
+}
+
+// 鎵撳嵃data涓殑鎵�鏈夋暟鎹�
+void printData(const vector<TargetData>& data) {
+    for (const auto& target : data) {
+        cout << "ID: " << target.id 
+             << ", x: " << target.x 
+             << ", y: " << target.y 
+             << ", width: " << target.width 
+             << ", height: " << target.height << endl;
+    }
+}
+
+
+int main(int argc, char* argv[]) {
+    if (argc < 3) {
+        cout << "浣跨敤鏂规硶: " << argv[0] << " <鏃ュ織鏂囦欢璺緞> <璇樊绯绘暟鑼冨洿>" << endl;
+        return 1;
+    }
+
+    string logFilePath = argv[1];
+    double n = stod(argv[2]);  // 璇樊绯绘暟鑼冨洿
+
+    // 璇诲彇鏃ュ織鏂囦欢涓殑鐩爣鏁版嵁
+    vector<TargetData> data = readLogFile(logFilePath);
+
+    // 鏁版嵁娓呮礂
+    cleanData(data, n);
+
+    // 鎵撳嵃娓呮礂鍚庣殑鏁版嵁
+    cout << "\n娓呮礂鍚庣殑鏁版嵁:" << endl;
+    printData(data);
+
+    // 浣跨敤鏈�灏忎簩涔樻硶鎷熷悎鏁版嵁
+    double a, b;
+    fitLinearModel(data, a, b);
+
+    // 杈撳嚭鎷熷悎鐨勫嚱鏁板叕寮�
+    printFitEquation(a, b);
+
+    return 0;
+}
\ No newline at end of file
diff --git a/samples/from_argv_width_calibration.cpp b/samples/from_argv_width_calibration.cpp
new file mode 100644
index 0000000..be0957e
--- /dev/null
+++ b/samples/from_argv_width_calibration.cpp
@@ -0,0 +1,199 @@
+#include "../nodes/vp_file_src_node.h"
+#include "../nodes/vp_rtsp_src_node.h"
+#include "../nodes/vp_rtsp_ffmpeg_src_node.h"
+#include "../nodes/vp_split_node.h"
+#include "../nodes/infers/vp_trt_vehicle_detector.h"
+#include "../nodes/infers/vp_trt_vehicle_plate_detector.h"
+#include "../nodes/infers/vp_trt_vehicle_color_classifier.h"
+#include "../nodes/infers/vp_yolo_detector_node.h"
+
+#include "../nodes/osd/vp_osd_node.h"
+#include "../nodes/vp_sync_node.h"
+#include "../nodes/track/vp_sort_track_node.h"
+#include "../nodes/ba/vp_ba_jam_node.h"
+#include "../nodes/ba/vp_ba_stop_node.h"
+
+#include "../nodes/osd/vp_ba_stop_osd_node.h"
+#include "../nodes/broker/vp_json_kafka_broker_node.h"
+#include "../nodes/record/vp_record_node.h"
+#include "../nodes/vp_screen_des_node.h"
+#include "../nodes/vp_fake_des_node.h"
+#include "../nodes/vp_placeholder_node.h"
+
+#include "../utils/analysis_board/vp_analysis_board.h"
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include <map>
+#include <sstream>
+
+// Function to read configuration from a file
+std::vector<std::vector<std::string>> read_config_file(const std::string& file_path) {
+    std::vector<std::vector<std::string>> config_lines;
+    std::string line;
+    try {
+        std::ifstream infile(file_path);
+        while (std::getline(infile, line)) {
+            std::vector<std::string> params;
+            size_t start = 0;
+            size_t end = line.find(" ");
+            while (end != std::string::npos) {
+                params.push_back(line.substr(start, end - start));
+                start = end + 1;
+                end = line.find(" ", start);
+            }
+            params.push_back(line.substr(start, end));  // add the last parameter
+            config_lines.push_back(params);
+        }
+    } catch (const std::exception& e) {
+        std::cerr << "read config file ex: " << std::string(e.what()) << " <config_file>\n";
+    } catch (...) {
+        std::cerr << "read config file ex end1111\n";
+    }
+    return config_lines;
+}
+
+// Function to parse polygon coordinates from string
+std::vector<vp_objects::vp_point> parse_polygon(const std::string& polygon_str, float resize_ratio) {
+    std::vector<vp_objects::vp_point> polygon;
+    std::stringstream ss(polygon_str);
+    std::string point_str;
+    while (std::getline(ss, point_str, ')')) {
+        size_t start = point_str.find('(');
+        if (start != std::string::npos) {
+            std::string coordinates = point_str.substr(start + 1);
+            size_t comma_pos = coordinates.find(',');
+            if (comma_pos != std::string::npos) {
+                int x = std::stoi(coordinates.substr(0, comma_pos));
+                int y = std::stoi(coordinates.substr(comma_pos + 1));
+                x = static_cast<int>(std::round(x * resize_ratio));
+                y = static_cast<int>(std::round(y * resize_ratio));
+                polygon.push_back(vp_objects::vp_point(x, y));
+            }
+        }
+    }
+    return polygon;
+}
+
+int main(int argc, char* argv[]) {
+    VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
+    VP_LOGGER_INIT();
+    // Read configuration file
+    if (argc < 2) {
+        std::cerr << "Usage: " << argv[0] << " <config_file>\n";
+        return -1;
+    }
+
+    try {
+        std::string config_file = argv[1];
+        auto configs = read_config_file(config_file);
+        VP_INFO(vp_utils::string_format("Launch a thread for each configuration  [%s]", config_file));
+
+        // Correct type declarations
+        std::string kafka_server_point = "";
+        std::vector<std::string> rtsp_srcs;
+        std::vector<int> channel_indexs;
+        std::vector<int> skip_intervals;
+        std::vector<bool> use_gpus;
+        std::vector<float> resize_ratios;
+
+        // Use shared pointers for nodes
+        std::vector<std::shared_ptr<vp_nodes::vp_node>> rtsp_nodes;
+        // std::vector<std::shared_ptr<vp_nodes::vp_src_node>> rtsp_nodes;
+        // Des鑺傜偣
+        std::vector<std::shared_ptr<vp_nodes::vp_des_node>> des_nodes;
+
+        // 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 = {};
+
+        for (const auto& config : configs) {
+            if (config.size() >= 5) {
+                float resize_ratio = std::stof(config[1]);
+                int skip_interval = std::stoi(config[3]);
+                int channel_index = std::stoi(config[4]);
+                bool usegpu = config.size() >= 6 && config[5] == "1";
+
+                rtsp_srcs.push_back(config[0]);
+                resize_ratios.push_back(resize_ratio);
+                kafka_server_point = config[2];
+                skip_intervals.push_back(skip_interval);
+                channel_indexs.push_back(channel_index);
+                use_gpus.push_back(usegpu);
+
+                // Read and parse the polygon coordinates
+                if (config.size() >= 7) {
+                    std::string polygon_str = config[6];  // Assuming the polygon coordinates are in the 7th column
+                    regions[channel_index] = parse_polygon(polygon_str,resize_ratio);
+                } else {
+                    // Default region if polygon is not provided
+                    regions[channel_index] = std::vector<vp_objects::vp_point>{
+                        vp_objects::vp_point(280, 30),
+                        vp_objects::vp_point(340, 30),
+                        vp_objects::vp_point(600, 330),
+                        vp_objects::vp_point(30, 350)
+                    };
+                }
+
+                rtsp_nodes.push_back(std::make_shared<vp_nodes::vp_rtsp_ffmpeg_src_node>(
+                    "rtsp_src_" + config[4], channel_index, config[0], resize_ratio, skip_interval, usegpu));
+
+                des_nodes.push_back(std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_" + config[4], channel_index));
+
+            } else {
+                std::cerr << "Invalid config line: ";
+                for (const auto& param : config) {
+                    std::cerr << param << " ";
+                }
+                std::cerr << "\n";
+            }
+        }
+
+        // branch 0
+        auto vehicle_detector = std::make_shared<vp_nodes::vp_yolo_detector_node>("vehicle_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");
+
+        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_tracker", vp_nodes::vp_broke_for::BARESULT);
+        auto osd_0 = std::make_shared<vp_nodes::vp_ba_stop_osd_node>("osd_0", "./vp_data/font/NotoSansCJKsc-Medium.otf");
+        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);
+
+        // for testing. USING fake_des node in production    
+        auto fake_des_0 = std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_0", 0);
+
+        // construct pipeline
+        vehicle_detector->attach_to(rtsp_nodes);
+        tracker->attach_to({vehicle_detector});
+        ba_stop->attach_to({tracker});
+        json_kafka_broker_0->attach_to({ba_stop});
+        osd_0->attach_to({json_kafka_broker_0});
+
+        recorder->attach_to({osd_0});
+        split->attach_to({recorder});  
+
+        for (size_t i = 0; i < des_nodes.size(); ++i) {
+            des_nodes[i]->attach_to({split});
+        }
+
+        for (auto node : rtsp_nodes) {
+            ((vp_nodes::vp_src_node*)node.get())->start();
+        }
+
+        std::string wait;
+        std::getline(std::cin, wait);
+
+        for (auto node : rtsp_nodes) {
+            ((vp_nodes::vp_src_node*)node.get())->detach_recursively();
+        }
+
+    } catch (const std::exception& e) {
+        std::cerr << "read config file ex: " << std::string(e.what()) << " <config_file>\n";
+    } catch (...) {
+        std::cerr << "read config file ex end\n";
+    }
+
+    return 0;
+}
\ No newline at end of file
diff --git a/samples/lpr_camera/plate_recognize_pipeline b/samples/lpr_camera/plate_recognize_pipeline
index 284a458..628526f 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 5338752..32ac0a7 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 ecd62d4..a3a0e41 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 02e6f2d..62d8f42 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 b9e8f64..1e62e4d 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