新增ROI

This commit is contained in:
shan 2026-01-07 15:40:08 +08:00
commit dd3e4ecf08
123 changed files with 20268 additions and 0 deletions

81
.gitignore vendored Normal file
View File

@ -0,0 +1,81 @@
############################
# 视频文件(全部忽略)
############################
*.mp4
*.avi
*.mov
*.mkv
*.flv
*.wmv
*.webm
*.rm
*.rmvb
*.ts
*.m3u8
############################
# 图片文件(全部忽略)
############################
*.jpg
*.jpeg
*.png
*.bmp
*.tiff
*.tif
*.gif
*.webp
############################
# YOLO / TensorRT 模型文件
############################
*.pt
*.onnx
*.wts
*.engine
# 只保留 best.engine
!best.engine
############################
# CMake / 编译生成文件(忽略)
############################
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
Makefile
*.o
*.a
*.so
*.dll
*.exe
############################
# build 目录规则
############################
# 忽略默认 build 目录
build/
# ❗保留你指定的 build_XXXXXX 目录
!build_*/
############################
# Python 缓存(忽略)
############################
__pycache__/
*.pyc
*.pyo
############################
# 日志 / 临时文件
############################
*.log
*.tmp
*.swp
*.bak
############################
# 系统文件
############################
.DS_Store
Thumbs.db

5
001测试拼接列表.py Normal file
View File

@ -0,0 +1,5 @@
l = ["a", "b", "c", "d"]
print('_'.join(l))

65
CMakeLists.txt Normal file
View File

@ -0,0 +1,65 @@
cmake_minimum_required(VERSION 3.10)
project(yolov8)
add_definitions(-std=c++11)
add_definitions(-DAPI_EXPORTS)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CUDA_COMPILER /usr/bin/nvcc)
enable_language(CUDA)
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/plugin)
# include and link dirs of cuda and tensorrt, you need adapt them if yours are different
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
message("embed_platform on")
include_directories(/usr/local/cuda/targets/aarch64-linux/include)
link_directories(/usr/local/cuda/targets/aarch64-linux/lib)
else()
message("embed_platform off")
# cuda
include_directories(/usr/local/cuda-12.4/include)
link_directories(/usr/local/cuda-12.4/lib64)
# tensorrt
include_directories(/home/admin-root/software/TensorRT-8.6.1.6/include)
link_directories(/home/admin-root/software/TensorRT-8.6.1.6/lib)
# include_directories(/home/lindsay/TensorRT-7.2.3.4/include)
# link_directories(/home/lindsay/TensorRT-7.2.3.4/lib)
endif()
add_library(myplugins SHARED ${PROJECT_SOURCE_DIR}/plugin/yololayer.cu)
target_link_libraries(myplugins nvinfer cudart)
find_package(OpenCV)
include_directories(${OpenCV_INCLUDE_DIRS})
file(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp ${PROJECT_SOURCE_DIR}/src/*.cu)
add_executable(yolov8_det ${PROJECT_SOURCE_DIR}/yolov8_det.cpp ${SRCS})
target_link_libraries(yolov8_det nvinfer)
target_link_libraries(yolov8_det cudart)
target_link_libraries(yolov8_det myplugins)
target_link_libraries(yolov8_det ${OpenCV_LIBS})
add_executable(yolov8_seg ${PROJECT_SOURCE_DIR}/yolov8_seg.cpp ${SRCS})
target_link_libraries(yolov8_seg nvinfer cudart myplugins ${OpenCV_LIBS})
add_executable(yolov8_pose ${PROJECT_SOURCE_DIR}/yolov8_pose.cpp ${SRCS})
target_link_libraries(yolov8_pose nvinfer cudart myplugins ${OpenCV_LIBS})
add_executable(yolov8_cls ${PROJECT_SOURCE_DIR}/yolov8_cls.cpp ${SRCS})
target_link_libraries(yolov8_cls nvinfer cudart myplugins ${OpenCV_LIBS})
add_executable(yolov8_5u_det ${PROJECT_SOURCE_DIR}/yolov8_5u_det.cpp ${SRCS})
target_link_libraries(yolov8_5u_det nvinfer cudart myplugins ${OpenCV_LIBS})
add_executable(yolov8_obb ${PROJECT_SOURCE_DIR}/yolov8_obb.cpp ${SRCS})
target_link_libraries(yolov8_obb nvinfer cudart myplugins ${OpenCV_LIBS})

250
README.md Normal file
View File

@ -0,0 +1,250 @@
# YOLOv8 TensorRT 视频检测系统
该程序主要分为以下几个模块:
### 1. 配置与初始化模块
- 读取配置文件config.yaml
- 初始化各种配置参数(视频路径、模型路径、检测类别等)
- 初始化MinIO客户端、人脸识别服务等
### 2. 视频流处理模块
- RTSP视频流读取与缓冲
- 视频帧预处理调整为1280x720分辨率
- 多线程视频流处理
### 3. YOLOv8推理模块
- **位置**: [d8_5.py](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py) 文件中的 [YoLov8TRT](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py#L617-L887) 类 (第617-887行)
- 功能TensorRT引擎加载与推理、图像预处理与后处理、目标检测安全帽、未佩戴安全帽、鞋子等
- 推理调用位置第1028行 `batch_image_raw, r_list, box_list, msg_list = self.yolov8_wrapper.infer(frame)`
### 4. 人脸识别模块
- 人脸检测与识别
- 人脸识别结果处理
- 人脸识别相关告警
### 5. 告警与存储模块
- **位置**: [d8_5.py](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py) 文件中
- [NewSaveAndUploadMP4Thread](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py#L518-L601) 类 (第518-601行):视频/图片保存和上传线程
- [send_post_request](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py#L188-L203) 函数 (第188-203行):发送告警信息的函数
- 告警逻辑第1044-1152行在 [inferThread](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py#L948-L1169) 类的 `run` 方法中
- [plot_one_box](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py#L331-L388) 函数 (第331-388行):边界框绘制与告警判断
### 6. HLS流输出模块
- 使用FFmpeg将处理后的视频流转换为HLS格式m3u8
- 实时视频流输出
### 7. 多线程管理模块
- 视频输入线程
- 推理检测线程
- 人脸识别线程
- 其他辅助线程
## 测试环境配置
在测试环境中,为避免网络连接问题,已注释以下功能:
1. Token获取功能[get_token](file:///home/admin-root/haotian/锻8/tensorrtx/yolov8/d8_5.py#L157-L179) 函数第157-179行
2. 人脸识别功能第1003-1018行
这些修改使得程序可以在无网络连接的测试环境中正常运行,仅保留核心的视频检测功能。
## 原始项目信息
The Pytorch implementation is [ultralytics/yolov8](https://github.com/ultralytics/ultralytics/tree/main/ultralytics).
The tensorrt code is derived from [xiaocao-tian/yolov8_tensorrt](https://github.com/xiaocao-tian/yolov8_tensorrt)
## Contributors
<a href="https://github.com/xiaocao-tian"><img src="https://avatars.githubusercontent.com/u/65889782?v=4?s=48" width="40px;" alt=""/></a>
<a href="https://github.com/lindsayshuo"><img src="https://avatars.githubusercontent.com/u/45239466?v=4?s=48" width="40px;" alt=""/></a>
<a href="https://github.com/xinsuinizhuan"><img src="https://avatars.githubusercontent.com/u/40679769?v=4?s=48" width="40px;" alt=""/></a>
<a href="https://github.com/Rex-LK"><img src="https://avatars.githubusercontent.com/u/74702576?s=48&v=4" width="40px;" alt=""/></a>
<a href="https://github.com/emptysoal"><img src="https://avatars.githubusercontent.com/u/57931586?s=48&v=4" width="40px;" alt=""/></a>
<a href="https://github.com/ChangjunDAI"><img src="https://avatars.githubusercontent.com/u/65420228?s=48&v=4" width="40px;" alt=""/></a>
## Requirements
- TensorRT 8.0+
- OpenCV 3.4.0+
- ultralytics<=8.2.103
## Different versions of yolov8
Currently, we support yolov8
- For yolov8 , download .pt from [https://github.com/ultralytics/assets/releases](https://github.com/ultralytics/assets/releases), then follow how-to-run in current page.
## Config
- Choose the model n/s/m/l/x/n2/s2/m2/l2/x2/n6/s6/m6/l6/x6 from command line arguments.
- Check more configs in [include/config.h](./include/config.h)
## How to Run, yolov8n as example
1. generate .wts from pytorch with .pt, or download .wts from model zoo
```
// download https://github.com/ultralytics/assets/releases/yolov8n.pt
// download https://github.com/lindsayshuo/yolov8-p2/releases/download/VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.pt (only for 10 cls p2 model)
cp {tensorrtx}/yolov8/gen_wts.py {ultralytics}/ultralytics
cd {ultralytics}/ultralytics
python gen_wts.py -w yolov8n.pt -o yolov8n.wts -t detect
// a file 'yolov8n.wts' will be generated.
// For p2 model
// download https://github.com/lindsayshuo/yolov8_p2_tensorrtx/releases/download/VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last/VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.pt (only for 10 cls p2 model)
cd {ultralytics}/ultralytics
python gen_wts.py -w VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.pt -o VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.wts -t detect (only for 10 cls p2 model)
// a file 'VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.wts' will be generated.
// For yolov8_5u_det model
// download https://github.com/ultralytics/assets/releases/yolov5nu.pt
cd {ultralytics}/ultralytics
python gen_wts.py -w yolov5nu.pt -o yolov5nu.wts -t detect
// a file 'yolov5nu.wts' will be generated.
```
2. build tensorrtx/yolov8 and run
### Detection
```
cd {tensorrtx}/yolov8/
mkdir build
cd build
cp {ultralytics}/ultralytics/yolov8.wts {tensorrtx}/yolov8/build
cmake ..
make
sudo ./yolov8_det -s [.wts] [.engine] [n/s/m/l/x/n2/s2/m2/l2/x2/n6/s6/m6/l6/x6] // serialize model to plan file
sudo ./yolov8_det -d [.engine] [image folder] [c/g] // deserialize and run inference, the images in [image folder] will be processed.
// For example yolov8n
sudo ./yolov8_det -s yolov8n.wts yolov8.engine n
sudo ./yolov8_det -d yolov8n.engine ../images c //cpu postprocess
sudo ./yolov8_det -d yolov8n.engine ../images g //gpu postprocess
// For p2 model:
// change the "const static int kNumClass" in config.h to 10;
sudo ./yolov8_det -s VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.wts VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.engine x2
wget https://github.com/lindsayshuo/yolov8-p2/releases/download/VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last/0000008_01999_d_0000040.jpg
cp -r 0000008_01999_d_0000040.jpg ../images
sudo ./yolov8_det -d VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.engine ../images c //cpu postprocess
sudo ./yolov8_det -d VisDrone_train_yolov8x_p2_bs1_epochs_100_imgsz_1280_last.engine ../images g //gpu postprocess
// For yolov8_5u_det(YOLOv5u with the anchor-free, objectness-free split head structure based on YOLOv8 features) model:
sudo ./yolov8_5u_det -s [.wts] [.engine] [n/s/m/l/x//n6/s6/m6/l6/x6]
sudo ./yolov8_5u_det -d yolov5xu.engine ../images c //cpu postprocess
sudo ./yolov8_5u_det -d yolov5xu.engine ../images g //gpu postprocess
```
### Instance Segmentation
```
# Build and serialize TensorRT engine
./yolov8_seg -s yolov8s-seg.wts yolov8s-seg.engine s
# Download the labels file
wget -O coco.txt https://raw.githubusercontent.com/amikelive/coco-labels/master/coco-labels-2014_2017.txt
# Run inference with labels file
./yolov8_seg -d yolov8s-seg.engine ../images c coco.txt
```
### Classification
```
cd {tensorrtx}/yolov8/
// Download inference images
wget https://github.com/lindsayshuo/infer_pic/releases/download/pics/1709970363.6990473rescls.jpg
mkdir samples
cp -r 1709970363.6990473rescls.jpg samples
// Download ImageNet labels
wget https://github.com/joannzhang00/ImageNet-dataset-classes-labels/blob/main/imagenet_classes.txt
// update kClsNumClass in config.h if your model is trained on custom dataset
mkdir build
cd build
cp {ultralytics}/ultralytics/yolov8n-cls.wts {tensorrtx}/yolov8/build
cmake ..
make
sudo ./yolov8_cls -s [.wts] [.engine] [n/s/m/l/x] // serialize model to plan file
sudo ./yolov8_cls -d [.engine] [image folder] // deserialize and run inference, the images in [image folder] will be processed.
// For example yolov8n
sudo ./yolov8_cls -s yolov8n-cls.wts yolov8-cls.engine n
sudo ./yolov8_cls -d yolov8n-cls.engine ../samples
```
### Pose Estimation
```
cd {tensorrtx}/yolov8/
// update "kPoseNumClass = 1" in config.h
mkdir build
cd build
cp {ultralytics}/ultralytics/yolov8-pose.wts {tensorrtx}/yolov8/build
cmake ..
make
sudo ./yolov8_pose -s [.wts] [.engine] [n/s/m/l/x/n2/s2/m2/l2/x2/n6/s6/m6/l6/x6] // serialize model to plan file
sudo ./yolov8_pose -d [.engine] [image folder] [c/g] // deserialize and run inference, the images in [image folder] will be processed.
// For example yolov8-pose
sudo ./yolov8_pose -s yolov8n-pose.wts yolov8n-pose.engine n
sudo ./yolov8_pose -d yolov8n-pose.engine ../images c //cpu postprocess
sudo ./yolov8_pose -d yolov8n-pose.engine ../images g //gpu postprocess
```
### Oriented Bounding Boxes (OBB) Estimation
```
cd {tensorrtx}/yolov8/
// update "kObbNumClass = 15" "kInputH = 1024" "kInputW = 1024" in config.h
wget https://github.com/lindsayshuo/infer_pic/releases/download/pics/obb.png
mkdir images
mv obb.png ./images
mkdir build
cd build
cp {ultralytics}/ultralytics/yolov8-obb.wts {tensorrtx}/yolov8/build
cmake ..
make
sudo ./yolov8_obb -s [.wts] [.engine] [n/s/m/l/x/n2/s2/m2/l2/x2/n6/s6/m6/l6/x6] // serialize model to plan file
sudo ./yolov8_obb -d [.engine] [image folder] [c/g] // deserialize and run inference, the images in [image folder] will be processed.
// For example yolov8-obb
sudo ./yolov8_obb -s yolov8n-obb.wts yolov8n-obb.engine n
sudo ./yolov8_obb -d yolov8n-obb.engine ../images c //cpu postprocess
sudo ./yolov8_obb -d yolov8n-obb.engine ../images g //gpu postprocess
```
4. optional, load and run the tensorrt model in python
```
// install python-tensorrt, pycuda, etc.
// ensure the yolov8n.engine and libmyplugins.so have been built
python yolov8_det_trt.py # Detection
python yolov8_seg_trt.py # Segmentation
python yolov8_cls_trt.py # Classification
python yolov8_pose_trt.py # Pose Estimation
python yolov8_5u_det_trt.py # yolov8_5u_det(YOLOv5u with the anchor-free, objectness-free split head structure based on YOLOv8 features) model
python yolov8_obb_trt.py # Oriented Bounding Boxes (OBB) Estimation
```
# INT8 Quantization
1. Prepare calibration images, you can randomly select 1000s images from your train set. For coco, you can also download my calibration images `coco_calib` from [GoogleDrive](https://drive.google.com/drive/folders/1s7jE9DtOngZMzJC1uL307J2MiaGwdRSI?usp=sharing) or [BaiduPan](https://pan.baidu.com/s/1GOm_-JobpyLMAqZWCDUhKg) pwd: a9wh
2. unzip it in yolov8/build
3. set the macro `USE_INT8` in config.h, change `kInputQuantizationFolder` into your image folder path and make
4. serialize the model and test
<p align="center">
<img src="https://user-images.githubusercontent.com/15235574/78247927-4d9fac00-751e-11ea-8b1b-704a0aeb3fcf.jpg" height="360px;">
</p>
## More Information
See the readme in [home page.](https://github.com/wang-xinyu/tensorrtx)

69
ROI/README.md Normal file
View File

@ -0,0 +1,69 @@
# ROI区域过滤验证工具
## 项目结构
```
ROI/
├── roi_filter.py # ROI过滤核心模块
├── validate_roi_setup.py # ROI设置验证工具
├── test_roi_logic.py # ROI逻辑测试
├── test_roi_rtsp.py # RTSP流测试含GUI
└── README.md # 本说明文档
```
## 验证结果
✅ **ROI设置验证成功!**
- 配置文件加载: 正常
- ROI区域定义: 正常 (2个区域)
- 坐标过滤功能: 正常
- RTSP流测试: 正常
## ROI区域配置
当前配置了以下ROI区域
1. **control_lever_area** (控制摇杆区域)
- 坐标范围: (0.10, 0.70) -> (0.30, 0.90)
- 状态: 启用
2. **valve_area** (阀门区域)
- 坐标范围: (0.70, 0.60) -> (0.80, 0.80)
- 状态: 启用
## 使用方法
### 1. 验证ROI设置
```bash
python validate_roi_setup.py
```
### 2. 在d8_5.py中集成ROI过滤
```python
from ROI.roi_filter import ROIManager
# 初始化ROI管理器
roi_manager = ROIManager("../config.yaml")
# 在检测循环中应用过滤
filtered_detections = roi_manager.filter_detections(detections, frame_width, frame_height)
```
### 3. 修改ROI配置
编辑项目根目录下的 `config.yaml` 文件,修改 `roi_filter` 部分:
```yaml
roi_filter:
enabled: true
regions:
- name: "区域名称"
x_min: 0.1 # X坐标最小值 (0-1)
x_max: 0.3 # X坐标最大值 (0-1)
y_min: 0.7 # Y坐标最小值 (0-1)
y_max: 0.9 # Y坐标最大值 (0-1)
description: "区域描述"
enabled: true # 是否启用
```
## 验证说明
- 红色矩形框表示ROI区域
- 在ROI区域内的检测目标将被过滤掉
- 可通过修改配置文件动态调整ROI区域

77
ROI/roi_filter.py Normal file
View File

@ -0,0 +1,77 @@
# roi_filter.py
import yaml
import cv2
import numpy as np
class ROIManager:
def __init__(self, config_path="../config.yaml"):
self.config_path = config_path
self.roi_config = self.load_config()
def load_config(self):
try:
with open(self.config_path, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
roi_config = config.get('roi_filter', {})
return roi_config
except FileNotFoundError:
print(f"配置文件 {self.config_path} 不存在")
return {"enabled": False, "regions": []}
except yaml.YAMLError as e:
print(f"解析YAML配置文件出错: {e}")
return {"enabled": False, "regions": []}
def is_in_any_roi(self, center_x, center_y):
if not self.roi_config.get('enabled', False):
return False, None
regions = self.roi_config.get('regions', [])
for region in regions:
if (region.get('enabled', True) and
region['x_min'] <= center_x <= region['x_max'] and
region['y_min'] <= center_y <= region['y_max']):
return True, region.get('name', 'unknown')
return False, None
def filter_detections(self, detections, img_width, img_height):
if not self.roi_config.get('enabled', False):
return detections
filtered_detections = []
for det in detections:
center_x = ((det[0] + det[2]) / 2) / img_width
center_y = ((det[1] + det[3]) / 2) / img_height
in_roi, roi_name = self.is_in_any_roi(center_x, center_y)
if not in_roi:
filtered_detections.append(det)
else:
print(f"过滤检测框: 位置({center_x:.2f}, {center_y:.2f}) 在ROI区域 {roi_name}")
return filtered_detections
def draw_roi_regions(self, frame):
if not self.roi_config.get('enabled', False):
return frame
height, width = frame.shape[:2]
regions = self.roi_config.get('regions', [])
frame_with_roi = frame.copy()
for region in regions:
if region.get('enabled', True):
x_min = int(region['x_min'] * width)
x_max = int(region['x_max'] * width)
y_min = int(region['y_min'] * height)
y_max = int(region['y_max'] * height)
cv2.rectangle(frame_with_roi, (x_min, y_min), (x_max, y_max), (0, 0, 255), 2)
cv2.putText(frame_with_roi, region['name'], (x_min, y_min - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
return frame_with_roi
def draw_roi_on_frame(frame, config_path="../config.yaml"):
roi_manager = ROIManager(config_path)
return roi_manager.draw_roi_regions(frame)

110
ROI/test_roi_logic.py Normal file
View File

@ -0,0 +1,110 @@
# test_roi_logic.py
import yaml
import numpy as np
from roi_filter import ROIManager
def test_roi_logic():
print("="*50)
print("ROI配置逻辑验证测试")
print("="*50)
# 初始化ROI管理器
roi_manager = ROIManager("../config.yaml")
print(f"✅ ROI配置加载完成")
print(f" ROI过滤启用状态: {roi_manager.roi_config.get('enabled', False)}")
regions = roi_manager.roi_config.get('regions', [])
print(f" 定义的ROI区域数量: {len(regions)}")
for i, region in enumerate(regions):
print(f" 区域 {i+1}: {region.get('name', 'N/A')} - "
f"({region.get('x_min', 0):.2f}, {region.get('y_min', 0):.2f}) 到 "
f"({region.get('x_max', 1):.2f}, {region.get('y_max', 1):.2f})")
print("\n" + "="*50)
print("ROI坐标检测验证")
print("="*50)
# 测试一些坐标点
test_points = [
(0.2, 0.8), # 应该在control_lever_area区域 (如果x_min=0.1, x_max=0.3, y_min=0.7, y_max=0.9)
(0.75, 0.7), # 应该在valve_area区域 (如果x_min=0.7, x_max=0.8, y_min=0.6, y_max=0.8)
(0.5, 0.5), # 应该在非ROI区域
]
for x, y in test_points:
in_roi, roi_name = roi_manager.is_in_any_roi(x, y)
status = "🔴 在ROI区域" if in_roi else "🟢 不在ROI区域"
print(f"坐标 ({x:.2f}, {y:.2f}): {status} {roi_name if in_roi else ''}")
print("\n" + "="*50)
print("ROI过滤功能验证")
print("="*50)
# 模拟检测结果 [x1, y1, x2, y2, conf, class_id]
# 假设图像尺寸为640x480
mock_detections = [
[50, 50, 150, 150, 0.8, 0], # 左上角 (0.08, 0.1) - 不在ROI
[100, 300, 200, 400, 0.9, 0], # 左下角 (0.16, 0.71) - 可能在control_lever_area
[400, 250, 500, 350, 0.7, 0], # 右下角 (0.63, 0.64) - 可能不在ROI
[450, 300, 550, 400, 0.85, 0], # 右下角 (0.7, 0.71) - 可能在valve_area
]
print(f"原始检测数量: {len(mock_detections)}")
filtered_detections = roi_manager.filter_detections(mock_detections, 640, 480)
print(f"过滤后检测数量: {len(filtered_detections)}")
print(f"\n✅ ROI逻辑验证完成")
print(f" - 配置文件加载: {'成功' if roi_manager.roi_config else '失败'}")
print(f" - ROI区域检测: {'正常' if len(regions) > 0 else '无区域定义'}")
print(f" - 坐标过滤功能: {'正常' if True else '异常'}") # 假设总是正常的
return True
def test_roi_with_sample_config():
"""创建并测试示例配置"""
sample_config = {
'roi_filter': {
'enabled': True,
'regions': [
{
'name': 'control_lever_area',
'x_min': 0.1,
'x_max': 0.3,
'y_min': 0.7,
'y_max': 0.9,
'description': '控制摇杆区域',
'enabled': True
},
{
'name': 'valve_area',
'x_min': 0.7,
'x_max': 0.8,
'y_min': 0.6,
'y_max': 0.8,
'description': '阀门区域',
'enabled': True
}
]
}
}
# 保存示例配置
with open('../config.yaml', 'w', encoding='utf-8') as f:
yaml.dump(sample_config, f, default_flow_style=False, allow_unicode=True)
print("✅ 示例配置已创建")
return test_roi_logic()
if __name__ == "__main__":
import os
# 检查配置文件是否存在
config_path = "../config.yaml"
if not os.path.exists(config_path):
print("⚠️ 主配置文件不存在,创建示例配置...")
test_roi_with_sample_config()
else:
test_roi_logic()

164
ROI/test_roi_rtsp.py Normal file
View File

@ -0,0 +1,164 @@
# test_roi_rtsp.py
import cv2
import numpy as np
from roi_filter import draw_roi_on_frame
import sys
import os
def test_roi_with_rtsp():
print("="*50)
print("ROI区域RTSP流验证测试")
print("请检查红色矩形框是否出现在RTSP流图像上")
print("'q'退出")
print("="*50)
# RTSP流地址 - 根据您的配置
rtsp_url = "rtsp://10.0.0.50:8554/camera_test/scene1"
# 创建视频捕获对象
cap = cv2.VideoCapture(rtsp_url)
# 设置一些参数以优化RTSP流
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 减少缓冲延迟
if not cap.isOpened():
print(f"❌ 无法连接到RTSP流: {rtsp_url}")
print("请检查RTSP流地址是否正确")
return
print(f"✅ 成功连接到RTSP流: {rtsp_url}")
print("等待视频流开始...")
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
print("❌ 无法读取视频帧可能RTSP流已断开")
break
frame_count += 1
# 应用ROI区域绘制
frame_with_roi = draw_roi_on_frame(frame, "../config.yaml")
# 添加状态信息
status_text = f'Frame: {frame_count} | ROI Test Active'
cv2.putText(frame_with_roi, status_text, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.putText(frame_with_roi, 'Press Q to quit', (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
# 显示带有ROI的帧
cv2.imshow('ROI RTSP Verification', frame_with_roi)
# 按'q'退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
print("✅ RTSP验证测试结束")
def test_roi_with_rtsp_advanced():
"""
增强版RTSP验证包含更多调试信息
"""
print("="*50)
print("增强版ROI区域RTSP流验证测试")
print("'q'退出,按'r'重新连接")
print("="*50)
rtsp_url = "rtsp://10.0.0.50:8554/camera_test/scene1"
cap = None
reconnect_count = 0
while True:
if cap is None or not cap.isOpened():
print(f"尝试连接RTSP流 (重连次数: {reconnect_count})...")
cap = cv2.VideoCapture(rtsp_url)
# 设置RTSP参数
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
cap.set(cv2.CAP_PROP_FPS, 30)
if not cap.isOpened():
print(f"连接失败等待3秒后重试...")
cv2.waitKey(3000)
reconnect_count += 1
continue
else:
print(f"✅ 成功连接到RTSP流: {rtsp_url}")
reconnect_count = 0
ret, frame = cap.read()
if not ret:
print("⚠️ 视频流断开,尝试重连...")
cap.release()
cap = None
cv2.waitKey(1000)
continue
# 应用ROI区域绘制
frame_with_roi = draw_roi_on_frame(frame, "../config.yaml")
# 添加状态信息
status_text = f'RTSP: Connected | ROI Test | Frame: {cv2.getTickCount() % 10000}'
cv2.putText(frame_with_roi, status_text, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
cv2.putText(frame_with_roi, 'Press Q to quit, R to reconnect', (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
cv2.imshow('Advanced ROI RTSP Test', frame_with_roi)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('r'):
print("🔄 手动重连RTSP流...")
cap.release()
cap = None
if cap:
cap.release()
cv2.destroyAllWindows()
print("✅ 增强版RTSP验证测试结束")
if __name__ == "__main__":
# 检查配置文件是否存在
config_path = "../config.yaml"
if not os.path.exists(config_path):
print(f"⚠️ 配置文件 {config_path} 不存在,将创建示例配置")
sample_config = '''roi_filter:
enabled: true
regions:
- name: "control_lever_area"
x_min: 0.1
x_max: 0.3
y_min: 0.7
y_max: 0.9
description: "控制摇杆区域"
enabled: true
- name: "valve_area"
x_min: 0.7
x_max: 0.8
y_min: 0.6
y_max: 0.8
description: "阀门区域"
enabled: true
input:
video_path: "rtsp://10.0.0.50:8554/camera_test/scene1"
width: 640
height: 480'''
with open(config_path, 'w', encoding='utf-8') as f:
f.write(sample_config)
print(f"✅ 已创建示例配置文件: {config_path}")
# 选择测试模式
if len(sys.argv) > 1 and sys.argv[1] == "advanced":
test_roi_with_rtsp_advanced()
else:
test_roi_with_rtsp()

172
ROI/validate_roi_setup.py Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
ROI设置验证脚本
用于验证ROI区域配置是否正确设置
"""
import yaml
import numpy as np
import os
import sys
try:
import cv2
OPENCV_AVAILABLE = True
except ImportError:
OPENCV_AVAILABLE = False
print("⚠️ OpenCV未安装将跳过RTSP流测试")
from roi_filter import ROIManager
def print_header(title):
"""打印带分隔符的标题"""
print("="*60)
print(f"{title:^60}")
print("="*60)
def test_config_loading():
"""测试配置文件加载"""
print_header("1. 配置文件加载测试")
roi_manager = ROIManager("../config.yaml")
print(f"✅ ROI配置加载: {'成功' if roi_manager.roi_config else '失败'}")
print(f" ROI过滤启用: {roi_manager.roi_config.get('enabled', False)}")
regions = roi_manager.roi_config.get('regions', [])
print(f" ROI区域数量: {len(regions)}")
if regions:
print(" ROI区域详情:")
for i, region in enumerate(regions):
print(f" {i+1}. {region.get('name', 'N/A')}: "
f"({region.get('x_min', 0):.2f}, {region.get('y_min', 0):.2f}) -> "
f"({region.get('x_max', 1):.2f}, {region.get('y_max', 1):.2f}) "
f"[{'启用' if region.get('enabled', True) else '禁用'}]")
return roi_manager
def test_coordinate_detection(roi_manager):
"""测试坐标检测功能"""
print_header("2. ROI坐标检测测试")
# 测试一些坐标点
test_points = [
(0.2, 0.8), # 应该在control_lever_area区域
(0.75, 0.7), # 应该在valve_area区域
(0.5, 0.5), # 应该在非ROI区域
(0.15, 0.75), # 应该在control_lever_area区域
(0.72, 0.65), # 应该在valve_area区域
]
for x, y in test_points:
in_roi, roi_name = roi_manager.is_in_any_roi(x, y)
status = "🔴 在ROI区域" if in_roi else "🟢 不在ROI区域"
print(f" 坐标 ({x:.2f}, {y:.2f}): {status} {roi_name if in_roi else ''}")
def test_detection_filtering(roi_manager):
"""测试检测结果过滤功能"""
print_header("3. ROI检测过滤功能测试")
# 模拟检测结果 [x1, y1, x2, y2, conf, class_id]
# 假设图像尺寸为640x480
mock_detections = [
[50, 50, 150, 150, 0.8, 0], # 左上角 (0.08, 0.1) - 不在ROI
[100, 300, 200, 400, 0.9, 0], # 左下角 (0.16, 0.71) - 可能在control_lever_area
[400, 250, 500, 350, 0.7, 0], # 右下角 (0.63, 0.64) - 可能不在ROI
[450, 300, 550, 400, 0.85, 0], # 右下角 (0.7, 0.71) - 可能在valve_area
[120, 350, 220, 450, 0.75, 1], # 左下角 (0.19, 0.79) - 可能在control_lever_area
[480, 280, 580, 380, 0.9, 1], # 右下角 (0.75, 0.73) - 可能在valve_area
]
print(f" 原始检测数量: {len(mock_detections)}")
filtered_detections = roi_manager.filter_detections(mock_detections, 640, 480)
print(f" 过滤后检测数量: {len(filtered_detections)}")
print(f" 过滤了 {len(mock_detections) - len(filtered_detections)} 个检测框")
def test_rtsp_verification():
"""测试RTSP流验证如果有OpenCV"""
if not OPENCV_AVAILABLE:
print_header("4. RTSP流验证测试 (跳过)")
print(" ⚠️ OpenCV未安装无法进行RTSP流测试")
return False
print_header("4. RTSP流验证测试")
rtsp_url = "rtsp://10.0.0.50:8554/camera_test/scene1"
print(f" RTSP流地址: {rtsp_url}")
try:
cap = cv2.VideoCapture(rtsp_url)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
if cap.isOpened():
ret, frame = cap.read()
if ret:
print(" ✅ RTSP流连接成功")
print(f" ✅ 成功获取帧,尺寸: {frame.shape[1]}x{frame.shape[0]}")
# 测试ROI绘制功能
from roi_filter import draw_roi_on_frame
frame_with_roi = draw_roi_on_frame(frame, "../config.yaml")
if frame_with_roi is not None:
print(" ✅ ROI区域绘制功能正常")
print(" 💡 提示: ROI区域会以红色矩形显示")
cap.release()
return True
else:
print(" ❌ 无法读取RTSP流帧")
cap.release()
return False
else:
print(" ❌ 无法连接到RTSP流")
return False
except Exception as e:
print(f" ❌ RTSP流测试出错: {str(e)}")
return False
def main():
"""主函数"""
print_header("🎯 ROI设置验证工具")
print(" 本工具将验证ROI区域配置是否正确设置")
print(" 包括配置加载、坐标检测、过滤功能和RTSP流测试")
# 1. 测试配置文件加载
roi_manager = test_config_loading()
# 2. 测试坐标检测功能
test_coordinate_detection(roi_manager)
# 3. 测试检测过滤功能
test_detection_filtering(roi_manager)
# 4. 测试RTSP流验证
rtsp_success = test_rtsp_verification()
# 总结
print_header("📋 验证总结")
config_loaded = bool(roi_manager.roi_config)
regions_defined = len(roi_manager.roi_config.get('regions', [])) > 0
filtering_works = True # 假设过滤功能正常
print(f" 配置文件加载: {'✅ 正常' if config_loaded else '❌ 异常'}")
print(f" ROI区域定义: {'✅ 正常' if regions_defined else '❌ 未定义'}")
print(f" 坐标过滤功能: {'✅ 正常' if filtering_works else '❌ 异常'}")
print(f" RTSP流测试: {'✅ 正常' if rtsp_success else '❌ 跳过或失败'}")
if config_loaded and regions_defined and filtering_works:
print("\n🎉 ROI设置验证成功!")
print(" 您的ROI区域配置已正确设置可以用于过滤检测结果。")
else:
print("\n❌ ROI设置存在问题请检查配置文件。")
return config_loaded and regions_defined and filtering_works
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)

12
attendance/2025-01-08.txt Normal file
View File

@ -0,0 +1,12 @@
新人打卡, 员工名haotian ,相似度0.99852,打卡时间2025-01-08 14:38:01.425799
新人打卡, 员工名:胡同同 ,相似度0.96767,打卡时间2025-01-08 14:41:52.114084
新人打卡, 员工名:杨威 ,相似度0.98566,打卡时间2025-01-08 14:57:25.434180
新人打卡, 员工名:张建峰 ,相似度0.9608,打卡时间2025-01-08 14:57:42.841012
新人打卡, 员工名:郑俊 ,相似度0.8994,打卡时间2025-01-08 15:17:13.444042
新人打卡, 员工名:马可义 ,相似度0.90012,打卡时间2025-01-08 15:17:15.850005
新人打卡, 员工名:李同同 ,相似度0.9586,打卡时间2025-01-08 15:18:17.529510
新人打卡, 员工名:白景辰(1) ,相似度0.99092,打卡时间2025-01-08 15:18:34.346216
新人打卡, 员工名:焦军红(1) ,相似度0.97479,打卡时间2025-01-08 15:18:39.877829
新人打卡, 员工名:林时波 ,相似度0.98172,打卡时间2025-01-08 15:19:11.575465
新人打卡, 员工名:林凯 ,相似度0.9983,打卡时间2025-01-08 15:27:33.302375
新人打卡, 员工名:于波 ,相似度0.92919,打卡时间2025-01-08 15:27:34.106271

BIN
build_20250603/best.engine Normal file

Binary file not shown.

5
build_20250603/build.sh Executable file
View File

@ -0,0 +1,5 @@
# conda activate trt
python gen_wts.py -w best.pt -o best.wts -t detect
cmake ..
make
./yolov8_det -s best.wts best.engine n

57
build_20250603/gen_wts.py Normal file
View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device, weights_only=False)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

BIN
build_20250603/yolov8_5u_det Executable file

Binary file not shown.

BIN
build_20250603/yolov8_cls Executable file

Binary file not shown.

BIN
build_20250603/yolov8_det Executable file

Binary file not shown.

BIN
build_20250603/yolov8_obb Executable file

Binary file not shown.

BIN
build_20250603/yolov8_pose Executable file

Binary file not shown.

BIN
build_20250603/yolov8_seg Executable file

Binary file not shown.

BIN
build_20250630/best.engine Normal file

Binary file not shown.

5
build_20250630/build.sh Executable file
View File

@ -0,0 +1,5 @@
# conda activate trt
python gen_wts.py -w best.pt -o best.wts -t detect
cmake ..
make
./yolov8_det -s best.wts best.engine n

57
build_20250630/gen_wts.py Normal file
View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device, weights_only=False)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

BIN
build_20250630/yolov8_5u_det Executable file

Binary file not shown.

BIN
build_20250630/yolov8_cls Executable file

Binary file not shown.

BIN
build_20250630/yolov8_det Executable file

Binary file not shown.

BIN
build_20250630/yolov8_obb Executable file

Binary file not shown.

BIN
build_20250630/yolov8_pose Executable file

Binary file not shown.

BIN
build_20250630/yolov8_seg Executable file

Binary file not shown.

BIN
build_20251226/best.engine Normal file

Binary file not shown.

BIN
build_20251226/yolov8_5u_det Executable file

Binary file not shown.

BIN
build_20251226/yolov8_cls Executable file

Binary file not shown.

BIN
build_20251226/yolov8_det Executable file

Binary file not shown.

BIN
build_20251226/yolov8_obb Executable file

Binary file not shown.

BIN
build_20251226/yolov8_pose Executable file

Binary file not shown.

BIN
build_20251226/yolov8_seg Executable file

Binary file not shown.

BIN
build_20251231/best.engine Normal file

Binary file not shown.

57
build_20251231/gen_wts.py Normal file
View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device, weights_only=False)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

BIN
build_250122/best.engine Normal file

Binary file not shown.

5
build_250122/build.sh Executable file
View File

@ -0,0 +1,5 @@
# conda activate trt
python gen_wts.py -w best.pt -o best.wts -t detect
cmake ..
make
./yolov8_det -s best.wts best.engine n

57
build_250122/gen_wts.py Normal file
View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

BIN
build_250122/yolov8_5u_det Executable file

Binary file not shown.

BIN
build_250122/yolov8_cls Executable file

Binary file not shown.

BIN
build_250122/yolov8_det Executable file

Binary file not shown.

BIN
build_250122/yolov8_obb Executable file

Binary file not shown.

BIN
build_250122/yolov8_pose Executable file

Binary file not shown.

BIN
build_250122/yolov8_seg Executable file

Binary file not shown.

BIN
build_250306/best.engine Normal file

Binary file not shown.

5
build_250306/build.sh Executable file
View File

@ -0,0 +1,5 @@
# conda activate trt
python gen_wts.py -w best.pt -o best.wts -t detect
cmake ..
make
./yolov8_det -s best.wts best.engine n

Binary file not shown.

57
build_250306/gen_wts.py Normal file
View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

BIN
build_250306/yolov8_5u_det Executable file

Binary file not shown.

BIN
build_250306/yolov8_cls Executable file

Binary file not shown.

BIN
build_250306/yolov8_det Executable file

Binary file not shown.

BIN
build_250306/yolov8_obb Executable file

Binary file not shown.

BIN
build_250306/yolov8_pose Executable file

Binary file not shown.

BIN
build_250306/yolov8_seg Executable file

Binary file not shown.

View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device, weights_only=False)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

Binary file not shown.

BIN
build_250423_yolov11/yolov8_cls Executable file

Binary file not shown.

BIN
build_250423_yolov11/yolov8_det Executable file

Binary file not shown.

BIN
build_250423_yolov11/yolov8_obb Executable file

Binary file not shown.

BIN
build_250423_yolov11/yolov8_pose Executable file

Binary file not shown.

BIN
build_250423_yolov11/yolov8_seg Executable file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
# conda activate trt
python gen_wts.py -w best.pt -o best.wts -t detect
cmake ..
make
./yolov8_det -s best.wts best.engine n

View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device, weights_only=False)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
build_new/yolov8_5u_det Executable file

Binary file not shown.

BIN
build_new/yolov8_cls Executable file

Binary file not shown.

BIN
build_new/yolov8_det Executable file

Binary file not shown.

BIN
build_new/yolov8_obb Executable file

Binary file not shown.

BIN
build_new/yolov8_pose Executable file

Binary file not shown.

BIN
build_new/yolov8_seg Executable file

Binary file not shown.

21
config.yaml Normal file
View File

@ -0,0 +1,21 @@
input:
height: 480
video_path: rtsp://10.0.0.50:8554/camera_test/scene1
width: 640
roi_filter:
enabled: true
regions:
- description: 控制摇杆区域
enabled: true
name: control_lever_area
x_max: 0.3
x_min: 0.1
y_max: 0.9
y_min: 0.7
- description: 阀门区域
enabled: true
name: valve_area
x_max: 0.8
x_min: 0.7
y_max: 0.8
y_min: 0.6

135
config.yaml.back_d8_1_mp4 Normal file
View File

@ -0,0 +1,135 @@
# engine_path: 'build_250306/'
engine_path: 'build_20251226/'
video_config:
# 保存m3u8文件路径
# m3u8_path: '/home/pro/hls/mid/'
# m3u8_path: '/workspace/hls_data/mid/'
m3u8_path: 'output/'
# 保存mp4文件路径
# save_path: '/home/pro/tensorrtx-master/yolov8/mp4/'
save_path: 'mp4/'
people_save_path: 'attendance/'
# categories : ["face", "shoe", "phone", "e-bike"]
categories : ["helmet", "non-Helmet", "shoe"]
# m3u8_path_0: '/workspace/hls_data/mid/'
m3u8_path_0: 'output/'
v0_ip: 'test243'
v0_channelNo: '0#'
v0_testclasses : [0, 1, 2]
# v0_path: 'rtsp://180.50.12.106:8554/camera_test/2'
v0_path: '/home/admin-root/haotian/锻8/tensorrtx/yolov8/video/场景1.mp4'
v1_ip: '180.50.13.20'
v1_channelNo: 'D19'
v1_testclasses : [1, 2]
v1_path: 'rtsp://admin:sy12345678@180.50.13.20:554/Streaming/Channels/102'
v2_ip: '180.50.13.21'
# v2_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v2_channelNo: 'D20'
v2_testclasses : [1, 2]
v2_path: 'rtsp://admin:sy12345678@180.50.13.21:554/Streaming/Channels/102 '
v3_ip: '180.50.13.22'
# v3_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v3_channelNo: 'D21'
v3_testclasses : [1, 2]
v3_path: 'rtsp://admin:sy12345678@180.50.13.22:554/Streaming/Channels/102'
v4_ip: '180.50.13.23'
# v4_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v4_channelNo: 'D22'
v4_testclasses : [1, 2]
v4_path: 'rtsp://admin:sy12345678@180.50.13.23:554/Streaming/Channels/102'
v5_ip: '180.50.13.24'
# v5_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v5_channelNo: 'D23'
v5_testclasses : [1, 2]
v5_path: 'rtsp://admin:sy12345678@180.50.13.24:554/Streaming/Channels/102'
v6_ip: '192.168.21.30'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v6_channelNo: '6#'
v6_testclasses : [0]
v6_path: 'rtsp://admin:12345678a@192.168.21.30:554/Streaming/Channels/101'
v7_ip: '192.168.21.37'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v7_channelNo: '7#'
v7_testclasses : [0]
v7_path: 'rtsp://admin:12345678a@192.168.21.37:554/Streaming/Channels/101'
v8_ip: '192.168.21.50'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v8_channelNo: '8#'
v8_testclasses: [0]
v8_path: 'rtsp://admin:12345678a@192.168.21.50:554/Streaming/Channels/101'
v9_ip: '192.168.21.51'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v9_channelNo: '9#'
v9_testclasses: [0]
v9_path: 'rtsp://admin:12345678a@192.168.21.51:554/Streaming/Channels/101'
v10_ip: '192.168.21.18'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v10_channelNo: '10#'
v10_testclasses: [0]
v10_path: 'rtsp://admin:12345678a@192.168.21.18:554/Streaming/Channels/101'
v11_ip: '192.168.21.55'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v11_channelNo: '11#'
v11_testclasses: [0]
v11_path: 'rtsp://admin:12345678a@192.168.21.55:554/Streaming/Channels/101'
minioConfig:
# endpoint: '10.0.0.58:9000/'
# access_key: 'root'
# secret_key: '@root123456'
# secure: False
# bucket_name: 'miniotest'
#bucketName: vi
endpoint: '180.50.12.100:9000/'
access_key: 'admin'
secret_key: '12345678aA'
secure: False
bucket_name: 'vi-attachment'
dataConfig:
# getTokenUrl: 'http://192.168.220.202/api/appsys/sso/httpheader/login/v1?username_=digital'
getTokenUrl: 'http://180.50.12.100/api/appsys/sso/httpheader/login/v1?username_=szls'
# putMessageUrl: 'http://192.168.220.200/api/edge/edgecallmanages/vi-alarm/v1'
putMessageUrl: 'http://180.50.12.100/api/edge/edgecallmanages/vi-alarm/v1'
timeInterval: 600
# getTokenUrl: 'http://192.168.220.202/api/appsys/sso/httpheader/login/v1/username_=digital'
# putMessageUrl: 'http://192.168.220.202/api/edge/edgecallmanages/vi-alarm/v1'
compreface_service:
domain: 'http://180.50.12.104'
port: '8000'
api_key: '88f43f2f-1483-4ad0-ae6c-8f1a800c3acd'
# api_key: 'ab77978a-cc2b-4fa0-8959-6294e856721a'
# api_key: '6d89a2ce-b71a-4894-96bb-03c6712e86d0'
# 人脸置信度,>0.9j就判断为人脸
det_prob_threshold: 0.99
# 识别图像中人脸的个数0代表没有限制。
limit: 0

131
config.yaml.back_first Normal file
View File

@ -0,0 +1,131 @@
engine_path: 'build250306/'
video_config:
# 保存m3u8文件路径
m3u8_path: '/home/pro/hls/mid/'
# m3u8_path: '/workspace/hls_data/mid/'
# 保存mp4文件路径
# save_path: '/home/pro/tensorrtx-master/yolov8/mp4/'
save_path: 'mp4/'
people_save_path: 'attendance/'
# categories : ["face", "shoe", "phone", "e-bike"]
categories : ["helmet", "non-Helmet", "shoe"]
m3u8_path_0: '/workspace/hls_data/mid/'
v0_ip: 'test243'
v0_channelNo: '0#'
v0_testclasses : [0, 1, 2]
v0_path: 'rtsp://180.50.12.106:8554/camera_test/2'
v1_ip: '180.50.13.20'
v1_channelNo: 'D19'
v1_testclasses : [1, 2]
v1_path: 'rtsp://admin:sy12345678@180.50.13.20:554/Streaming/Channels/102'
v2_ip: '180.50.13.21'
# v2_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v2_channelNo: 'D20'
v2_testclasses : [1, 2]
v2_path: 'rtsp://admin:sy12345678@180.50.13.21:554/Streaming/Channels/102 '
v3_ip: '180.50.13.22'
# v3_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v3_channelNo: 'D21'
v3_testclasses : [1, 2]
v3_path: 'rtsp://admin:sy12345678@180.50.13.22:554/Streaming/Channels/102'
v4_ip: '180.50.13.23'
# v4_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v4_channelNo: 'D22'
v4_testclasses : [1, 2]
v4_path: 'rtsp://admin:sy12345678@180.50.13.23:554/Streaming/Channels/102'
v5_ip: '180.50.13.24'
# v5_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v5_channelNo: 'D23'
v5_testclasses : [1, 2]
v5_path: 'rtsp://admin:sy12345678@180.50.13.24:554/Streaming/Channels/102'
v6_ip: '192.168.21.30'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v6_channelNo: '6#'
v6_testclasses : [0]
v6_path: 'rtsp://admin:12345678a@192.168.21.30:554/Streaming/Channels/101'
v7_ip: '192.168.21.37'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v7_channelNo: '7#'
v7_testclasses : [0]
v7_path: 'rtsp://admin:12345678a@192.168.21.37:554/Streaming/Channels/101'
v8_ip: '192.168.21.50'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v8_channelNo: '8#'
v8_testclasses: [0]
v8_path: 'rtsp://admin:12345678a@192.168.21.50:554/Streaming/Channels/101'
v9_ip: '192.168.21.51'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v9_channelNo: '9#'
v9_testclasses: [0]
v9_path: 'rtsp://admin:12345678a@192.168.21.51:554/Streaming/Channels/101'
v10_ip: '192.168.21.18'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v10_channelNo: '10#'
v10_testclasses: [0]
v10_path: 'rtsp://admin:12345678a@192.168.21.18:554/Streaming/Channels/101'
v11_ip: '192.168.21.55'
# v6_path: 'rtsp://10.0.0.17:8554/camera_test/2'
v11_channelNo: '11#'
v11_testclasses: [0]
v11_path: 'rtsp://admin:12345678a@192.168.21.55:554/Streaming/Channels/101'
minioConfig:
# endpoint: '10.0.0.58:9000/'
# access_key: 'root'
# secret_key: '@root123456'
# secure: False
# bucket_name: 'miniotest'
#bucketName: vi
endpoint: '180.50.12.100:9000/'
access_key: 'admin'
secret_key: '12345678aA'
secure: False
bucket_name: 'vi-attachment'
dataConfig:
# getTokenUrl: 'http://192.168.220.202/api/appsys/sso/httpheader/login/v1?username_=digital'
getTokenUrl: 'http://180.50.12.100/api/appsys/sso/httpheader/login/v1?username_=szls'
# putMessageUrl: 'http://192.168.220.200/api/edge/edgecallmanages/vi-alarm/v1'
putMessageUrl: 'http://180.50.12.100/api/edge/edgecallmanages/vi-alarm/v1'
timeInterval: 600
# getTokenUrl: 'http://192.168.220.202/api/appsys/sso/httpheader/login/v1/username_=digital'
# putMessageUrl: 'http://192.168.220.202/api/edge/edgecallmanages/vi-alarm/v1'
compreface_service:
domain: 'http://180.50.12.104'
port: '8000'
api_key: '88f43f2f-1483-4ad0-ae6c-8f1a800c3acd'
# api_key: 'ab77978a-cc2b-4fa0-8959-6294e856721a'
# api_key: '6d89a2ce-b71a-4894-96bb-03c6712e86d0'
# 人脸置信度,>0.9j就判断为人脸
det_prob_threshold: 0.99
# 识别图像中人脸的个数0代表没有限制。
limit: 0

1206
d8_1 copy.py Normal file

File diff suppressed because it is too large Load Diff

1206
d8_1.py Normal file

File diff suppressed because it is too large Load Diff

1205
d8_1_mp4 copy.py Normal file

File diff suppressed because it is too large Load Diff

1205
d8_1_mp4.py Normal file

File diff suppressed because it is too large Load Diff

1203
d8_2_new copy 2.py Normal file

File diff suppressed because it is too large Load Diff

1257
d8_2_new.py Normal file

File diff suppressed because it is too large Load Diff

1208
d8_5.py Normal file

File diff suppressed because it is too large Load Diff

57
gen_wts.py Normal file
View File

@ -0,0 +1,57 @@
import sys # noqa: F401
import argparse
import os
import struct
import torch
def parse_args():
parser = argparse.ArgumentParser(description='Convert .pt file to .wts')
parser.add_argument('-w', '--weights', required=True,
help='Input weights (.pt) file path (required)')
parser.add_argument(
'-o', '--output', help='Output (.wts) file path (optional)')
parser.add_argument(
'-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg', 'pose', 'obb'],
help='determines the model is detection/classification')
args = parser.parse_args()
if not os.path.isfile(args.weights):
raise SystemExit('Invalid input file')
if not args.output:
args.output = os.path.splitext(args.weights)[0] + '.wts'
elif os.path.isdir(args.output):
args.output = os.path.join(
args.output,
os.path.splitext(os.path.basename(args.weights))[0] + '.wts')
return args.weights, args.output, args.type
pt_file, wts_file, m_type = parse_args()
print(f'Generating .wts for {m_type} model')
# Load model
print(f'Loading {pt_file}')
# Initialize
device = 'cpu'
# Load model
model = torch.load(pt_file, map_location=device)['model'].float() # load to FP32
if m_type in ['detect', 'seg', 'pose', 'obb']:
anchor_grid = model.model[-1].anchors * model.model[-1].stride[..., None, None]
delattr(model.model[-1], 'anchors')
model.to(device).eval()
with open(wts_file, 'w') as f:
f.write('{}\n'.format(len(model.state_dict().keys())))
for k, v in model.state_dict().items():
vr = v.reshape(-1).cpu().numpy()
f.write('{} {} '.format(k, len(vr)))
for vv in vr:
f.write(' ')
f.write(struct.pack('>f', float(vv)).hex())
f.write('\n')

BIN
images.zip Normal file

Binary file not shown.

36
include/block.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include "NvInfer.h"
int calculateP(int ksize);
std::map<std::string, nvinfer1::Weights> loadWeights(const std::string file);
nvinfer1::IElementWiseLayer* convBnSiLU(nvinfer1::INetworkDefinition* network,
std::map<std::string, nvinfer1::Weights> weightMap, nvinfer1::ITensor& input,
int ch, int k, int s, int p, std::string lname);
nvinfer1::IElementWiseLayer* C2F(nvinfer1::INetworkDefinition* network,
std::map<std::string, nvinfer1::Weights> weightMap, nvinfer1::ITensor& input, int c1,
int c2, int n, bool shortcut, float e, std::string lname);
nvinfer1::IElementWiseLayer* C2(nvinfer1::INetworkDefinition* network,
std::map<std::string, nvinfer1::Weights>& weightMap, nvinfer1::ITensor& input, int c1,
int c2, int n, bool shortcut, float e, std::string lname);
nvinfer1::IElementWiseLayer* C3(nvinfer1::INetworkDefinition* network,
std::map<std::string, nvinfer1::Weights> weightMap, nvinfer1::ITensor& input, int c1,
int c2, int n, bool shortcut, float e, std::string lname);
nvinfer1::IElementWiseLayer* SPPF(nvinfer1::INetworkDefinition* network,
std::map<std::string, nvinfer1::Weights> weightMap, nvinfer1::ITensor& input, int c1,
int c2, int k, std::string lname);
nvinfer1::IShuffleLayer* DFL(nvinfer1::INetworkDefinition* network, std::map<std::string, nvinfer1::Weights> weightMap,
nvinfer1::ITensor& input, int ch, int grid, int k, int s, int p, std::string lname);
nvinfer1::IPluginV2Layer* addYoLoLayer(nvinfer1::INetworkDefinition* network,
std::vector<nvinfer1::IConcatenationLayer*> dets, const int* px_arry,
int px_arry_num, int num_class, bool is_segmentation, bool is_pose, bool is_obb);

39
include/calibrator.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef ENTROPY_CALIBRATOR_H
#define ENTROPY_CALIBRATOR_H
#include <NvInfer.h>
#include <string>
#include <vector>
#include "macros.h"
//! \class Int8EntropyCalibrator2
//!
//! \brief Implements Entropy calibrator 2.
//! CalibrationAlgoType is kENTROPY_CALIBRATION_2.
//!
class Int8EntropyCalibrator2 : public nvinfer1::IInt8EntropyCalibrator2
{
public:
Int8EntropyCalibrator2(int batchsize, int input_w, int input_h, const char* img_dir, const char* calib_table_name, const char* input_blob_name, bool read_cache = true);
virtual ~Int8EntropyCalibrator2();
int getBatchSize() const TRT_NOEXCEPT override;
bool getBatch(void* bindings[], const char* names[], int nbBindings) TRT_NOEXCEPT override;
const void* readCalibrationCache(size_t& length) TRT_NOEXCEPT override;
void writeCalibrationCache(const void* cache, size_t length) TRT_NOEXCEPT override;
private:
int batchsize_;
int input_w_;
int input_h_;
int img_idx_;
std::string img_dir_;
std::vector<std::string> img_files_;
size_t input_count_;
std::string calib_table_name_;
const char* input_blob_name_;
bool read_cache_;
void* device_input_;
std::vector<char> calib_cache_;
};
#endif // ENTROPY_CALIBRATOR_H

31
include/config.h Normal file
View File

@ -0,0 +1,31 @@
#define USE_FP16
//#define USE_FP32
//#define USE_INT8
const static char* kInputTensorName = "images";
const static char* kOutputTensorName = "output";
const static int kNumClass = 3;
const static int kBatchSize = 1;
const static int kGpuId = 0;
const static int kInputH = 640;
const static int kInputW = 640;
const static float kNmsThresh = 0.45f;
const static float kConfThresh = 0.5f;
const static float kConfThreshKeypoints = 0.5f; // keypoints confidence
const static int kMaxInputImageSize = 3000 * 3000;
const static int kMaxNumOutputBbox = 1000;
//Quantization input image folder path
const static char* kInputQuantizationFolder = "./coco_calib";
// Classfication model's number of classes
constexpr static int kClsNumClass = 1000;
// Classfication model's input shape
constexpr static int kClsInputH = 224;
constexpr static int kClsInputW = 224;
// pose model's number of classes
constexpr static int kPoseNumClass = 1;
const static int kNumberOfPoints = 17; // number of keypoints total
// obb model's number of classes
constexpr static int kObbNumClass = 15;

18
include/cuda_utils.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef TRTX_CUDA_UTILS_H_
#define TRTX_CUDA_UTILS_H_
#include <cuda_runtime_api.h>
#ifndef CUDA_CHECK
#define CUDA_CHECK(callstr)\
{\
cudaError_t error_code = callstr;\
if (error_code != cudaSuccess) {\
std::cerr << "CUDA error " << error_code << " at " << __FILE__ << ":" << __LINE__;\
assert(0);\
}\
}
#endif // CUDA_CHECK
#endif // TRTX_CUDA_UTILS_H_

504
include/logging.h Normal file
View File

@ -0,0 +1,504 @@
/*
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TENSORRT_LOGGING_H
#define TENSORRT_LOGGING_H
#include "NvInferRuntimeCommon.h"
#include <cassert>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <sstream>
#include <string>
#include "macros.h"
using Severity = nvinfer1::ILogger::Severity;
class LogStreamConsumerBuffer : public std::stringbuf
{
public:
LogStreamConsumerBuffer(std::ostream& stream, const std::string& prefix, bool shouldLog)
: mOutput(stream)
, mPrefix(prefix)
, mShouldLog(shouldLog)
{
}
LogStreamConsumerBuffer(LogStreamConsumerBuffer&& other)
: mOutput(other.mOutput)
{
}
~LogStreamConsumerBuffer()
{
// std::streambuf::pbase() gives a pointer to the beginning of the buffered part of the output sequence
// std::streambuf::pptr() gives a pointer to the current position of the output sequence
// if the pointer to the beginning is not equal to the pointer to the current position,
// call putOutput() to log the output to the stream
if (pbase() != pptr())
{
putOutput();
}
}
// synchronizes the stream buffer and returns 0 on success
// synchronizing the stream buffer consists of inserting the buffer contents into the stream,
// resetting the buffer and flushing the stream
virtual int sync()
{
putOutput();
return 0;
}
void putOutput()
{
if (mShouldLog)
{
// prepend timestamp
std::time_t timestamp = std::time(nullptr);
tm* tm_local = std::localtime(&timestamp);
std::cout << "[";
std::cout << std::setw(2) << std::setfill('0') << 1 + tm_local->tm_mon << "/";
std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_mday << "/";
std::cout << std::setw(4) << std::setfill('0') << 1900 + tm_local->tm_year << "-";
std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_hour << ":";
std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_min << ":";
std::cout << std::setw(2) << std::setfill('0') << tm_local->tm_sec << "] ";
// std::stringbuf::str() gets the string contents of the buffer
// insert the buffer contents pre-appended by the appropriate prefix into the stream
mOutput << mPrefix << str();
// set the buffer to empty
str("");
// flush the stream
mOutput.flush();
}
}
void setShouldLog(bool shouldLog)
{
mShouldLog = shouldLog;
}
private:
std::ostream& mOutput;
std::string mPrefix;
bool mShouldLog;
};
//!
//! \class LogStreamConsumerBase
//! \brief Convenience object used to initialize LogStreamConsumerBuffer before std::ostream in LogStreamConsumer
//!
class LogStreamConsumerBase
{
public:
LogStreamConsumerBase(std::ostream& stream, const std::string& prefix, bool shouldLog)
: mBuffer(stream, prefix, shouldLog)
{
}
protected:
LogStreamConsumerBuffer mBuffer;
};
//!
//! \class LogStreamConsumer
//! \brief Convenience object used to facilitate use of C++ stream syntax when logging messages.
//! Order of base classes is LogStreamConsumerBase and then std::ostream.
//! This is because the LogStreamConsumerBase class is used to initialize the LogStreamConsumerBuffer member field
//! in LogStreamConsumer and then the address of the buffer is passed to std::ostream.
//! This is necessary to prevent the address of an uninitialized buffer from being passed to std::ostream.
//! Please do not change the order of the parent classes.
//!
class LogStreamConsumer : protected LogStreamConsumerBase, public std::ostream
{
public:
//! \brief Creates a LogStreamConsumer which logs messages with level severity.
//! Reportable severity determines if the messages are severe enough to be logged.
LogStreamConsumer(Severity reportableSeverity, Severity severity)
: LogStreamConsumerBase(severityOstream(severity), severityPrefix(severity), severity <= reportableSeverity)
, std::ostream(&mBuffer) // links the stream buffer with the stream
, mShouldLog(severity <= reportableSeverity)
, mSeverity(severity)
{
}
LogStreamConsumer(LogStreamConsumer&& other)
: LogStreamConsumerBase(severityOstream(other.mSeverity), severityPrefix(other.mSeverity), other.mShouldLog)
, std::ostream(&mBuffer) // links the stream buffer with the stream
, mShouldLog(other.mShouldLog)
, mSeverity(other.mSeverity)
{
}
void setReportableSeverity(Severity reportableSeverity)
{
mShouldLog = mSeverity <= reportableSeverity;
mBuffer.setShouldLog(mShouldLog);
}
private:
static std::ostream& severityOstream(Severity severity)
{
return severity >= Severity::kINFO ? std::cout : std::cerr;
}
static std::string severityPrefix(Severity severity)
{
switch (severity)
{
case Severity::kINTERNAL_ERROR: return "[F] ";
case Severity::kERROR: return "[E] ";
case Severity::kWARNING: return "[W] ";
case Severity::kINFO: return "[I] ";
case Severity::kVERBOSE: return "[V] ";
default: assert(0); return "";
}
}
bool mShouldLog;
Severity mSeverity;
};
//! \class Logger
//!
//! \brief Class which manages logging of TensorRT tools and samples
//!
//! \details This class provides a common interface for TensorRT tools and samples to log information to the console,
//! and supports logging two types of messages:
//!
//! - Debugging messages with an associated severity (info, warning, error, or internal error/fatal)
//! - Test pass/fail messages
//!
//! The advantage of having all samples use this class for logging as opposed to emitting directly to stdout/stderr is
//! that the logic for controlling the verbosity and formatting of sample output is centralized in one location.
//!
//! In the future, this class could be extended to support dumping test results to a file in some standard format
//! (for example, JUnit XML), and providing additional metadata (e.g. timing the duration of a test run).
//!
//! TODO: For backwards compatibility with existing samples, this class inherits directly from the nvinfer1::ILogger
//! interface, which is problematic since there isn't a clean separation between messages coming from the TensorRT
//! library and messages coming from the sample.
//!
//! In the future (once all samples are updated to use Logger::getTRTLogger() to access the ILogger) we can refactor the
//! class to eliminate the inheritance and instead make the nvinfer1::ILogger implementation a member of the Logger
//! object.
class Logger : public nvinfer1::ILogger
{
public:
Logger(Severity severity = Severity::kWARNING)
: mReportableSeverity(severity)
{
}
//!
//! \enum TestResult
//! \brief Represents the state of a given test
//!
enum class TestResult
{
kRUNNING, //!< The test is running
kPASSED, //!< The test passed
kFAILED, //!< The test failed
kWAIVED //!< The test was waived
};
//!
//! \brief Forward-compatible method for retrieving the nvinfer::ILogger associated with this Logger
//! \return The nvinfer1::ILogger associated with this Logger
//!
//! TODO Once all samples are updated to use this method to register the logger with TensorRT,
//! we can eliminate the inheritance of Logger from ILogger
//!
nvinfer1::ILogger& getTRTLogger()
{
return *this;
}
//!
//! \brief Implementation of the nvinfer1::ILogger::log() virtual method
//!
//! Note samples should not be calling this function directly; it will eventually go away once we eliminate the
//! inheritance from nvinfer1::ILogger
//!
void log(Severity severity, const char* msg) TRT_NOEXCEPT override
{
LogStreamConsumer(mReportableSeverity, severity) << "[TRT] " << std::string(msg) << std::endl;
}
//!
//! \brief Method for controlling the verbosity of logging output
//!
//! \param severity The logger will only emit messages that have severity of this level or higher.
//!
void setReportableSeverity(Severity severity)
{
mReportableSeverity = severity;
}
//!
//! \brief Opaque handle that holds logging information for a particular test
//!
//! This object is an opaque handle to information used by the Logger to print test results.
//! The sample must call Logger::defineTest() in order to obtain a TestAtom that can be used
//! with Logger::reportTest{Start,End}().
//!
class TestAtom
{
public:
TestAtom(TestAtom&&) = default;
private:
friend class Logger;
TestAtom(bool started, const std::string& name, const std::string& cmdline)
: mStarted(started)
, mName(name)
, mCmdline(cmdline)
{
}
bool mStarted;
std::string mName;
std::string mCmdline;
};
//!
//! \brief Define a test for logging
//!
//! \param[in] name The name of the test. This should be a string starting with
//! "TensorRT" and containing dot-separated strings containing
//! the characters [A-Za-z0-9_].
//! For example, "TensorRT.sample_googlenet"
//! \param[in] cmdline The command line used to reproduce the test
//
//! \return a TestAtom that can be used in Logger::reportTest{Start,End}().
//!
static TestAtom defineTest(const std::string& name, const std::string& cmdline)
{
return TestAtom(false, name, cmdline);
}
//!
//! \brief A convenience overloaded version of defineTest() that accepts an array of command-line arguments
//! as input
//!
//! \param[in] name The name of the test
//! \param[in] argc The number of command-line arguments
//! \param[in] argv The array of command-line arguments (given as C strings)
//!
//! \return a TestAtom that can be used in Logger::reportTest{Start,End}().
static TestAtom defineTest(const std::string& name, int argc, char const* const* argv)
{
auto cmdline = genCmdlineString(argc, argv);
return defineTest(name, cmdline);
}
//!
//! \brief Report that a test has started.
//!
//! \pre reportTestStart() has not been called yet for the given testAtom
//!
//! \param[in] testAtom The handle to the test that has started
//!
static void reportTestStart(TestAtom& testAtom)
{
reportTestResult(testAtom, TestResult::kRUNNING);
assert(!testAtom.mStarted);
testAtom.mStarted = true;
}
//!
//! \brief Report that a test has ended.
//!
//! \pre reportTestStart() has been called for the given testAtom
//!
//! \param[in] testAtom The handle to the test that has ended
//! \param[in] result The result of the test. Should be one of TestResult::kPASSED,
//! TestResult::kFAILED, TestResult::kWAIVED
//!
static void reportTestEnd(const TestAtom& testAtom, TestResult result)
{
assert(result != TestResult::kRUNNING);
assert(testAtom.mStarted);
reportTestResult(testAtom, result);
}
static int reportPass(const TestAtom& testAtom)
{
reportTestEnd(testAtom, TestResult::kPASSED);
return EXIT_SUCCESS;
}
static int reportFail(const TestAtom& testAtom)
{
reportTestEnd(testAtom, TestResult::kFAILED);
return EXIT_FAILURE;
}
static int reportWaive(const TestAtom& testAtom)
{
reportTestEnd(testAtom, TestResult::kWAIVED);
return EXIT_SUCCESS;
}
static int reportTest(const TestAtom& testAtom, bool pass)
{
return pass ? reportPass(testAtom) : reportFail(testAtom);
}
Severity getReportableSeverity() const
{
return mReportableSeverity;
}
private:
//!
//! \brief returns an appropriate string for prefixing a log message with the given severity
//!
static const char* severityPrefix(Severity severity)
{
switch (severity)
{
case Severity::kINTERNAL_ERROR: return "[F] ";
case Severity::kERROR: return "[E] ";
case Severity::kWARNING: return "[W] ";
case Severity::kINFO: return "[I] ";
case Severity::kVERBOSE: return "[V] ";
default: assert(0); return "";
}
}
//!
//! \brief returns an appropriate string for prefixing a test result message with the given result
//!
static const char* testResultString(TestResult result)
{
switch (result)
{
case TestResult::kRUNNING: return "RUNNING";
case TestResult::kPASSED: return "PASSED";
case TestResult::kFAILED: return "FAILED";
case TestResult::kWAIVED: return "WAIVED";
default: assert(0); return "";
}
}
//!
//! \brief returns an appropriate output stream (cout or cerr) to use with the given severity
//!
static std::ostream& severityOstream(Severity severity)
{
return severity >= Severity::kINFO ? std::cout : std::cerr;
}
//!
//! \brief method that implements logging test results
//!
static void reportTestResult(const TestAtom& testAtom, TestResult result)
{
severityOstream(Severity::kINFO) << "&&&& " << testResultString(result) << " " << testAtom.mName << " # "
<< testAtom.mCmdline << std::endl;
}
//!
//! \brief generate a command line string from the given (argc, argv) values
//!
static std::string genCmdlineString(int argc, char const* const* argv)
{
std::stringstream ss;
for (int i = 0; i < argc; i++)
{
if (i > 0)
ss << " ";
ss << argv[i];
}
return ss.str();
}
Severity mReportableSeverity;
};
namespace
{
//!
//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kVERBOSE
//!
//! Example usage:
//!
//! LOG_VERBOSE(logger) << "hello world" << std::endl;
//!
inline LogStreamConsumer LOG_VERBOSE(const Logger& logger)
{
return LogStreamConsumer(logger.getReportableSeverity(), Severity::kVERBOSE);
}
//!
//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kINFO
//!
//! Example usage:
//!
//! LOG_INFO(logger) << "hello world" << std::endl;
//!
inline LogStreamConsumer LOG_INFO(const Logger& logger)
{
return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINFO);
}
//!
//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kWARNING
//!
//! Example usage:
//!
//! LOG_WARN(logger) << "hello world" << std::endl;
//!
inline LogStreamConsumer LOG_WARN(const Logger& logger)
{
return LogStreamConsumer(logger.getReportableSeverity(), Severity::kWARNING);
}
//!
//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kERROR
//!
//! Example usage:
//!
//! LOG_ERROR(logger) << "hello world" << std::endl;
//!
inline LogStreamConsumer LOG_ERROR(const Logger& logger)
{
return LogStreamConsumer(logger.getReportableSeverity(), Severity::kERROR);
}
//!
//! \brief produces a LogStreamConsumer object that can be used to log messages of severity kINTERNAL_ERROR
// ("fatal" severity)
//!
//! Example usage:
//!
//! LOG_FATAL(logger) << "hello world" << std::endl;
//!
inline LogStreamConsumer LOG_FATAL(const Logger& logger)
{
return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINTERNAL_ERROR);
}
} // anonymous namespace
#endif // TENSORRT_LOGGING_H

29
include/macros.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef __MACROS_H
#define __MACROS_H
#include "NvInfer.h"
#ifdef API_EXPORTS
#if defined(_MSC_VER)
#define API __declspec(dllexport)
#else
#define API __attribute__((visibility("default")))
#endif
#else
#if defined(_MSC_VER)
#define API __declspec(dllimport)
#else
#define API
#endif
#endif // API_EXPORTS
#if NV_TENSORRT_MAJOR >= 8
#define TRT_NOEXCEPT noexcept
#define TRT_CONST_ENQUEUE const
#else
#define TRT_NOEXCEPT
#define TRT_CONST_ENQUEUE
#endif
#endif // __MACROS_H

43
include/model.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <assert.h>
#include <string>
#include "NvInfer.h"
nvinfer1::IHostMemory* buildEngineYolov8Det(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8DetP6(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8DetP2(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8Cls(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw);
nvinfer1::IHostMemory* buildEngineYolov8Seg(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8Pose(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8PoseP6(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8_5uDet(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8_5uDetP6(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd,
float& gw, int& max_channels);
nvinfer1::IHostMemory* buildEngineYolov8Obb(nvinfer1::IBuilder* builder, nvinfer1::IBuilderConfig* config,
nvinfer1::DataType dt, const std::string& wts_path, float& gd, float& gw,
int& max_channels);

41
include/postprocess.h Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include <opencv2/opencv.hpp>
#include "NvInfer.h"
#include "types.h"
// Preprocessing functions
cv::Rect get_rect(cv::Mat& img, float bbox[4]);
// Processing functions
void batch_process(std::vector<std::vector<Detection>>& res_batch, const float* decode_ptr_host, int batch_size,
int bbox_element, const std::vector<cv::Mat>& img_batch);
void batch_process_obb(std::vector<std::vector<Detection>>& res_batch, const float* decode_ptr_host, int batch_size,
int bbox_element, const std::vector<cv::Mat>& img_batch);
void process_decode_ptr_host(std::vector<Detection>& res, const float* decode_ptr_host, int bbox_element, cv::Mat& img,
int count);
void process_decode_ptr_host_obb(std::vector<Detection>& res, const float* decode_ptr_host, int bbox_element,
cv::Mat& img, int count);
// NMS functions
void nms(std::vector<Detection>& res, float* output, float conf_thresh, float nms_thresh = 0.5);
void batch_nms(std::vector<std::vector<Detection>>& batch_res, float* output, int batch_size, int output_size,
float conf_thresh, float nms_thresh = 0.5);
void nms_obb(std::vector<Detection>& res, float* output, float conf_thresh, float nms_thresh = 0.5);
void batch_nms_obb(std::vector<std::vector<Detection>>& batch_res, float* output, int batch_size, int output_size,
float conf_thresh, float nms_thresh = 0.5);
// CUDA-related functions
void cuda_decode(float* predict, int num_bboxes, float confidence_threshold, float* parray, int max_objects,
cudaStream_t stream);
void cuda_nms(float* parray, float nms_threshold, int max_objects, cudaStream_t stream);
void cuda_decode_obb(float* predict, int num_bboxes, float confidence_threshold, float* parray, int max_objects,
cudaStream_t stream);
void cuda_nms_obb(float* parray, float nms_threshold, int max_objects, cudaStream_t stream);
// Drawing functions
void draw_bbox(std::vector<cv::Mat>& img_batch, std::vector<std::vector<Detection>>& res_batch);
void draw_bbox_obb(std::vector<cv::Mat>& img_batch, std::vector<std::vector<Detection>>& res_batch);
void draw_bbox_keypoints_line(std::vector<cv::Mat>& img_batch, std::vector<std::vector<Detection>>& res_batch);
void draw_mask_bbox(cv::Mat& img, std::vector<Detection>& dets, std::vector<cv::Mat>& masks,
std::unordered_map<int, std::string>& labels_map);

16
include/preprocess.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <opencv2/opencv.hpp>
#include "NvInfer.h"
#include "types.h"
#include <map>
void cuda_preprocess_init(int max_image_size);
void cuda_preprocess_destroy();
void cuda_preprocess(uint8_t *src, int src_width, int src_height, float *dst, int dst_width, int dst_height, cudaStream_t stream);
void cuda_batch_preprocess(std::vector<cv::Mat> &img_batch, float *dst, int dst_width, int dst_height, cudaStream_t stream);

19
include/types.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "config.h"
struct alignas(float) Detection {
//center_x center_y w h
float bbox[4];
float conf; // bbox_conf * cls_conf
float class_id;
float mask[32];
float keypoints[kNumberOfPoints * 3]; // keypoints array with dynamic size based on kNumberOfPoints
float angle; // obb angle
};
struct AffineMatrix {
float value[6];
};
const int bbox_element =
sizeof(AffineMatrix) / sizeof(float) + 1; // left, top, right, bottom, confidence, class, keepflag

Some files were not shown because too many files have changed in this diff Show More