Page 2 of 2

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-05 1:56
by chenmodegaoyang
您好很感谢您的帮助,我按照您的要求做了如下修改我的根文件目录的CMakelist如下

Code: Select all

cmake_minimum_required(VERSION 3.0.0)
project(yolov5_deepsort VERSION 0.1.0)

add_subdirectory(deepsort)

set(SDK_PATH $ENV{LUCKFOX_SDK_PATH})
if(NOT SDK_PATH)
    message(WARNING "Please Set Luckfox-pico SDK Path. Such as:export LUCKFOX_SDK_PATH=/home/user/luckfox-pico")
    return()
endif()


set(CMAKE_C_COMPILER "${SDK_PATH}/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc"
)
set(CMAKE_CXX_COMPILER "${SDK_PATH}/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-g++"
)

set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake/opencv4")  # 填入OpenCVConfig.cmake
find_package(OpenCV 4 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

set(
    include_libs  
    "${PROJECT_SOURCE_DIR}/include"
    "${PROJECT_SOURCE_DIR}/yolov5/include"
    "${PROJECT_SOURCE_DIR}/deepsort/include"
    ${PROJECT_SOURCE_DIR}/3rdparty/librknn_api/include
    ${PROJECT_SOURCE_DIR}/3rdparty/rga/include
    ${PROJECT_SOURCE_DIR}/3rdparty
    #${PROJECT_SOURCE_DIR}/3rdparty/opencv/opencv-linux-aarch64/include
    ${PROJECT_SOURCE_DIR}/include/opencv4
    ${PROJECT_SOURCE_DIR}/include/opencv4/opencv2/video
    ${PROJECT_SOURCE_DIR}/lib
)

include_directories(${include_libs})

aux_source_directory(${PROJECT_SOURCE_DIR}/yolov5/src YOLO_SRC_DIR)
aux_source_directory(${PROJECT_SOURCE_DIR}/src YOLO_SRC_DIR)
add_executable(yolov5_deepsort yolov5_deepsort.cpp ${YOLO_SRC_DIR})

# 添加动态链接库
set(
    dynamic_libs  pthread
    ${PROJECT_SOURCE_DIR}/lib/librknnrt.so
    ${PROJECT_SOURCE_DIR}/3rdparty/rga/lib/librga.so
)

# 开启调试选项
add_definitions("-g")

target_link_libraries(yolov5_deepsort ${OpenCV_LIBS})
target_link_libraries(yolov5_deepsort ${dynamic_libs} deepsort)
但是改成这样后不用${PROJECT_SOURCE_DIR}/3rdparty/opencv/opencv-linux-aarch64/include会导致找不到opencv2/video.hpp文件导致报错,我看了下这个目录下:
Image
这样但是我不知道该选哪一个,我就把video/video.hpp向上移了一个目录但是它显示嵌套过深的报错如下:
Image
那我可以用./3rdparty/opencv/opencv-linux-armhf/include/opencv2/video.hpp下面的吗应该也不是luckpico交叉编译的opencv把,那这个该怎么样才能避免调用这个video.hpp文件或者替代一下的方法呢

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-05 2:23
by Crocodile
chenmodegaoyang wrote: 2024-03-05 1:56 您好很感谢您的帮助,我按照您的要求做了如下修改我的根文件目录的CMakelist如下

Code: Select all

cmake_minimum_required(VERSION 3.0.0)
project(yolov5_deepsort VERSION 0.1.0)

add_subdirectory(deepsort)

set(SDK_PATH $ENV{LUCKFOX_SDK_PATH})
if(NOT SDK_PATH)
    message(WARNING "Please Set Luckfox-pico SDK Path. Such as:export LUCKFOX_SDK_PATH=/home/user/luckfox-pico")
    return()
endif()


set(CMAKE_C_COMPILER "${SDK_PATH}/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc"
)
set(CMAKE_CXX_COMPILER "${SDK_PATH}/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-g++"
)

set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake/opencv4")  # 填入OpenCVConfig.cmake
find_package(OpenCV 4 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

set(
    include_libs  
    "${PROJECT_SOURCE_DIR}/include"
    "${PROJECT_SOURCE_DIR}/yolov5/include"
    "${PROJECT_SOURCE_DIR}/deepsort/include"
    ${PROJECT_SOURCE_DIR}/3rdparty/librknn_api/include
    ${PROJECT_SOURCE_DIR}/3rdparty/rga/include
    ${PROJECT_SOURCE_DIR}/3rdparty
    #${PROJECT_SOURCE_DIR}/3rdparty/opencv/opencv-linux-aarch64/include
    ${PROJECT_SOURCE_DIR}/include/opencv4
    ${PROJECT_SOURCE_DIR}/include/opencv4/opencv2/video
    ${PROJECT_SOURCE_DIR}/lib
)

include_directories(${include_libs})

aux_source_directory(${PROJECT_SOURCE_DIR}/yolov5/src YOLO_SRC_DIR)
aux_source_directory(${PROJECT_SOURCE_DIR}/src YOLO_SRC_DIR)
add_executable(yolov5_deepsort yolov5_deepsort.cpp ${YOLO_SRC_DIR})

# 添加动态链接库
set(
    dynamic_libs  pthread
    ${PROJECT_SOURCE_DIR}/lib/librknnrt.so
    ${PROJECT_SOURCE_DIR}/3rdparty/rga/lib/librga.so
)

# 开启调试选项
add_definitions("-g")

target_link_libraries(yolov5_deepsort ${OpenCV_LIBS})
target_link_libraries(yolov5_deepsort ${dynamic_libs} deepsort)
但是改成这样后不用${PROJECT_SOURCE_DIR}/3rdparty/opencv/opencv-linux-aarch64/include会导致找不到opencv2/video.hpp文件导致报错,我看了下这个目录下:
Image
这样但是我不知道该选哪一个,我就把video/video.hpp向上移了一个目录但是它显示嵌套过深的报错如下:
Image
那我可以用./3rdparty/opencv/opencv-linux-armhf/include/opencv2/video.hpp下面的吗应该也不是luckpico交叉编译的opencv把,那这个该怎么样才能避免调用这个video.hpp文件或者替代一下的方法呢
您好,由于我不清楚您的代码架构,我无法对您遇到的问题提供准确的解释
./3rdparty/opencv/opencv-linux-armhf 中的库能否在 luckfox-pico 使用我们目前还没有进行验证,可以会因为 glibc 的缺失导致无法运行。

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-05 6:11
by chenmodegaoyang
我看到官方有串行调用的例子,
Image

我试过上面网址的例子发现很多opencv函数以及交叉编译的opencv不适配,缺少很多需要的库,所以我现在想把官方给的yolov5和推流的demo中加入deepsort的模型这个我发的网址下的deepsort模型,他的形状如下,我不知道该怎么样控制输入和输出去执行这个模型,实现用原来的demo多加一个模型之后吧推理的结果rtsp推流到电脑上,这可能会用到并行使用rknn模型进行推理模式(一起使用)或者yolov5标记完再用这个deepsort模型去识别跟踪,想请官方帮助一下如何处理这个模型的输入和输出才能够正确使用
Image

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-05 8:52
by Crocodile
chenmodegaoyang wrote: 2024-03-05 6:11 我看到官方有串行调用的例子,
Image

我试过上面网址的例子发现很多opencv函数以及交叉编译的opencv不适配,缺少很多需要的库,所以我现在想把官方给的yolov5和推流的demo中加入deepsort的模型这个我发的网址下的deepsort模型,他的形状如下,我不知道该怎么样控制输入和输出去执行这个模型,实现用原来的demo多加一个模型之后吧推理的结果rtsp推流到电脑上,这可能会用到并行使用rknn模型进行推理模式(一起使用)或者yolov5标记完再用这个deepsort模型去识别跟踪,想请官方帮助一下如何处理这个模型的输入和输出才能够正确使用
Image
您好,可以提供一下您把 deepsort 转换为 rknn 前的权重文件吗(最好是ONNX格式)?方便排除一下模型大小和算子兼容的情况,luckfox-pico 的内存资源比较紧张,rtsp 推流,yolov5 推理已经占用大量的资源,可能会因为 deepsort 的内存占用过大导致无法运行。

同时请注意串行使用模型在资源调配上要求很严格,往往仅适用于单张图像推理的使用场景。

deepsort 模型的输入输出处理需要对模型结构有较为清晰的了解,根据模型推理源码进修改,属于深度二次开发内容不在我们的技术支持范围内,我们只能提供解决思路。

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-05 9:26
by chenmodegaoyang
你好这个deepsort原模型是在https://github.com/HowieMa/DeepSORT_YOLOv5_Pytorch这个网址的deep_sort/deep/checkpoint下的ckpt.t7,因为这个模型有点大上传不了附件,另外一个是rknn模型应该是该博主自己裁剪后的是https://github.com/Zhou-sx/yolov5_Deepsort_rknn上的model下的osnet_x0_25_market.rknn这个从他的主函数中看出来的

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-06 3:46
by Crocodile
chenmodegaoyang wrote: 2024-03-05 9:26 你好这个deepsort原模型是在https://github.com/HowieMa/DeepSORT_YOLOv5_Pytorch这个网址的deep_sort/deep/checkpoint下的ckpt.t7,因为这个模型有点大上传不了附件,另外一个是rknn模型应该是该博主自己裁剪后的是https://github.com/Zhou-sx/yolov5_Deepsort_rknn上的model下的osnet_x0_25_market.rknn这个从他的主函数中看出来的
您好,您所提供的 rknn 权重文件是适用于 rk3588 平台的,与 luckfox-pico 的 rv1106 在算子兼容和量化上都有很大差别,不能直接在 luckfox-pico 平台上运行。

这里是转换模型的思路:将 deepsort 权重文件装换为 onnx 格式,再调用 RKNN-Toolkit2 将模型装换为 rknn 格式,再调用 RKNN-ToolKit2 时注意将平台设置为 RV1106,观察打印信息,这样才能保证装换出来的模型的正确使用。

这里是我参考 https://github.com/dyh/unbox_yolov5_deepsort_counting 使用脚本转换出的适用于 luckfox-pico 的 rknn 权重文件,在 luckfox-pico pro 上进行测试可以顺利加载。具体的转换教程您可以参考博客 https://blog.csdn.net/lzzzzzzm/article/ ... /122634983
deepsort.7z (9.32 MiB)
Downloaded 647 times
注意:这个权重文件仅用于验证 luckfox-pico 上运行的情况,无法确定输出数据的可靠性,需要自己编写测试代码进行验证。

同时注意到您所提供的仓库https://github.com/Zhou-sx/yolov5_Deepsort_rknn其他分支提供了其他的跟踪器算法(Sort 和 ByteTrack),不需要依赖模型就可以运行,虽然比起 deepsort 少了特征对比的内容,但是在 luckfox-pico 资源受限的使用场景或许更加合适,移植的门槛也较低。

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-06 6:56
by chenmodegaoyang
Crocodile wrote: 2024-03-01 3:47
chenmodegaoyang wrote: 2024-03-01 3:22 很感谢官方的支持推出了Yolov5物体识别推流的demo适配RV1106,但是在这个例子上我该如何修改才能进行人物识别并且只要在该视频画面内将该人物标注固定ID,并有固定的ID进行跟踪反馈坐标信息,这个能通过改判断语句实现吗,还是只能将Deepsort的模型ckpt.t7进行转化变为rknn放到板子上结合yolov5才能运行,如果有一些相关的有帮助的转化示例,还想请官方帮忙给一下链接或修改方法。
您好,进行人物识别的实现方式可以重新训练 Yolov5 模型转换为 RKNN 模型再进行部署,对类别数和类别进行修改。目前例程提供的模型使用的COCO数据集也有对人物的检测,您可以尝试屏蔽其他识别种类,只保留对人物的识别。
注意:yolov5 只能进行人物识别无法对人物标注ID

如果需要使用 Deepsort 对人物标注 ID 请尝试将 Deepsort 模型转换为 rknn 模型(确认算子兼容)移植流程可以参考 https://wiki.luckfox.com/zh/Luckfox-Pico/RKNN-example
您好很感谢官方能够支持这个跟踪的项目,我试了一下单跑这个yolov5的例子的话他的推流效果因为检测目标数过多导致传输延迟有点大,而且板子的资源消耗程度很大,这种情况下可能如果再加模型会更加吃不消,我想尽可能减少检测目标数并且能够实现只检测人的逻辑其他的物体不予检测这个会不会能够有效提高这个推理和编码的速度这是我修改的代码

Code: Select all

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/wait.h> 
#include <time.h>
#include <unistd.h>
#include <vector>
#include <termios.h>

#include "rtsp_demo.h"
#include "sample_comm.h"
#include "yolov5.h"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>


// disp size
int width    = 720;
int height   = 480;

// model size
int model_width = 640;
int model_height = 640;	
float scale ;
int leftPadding ;
int topPadding  ;
//handle while function
static bool quit=false;

static RK_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) {
	printf("%s\n",__func__);
	VENC_RECV_PIC_PARAM_S stRecvParam;
	VENC_CHN_ATTR_S stAttr;
	memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S));

	// RTSP H264	
	stAttr.stVencAttr.enType = enType;
	//stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
	stAttr.stVencAttr.enPixelFormat = RK_FMT_RGB888;	
	stAttr.stVencAttr.u32Profile = H264E_PROFILE_MAIN;
	stAttr.stVencAttr.u32PicWidth = width;
	stAttr.stVencAttr.u32PicHeight = height;
	stAttr.stVencAttr.u32VirWidth = width;
	stAttr.stVencAttr.u32VirHeight = height;
	stAttr.stVencAttr.u32StreamBufCnt = 2;
	stAttr.stVencAttr.u32BufSize = width * height * 3 / 2;
	stAttr.stVencAttr.enMirror = MIRROR_NONE;
		
	stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
	stAttr.stRcAttr.stH264Cbr.u32BitRate = 3 * 1024;
	stAttr.stRcAttr.stH264Cbr.u32Gop = 1;
	RK_MPI_VENC_CreateChn(chnId, &stAttr);

	memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
	stRecvParam.s32RecvPicNum = -1;
	RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);

	return 0;
}


// demo板dev默认都是0,根据不同的channel 来选择不同的vi节点
int vi_dev_init() {
	printf("%s\n", __func__);
	int ret = 0;
	int devId = 0;
	int pipeId = devId;

	VI_DEV_ATTR_S stDevAttr;
	VI_DEV_BIND_PIPE_S stBindPipe;
	memset(&stDevAttr, 0, sizeof(stDevAttr));
	memset(&stBindPipe, 0, sizeof(stBindPipe));
	// 0. get dev config status
	ret = RK_MPI_VI_GetDevAttr(devId, &stDevAttr);
	if (ret == RK_ERR_VI_NOT_CONFIG) {
		// 0-1.config dev
		ret = RK_MPI_VI_SetDevAttr(devId, &stDevAttr);
		if (ret != RK_SUCCESS) {
			printf("RK_MPI_VI_SetDevAttr %x\n", ret);
			return -1;
		}
	} else {
		printf("RK_MPI_VI_SetDevAttr already\n");
	}
	// 1.get dev enable status
	ret = RK_MPI_VI_GetDevIsEnable(devId);
	if (ret != RK_SUCCESS) {
		// 1-2.enable dev
		ret = RK_MPI_VI_EnableDev(devId);
		if (ret != RK_SUCCESS) {
			printf("RK_MPI_VI_EnableDev %x\n", ret);
			return -1;
		}
		// 1-3.bind dev/pipe
		stBindPipe.u32Num = pipeId;
		stBindPipe.PipeId[0] = pipeId;
		ret = RK_MPI_VI_SetDevBindPipe(devId, &stBindPipe);
		if (ret != RK_SUCCESS) {
			printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
			return -1;
		}
	} else {
		printf("RK_MPI_VI_EnableDev already\n");
	}

	return 0;
}

int vi_chn_init(int channelId, int width, int height) {
	int ret;
	int buf_cnt = 2;
	// VI init
	VI_CHN_ATTR_S vi_chn_attr;
	memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
	vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
	vi_chn_attr.stIspOpt.enMemoryType =
	    VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
	vi_chn_attr.stSize.u32Width = width;
	vi_chn_attr.stSize.u32Height = height;
	vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
	vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE; // COMPRESS_AFBC_16x16;
	vi_chn_attr.u32Depth = 2;
	ret = RK_MPI_VI_SetChnAttr(0, channelId, &vi_chn_attr);
	ret |= RK_MPI_VI_EnableChn(0, channelId);
	if (ret) {
		printf("ERROR: create VI error! ret=%d\n", ret);
		return ret;
	}

	return ret;
}

int test_vpss_init(int VpssChn, int width, int height) {
	printf("%s\n",__func__);
	int s32Ret;
	VPSS_CHN_ATTR_S stVpssChnAttr;
	VPSS_GRP_ATTR_S stGrpVpssAttr;

	int s32Grp = 0;

	stGrpVpssAttr.u32MaxW = 4096;
	stGrpVpssAttr.u32MaxH = 4096;
	stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
	stGrpVpssAttr.stFrameRate.s32SrcFrameRate = -1;
	stGrpVpssAttr.stFrameRate.s32DstFrameRate = -1;
	stGrpVpssAttr.enCompressMode = COMPRESS_MODE_NONE;

	stVpssChnAttr.enChnMode = VPSS_CHN_MODE_USER;
	stVpssChnAttr.enDynamicRange = DYNAMIC_RANGE_SDR8;
	stVpssChnAttr.enPixelFormat = RK_FMT_RGB888;
	stVpssChnAttr.stFrameRate.s32SrcFrameRate = -1;
	stVpssChnAttr.stFrameRate.s32DstFrameRate = -1;
	stVpssChnAttr.u32Width = width;
	stVpssChnAttr.u32Height = height;
	stVpssChnAttr.enCompressMode = COMPRESS_MODE_NONE;

	s32Ret = RK_MPI_VPSS_CreateGrp(s32Grp, &stGrpVpssAttr);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}

	s32Ret = RK_MPI_VPSS_SetChnAttr(s32Grp, VpssChn, &stVpssChnAttr);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}
	s32Ret = RK_MPI_VPSS_EnableChn(s32Grp, VpssChn);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}

	s32Ret = RK_MPI_VPSS_StartGrp(s32Grp);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}
	return s32Ret;
}

cv::Mat letterbox(cv::Mat input)
{
	float scaleX = (float)model_width  / (float)width; //0.888
	float scaleY = (float)model_height / (float)height; //1.125	
	scale = scaleX < scaleY ? scaleX : scaleY;
	
	int inputWidth   = (int)((float)width * scale);
	int inputHeight  = (int)((float)height * scale);

	leftPadding = (model_width  - inputWidth) / 2;
	topPadding  = (model_height - inputHeight) / 2;	
	

	cv::Mat inputScale;
    cv::resize(input, inputScale, cv::Size(inputWidth,inputHeight), 0, 0, cv::INTER_LINEAR);	
	cv::Mat letterboxImage(640, 640, CV_8UC3,cv::Scalar(0, 0, 0));
    cv::Rect roi(leftPadding, topPadding, inputWidth, inputHeight);
    inputScale.copyTo(letterboxImage(roi));

	return letterboxImage; 	
}

void mapCoordinates(int *x, int *y) {	
	int mx = *x - leftPadding;
	int my = *y - topPadding;

    *x = (int)((float)mx / scale);
    *y = (int)((float)my / scale);
}
void rx_buffer_Handle(char *p)
{
if(strncmp(p,"close",5)==0){
	//close demo
	//exit(0);
	quit=true;//wei bian yi
}else if(strncmp(p,"reboot",6)==0){
	//reboot system
	system("reboot");
}else if(strncmp(p,"rkill",5)==0){
	//killall rkipc
	system("killall rkipc");
}	
}


rtsp_demo_handle g_rtsplive = NULL;
rknn_app_context_t rknn_app_ctx;
MPP_CHN_S stSrcChn, stvpssChn;
VENC_STREAM_S stFrame;
int serial_fd;
pthread_t Handle_thread;
//parameter release

void sigint_handler(int sig){
	//release
	fprintf(stderr, "signal %d-------------------------------\n", sig);
	//kill main thread
	quit=true;
	//kill read Thread
	int ret = pthread_cancel(Handle_thread); // 向子线程发送取消信号
    if (ret != 0) {
        perror("Failed to cancel thread");
        exit(-1);
    }	
}
static void *User_Handle(void *arg){
		//UART handle
		char rx_buffer[256];
		while(!quit){
		int bytes_read=read(serial_fd,rx_buffer,sizeof(rx_buffer));
		if(bytes_read < 0){
		perror("receive error");
		}else{
			rx_buffer[bytes_read]='\0';
			//printf("RX:%s\n",rx_buffer);
			write(serial_fd,rx_buffer,bytes_read);
			rx_buffer_Handle(rx_buffer);
		}
		memset(rx_buffer,0,sizeof(rx_buffer));
		}
}


int main(int argc, char *argv[]) {
	

	int flags = fcntl(serial_fd, F_GETFL,0);
	flags |= O_NONBLOCK;
	fcntl(serial_fd, F_SETFL, flags);
	RK_S32 s32Ret = 0; 
	int sX,sY,eX,eY; 
		
	// Rknn model
	char text[16];
		
	object_detect_result_list od_results;
    int ret;
	const char *model_path = "./model/yolov5.rknn";
    memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));	
    init_yolov5_model(model_path, &rknn_app_ctx);
	printf("init rknn model success!\n");
    init_post_process();

	//h264_frame	
		
	stFrame.pstPack = (VENC_PACK_S *)malloc(sizeof(VENC_PACK_S));
 	VIDEO_FRAME_INFO_S h264_frame;
 	VIDEO_FRAME_INFO_S stVpssFrame;

	// rkaiq init
	RK_BOOL multi_sensor = RK_FALSE;	
	const char *iq_dir = "/etc/iqfiles";
	rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
	//hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
	SAMPLE_COMM_ISP_Init(0, hdr_mode, multi_sensor, iq_dir);
	SAMPLE_COMM_ISP_Run(0);

	// rkmpi init
	if (RK_MPI_SYS_Init() != RK_SUCCESS) {
		RK_LOGE("rk mpi sys init fail!");
		return -1;
	}

	// rtsp init	
	
	rtsp_session_handle g_rtsp_session;
	g_rtsplive = create_rtsp_demo(554);
	g_rtsp_session = rtsp_new_session(g_rtsplive, "/live/0");
	rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);
	rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());
	
	// vi init
	vi_dev_init();
	vi_chn_init(0, width, height);

	// vpss init
	test_vpss_init(0, width, height);

	// bind vi to vpss
	
	stSrcChn.enModId = RK_ID_VI;
	stSrcChn.s32DevId = 0;
	stSrcChn.s32ChnId = 0;

	stvpssChn.enModId = RK_ID_VPSS;
	stvpssChn.s32DevId = 0;
	stvpssChn.s32ChnId = 0;
	printf("====RK_MPI_SYS_Bind vi0 to vpss0====\n");
	s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stvpssChn);
	if (s32Ret != RK_SUCCESS) {
		RK_LOGE("bind 0 ch venc failed");
		return -1;
	}

	// venc init
	RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_AVC;
	test_venc_init(0, width, height, enCodecType);
	printf("venc init success\n");

	//uart3 init
	int serial_port_num;
    const char serial_port[] = "/dev/ttyS3";
    
	signal(SIGINT, sigint_handler);

    serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
    if (serial_fd == -1) {
        perror("Failed to open serial port");
        return 1;
    }

    struct termios tty;
    memset(&tty, 0, sizeof(tty));

    if (tcgetattr(serial_fd, &tty) != 0) {
        perror("Error from tcgetattr");
        return 1;
    }

    cfsetospeed(&tty, B9600);
    cfsetispeed(&tty, B9600);

    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;

    if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
        perror("Error from tcsetattr");
        return 1;
    }

	//init fork
	char tx_buffer[256];
	
	pthread_create(&Handle_thread, NULL, User_Handle, NULL);
	int j;
	while(!quit)
	{	
		// get vpss frame
		s32Ret = RK_MPI_VPSS_GetChnFrame(0,0, &stVpssFrame,-1);
		if(s32Ret == RK_SUCCESS)
		{
			void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);	
			//opencv	
			//get camera frame
			cv::Mat frame(height,width,CV_8UC3,data);			
			//cv::Mat frame640;
        	//cv::resize(frame, frame640, cv::Size(640,640), 0, 0, cv::INTER_LINEAR);	
			//letterbox
			//change camera frame with black background and size 640x640
			cv::Mat letterboxImage = letterbox(frame);	
			memcpy(rknn_app_ctx.input_mems[0]->virt_addr, letterboxImage.data, model_width*model_height*3);		
			inference_yolov5_model(&rknn_app_ctx, &od_results);
			j=0;
			for(int i = 0; i < od_results.count; i++)
			{					
				//获取框的四个坐标 
				if(j>=5){
					break;
					}
				if(od_results.count >= 1)
				{
					object_detect_result *det_result = &(od_results.results[i]);
					
					/*printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
							 det_result->box.left, det_result->box.top,
							 det_result->box.right, det_result->box.bottom,
							 det_result->prop);
					*/
					//frame is camera photo but det_result before mapCoordinates(&sX,&sY) is yolov5 result 640x640 location so use mapCoordinates(&sX,&sY) to mate input photo
					//only person handle
					

					if(det_result->cls_id==0)
					{
					sX = (int)(det_result->box.left   );	
					sY = (int)(det_result->box.top 	  );	
					eX = (int)(det_result->box.right  );	
					eY = (int)(det_result->box.bottom );
					
					// printf("$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
					// 		 centerX,centerY,det_result->prop,
					// 		 det_result->box.left,det_result->box.right,
					// 		 det_result->box.top,det_result->box.bottom
					// 		 );
					//send rknn result and send frame after treatment of input camera frame 720x480
					mapCoordinates(&sX,&sY);
					mapCoordinates(&eX,&eY);
					int centerX = (sX + eX) / 2;
					int centerY = (sY + eY) / 2;
					sprintf(tx_buffer,"$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
							 centerX,centerY,det_result->prop,
							 sX,eX,
							 sY,eY);
					write(serial_fd,tx_buffer,strlen(tx_buffer));
					memset(tx_buffer,0,sizeof(tx_buffer));
					cv::rectangle(frame,cv::Point(sX ,sY),
								        cv::Point(eX ,eY),
										cv::Scalar(0,255,0),3);
					sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
					cv::putText(frame,text,cv::Point(sX, sY - 8),
												 cv::FONT_HERSHEY_SIMPLEX,1,
												 cv::Scalar(0,255,0),2);
					//draw circle
					cv::circle(frame, cv::Point(centerX, centerY), 5, cv::Scalar(0, 0, 255), -1);
					j++;
					}
				}
			}
			memcpy(data, frame.data, width * height * 3);					
		}
		

		// send stream to venc to encode
		// encode H264
		RK_MPI_VENC_SendFrame(0, &stVpssFrame,-1);
		// rtsp
		s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
		if(s32Ret == RK_SUCCESS)
		{
			if(g_rtsplive && g_rtsp_session)
			{
				//printf("len = %d PTS = %d \n",stFrame.pstPack->u32Len, stFrame.pstPack->u64PTS);
				//get venc encode stream
				void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
				rtsp_tx_video(g_rtsp_session, (uint8_t *)pData, stFrame.pstPack->u32Len,
							  stFrame.pstPack->u64PTS);
				rtsp_do_event(g_rtsplive);
			}
		}
		// release frame 
		s32Ret = RK_MPI_VPSS_ReleaseChnFrame(0, 0, &stVpssFrame);
		if (s32Ret != RK_SUCCESS) {
			RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
		}
		s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
		if (s32Ret != RK_SUCCESS) {
			RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
			}
		memset(text,0,8);
		}
	//release thread
	pthread_join(Handle_thread, NULL);
	printf("exit result enter--------------------------------------------------------------------------------------------\n");
	close(serial_fd);
	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
	
	RK_MPI_VI_DisableChn(0, 0);
	RK_MPI_VI_DisableDev(0);
	
	RK_MPI_VPSS_StopGrp(0);
	RK_MPI_VPSS_DestroyGrp(0);
	
	RK_MPI_VENC_StopRecvFrame(0);
	RK_MPI_VENC_DestroyChn(0);

	free(stFrame.pstPack);

	if (g_rtsplive)
	rtsp_del_demo(g_rtsplive);
	SAMPLE_COMM_ISP_Stop(0);

	RK_MPI_SYS_Exit();
	// Release rknn model
    release_yolov5_model(&rknn_app_ctx);		
    deinit_post_process();
	
	return 0;
}
虽然用条件让他只检测人的时候进行opencv的处理并且最多画5个框,但是画面还是很卡顿,我不知道是不是这个推理如果物品太多也会要很多时间,要修改哪里才能够减少这个检测推理的目标种类并且能提高一下rtsp流畅度呢,另外这个bytetrace的算法如果不用模型的话,有没有能够参考写入这个yolov5demo中的网址或例子呢?

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2024-03-06 8:01
by Crocodile
chenmodegaoyang wrote: 2024-03-06 6:56
Crocodile wrote: 2024-03-01 3:47
chenmodegaoyang wrote: 2024-03-01 3:22 很感谢官方的支持推出了Yolov5物体识别推流的demo适配RV1106,但是在这个例子上我该如何修改才能进行人物识别并且只要在该视频画面内将该人物标注固定ID,并有固定的ID进行跟踪反馈坐标信息,这个能通过改判断语句实现吗,还是只能将Deepsort的模型ckpt.t7进行转化变为rknn放到板子上结合yolov5才能运行,如果有一些相关的有帮助的转化示例,还想请官方帮忙给一下链接或修改方法。
您好,进行人物识别的实现方式可以重新训练 Yolov5 模型转换为 RKNN 模型再进行部署,对类别数和类别进行修改。目前例程提供的模型使用的COCO数据集也有对人物的检测,您可以尝试屏蔽其他识别种类,只保留对人物的识别。
注意:yolov5 只能进行人物识别无法对人物标注ID

如果需要使用 Deepsort 对人物标注 ID 请尝试将 Deepsort 模型转换为 rknn 模型(确认算子兼容)移植流程可以参考 https://wiki.luckfox.com/zh/Luckfox-Pico/RKNN-example
您好很感谢官方能够支持这个跟踪的项目,我试了一下单跑这个yolov5的例子的话他的推流效果因为检测目标数过多导致传输延迟有点大,而且板子的资源消耗程度很大,这种情况下可能如果再加模型会更加吃不消,我想尽可能减少检测目标数并且能够实现只检测人的逻辑其他的物体不予检测这个会不会能够有效提高这个推理和编码的速度这是我修改的代码

Code: Select all

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/wait.h> 
#include <time.h>
#include <unistd.h>
#include <vector>
#include <termios.h>

#include "rtsp_demo.h"
#include "sample_comm.h"
#include "yolov5.h"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>


// disp size
int width    = 720;
int height   = 480;

// model size
int model_width = 640;
int model_height = 640;	
float scale ;
int leftPadding ;
int topPadding  ;
//handle while function
static bool quit=false;

static RK_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) {
	printf("%s\n",__func__);
	VENC_RECV_PIC_PARAM_S stRecvParam;
	VENC_CHN_ATTR_S stAttr;
	memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S));

	// RTSP H264	
	stAttr.stVencAttr.enType = enType;
	//stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
	stAttr.stVencAttr.enPixelFormat = RK_FMT_RGB888;	
	stAttr.stVencAttr.u32Profile = H264E_PROFILE_MAIN;
	stAttr.stVencAttr.u32PicWidth = width;
	stAttr.stVencAttr.u32PicHeight = height;
	stAttr.stVencAttr.u32VirWidth = width;
	stAttr.stVencAttr.u32VirHeight = height;
	stAttr.stVencAttr.u32StreamBufCnt = 2;
	stAttr.stVencAttr.u32BufSize = width * height * 3 / 2;
	stAttr.stVencAttr.enMirror = MIRROR_NONE;
		
	stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
	stAttr.stRcAttr.stH264Cbr.u32BitRate = 3 * 1024;
	stAttr.stRcAttr.stH264Cbr.u32Gop = 1;
	RK_MPI_VENC_CreateChn(chnId, &stAttr);

	memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
	stRecvParam.s32RecvPicNum = -1;
	RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);

	return 0;
}


// demo板dev默认都是0,根据不同的channel 来选择不同的vi节点
int vi_dev_init() {
	printf("%s\n", __func__);
	int ret = 0;
	int devId = 0;
	int pipeId = devId;

	VI_DEV_ATTR_S stDevAttr;
	VI_DEV_BIND_PIPE_S stBindPipe;
	memset(&stDevAttr, 0, sizeof(stDevAttr));
	memset(&stBindPipe, 0, sizeof(stBindPipe));
	// 0. get dev config status
	ret = RK_MPI_VI_GetDevAttr(devId, &stDevAttr);
	if (ret == RK_ERR_VI_NOT_CONFIG) {
		// 0-1.config dev
		ret = RK_MPI_VI_SetDevAttr(devId, &stDevAttr);
		if (ret != RK_SUCCESS) {
			printf("RK_MPI_VI_SetDevAttr %x\n", ret);
			return -1;
		}
	} else {
		printf("RK_MPI_VI_SetDevAttr already\n");
	}
	// 1.get dev enable status
	ret = RK_MPI_VI_GetDevIsEnable(devId);
	if (ret != RK_SUCCESS) {
		// 1-2.enable dev
		ret = RK_MPI_VI_EnableDev(devId);
		if (ret != RK_SUCCESS) {
			printf("RK_MPI_VI_EnableDev %x\n", ret);
			return -1;
		}
		// 1-3.bind dev/pipe
		stBindPipe.u32Num = pipeId;
		stBindPipe.PipeId[0] = pipeId;
		ret = RK_MPI_VI_SetDevBindPipe(devId, &stBindPipe);
		if (ret != RK_SUCCESS) {
			printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
			return -1;
		}
	} else {
		printf("RK_MPI_VI_EnableDev already\n");
	}

	return 0;
}

int vi_chn_init(int channelId, int width, int height) {
	int ret;
	int buf_cnt = 2;
	// VI init
	VI_CHN_ATTR_S vi_chn_attr;
	memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
	vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
	vi_chn_attr.stIspOpt.enMemoryType =
	    VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
	vi_chn_attr.stSize.u32Width = width;
	vi_chn_attr.stSize.u32Height = height;
	vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
	vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE; // COMPRESS_AFBC_16x16;
	vi_chn_attr.u32Depth = 2;
	ret = RK_MPI_VI_SetChnAttr(0, channelId, &vi_chn_attr);
	ret |= RK_MPI_VI_EnableChn(0, channelId);
	if (ret) {
		printf("ERROR: create VI error! ret=%d\n", ret);
		return ret;
	}

	return ret;
}

int test_vpss_init(int VpssChn, int width, int height) {
	printf("%s\n",__func__);
	int s32Ret;
	VPSS_CHN_ATTR_S stVpssChnAttr;
	VPSS_GRP_ATTR_S stGrpVpssAttr;

	int s32Grp = 0;

	stGrpVpssAttr.u32MaxW = 4096;
	stGrpVpssAttr.u32MaxH = 4096;
	stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
	stGrpVpssAttr.stFrameRate.s32SrcFrameRate = -1;
	stGrpVpssAttr.stFrameRate.s32DstFrameRate = -1;
	stGrpVpssAttr.enCompressMode = COMPRESS_MODE_NONE;

	stVpssChnAttr.enChnMode = VPSS_CHN_MODE_USER;
	stVpssChnAttr.enDynamicRange = DYNAMIC_RANGE_SDR8;
	stVpssChnAttr.enPixelFormat = RK_FMT_RGB888;
	stVpssChnAttr.stFrameRate.s32SrcFrameRate = -1;
	stVpssChnAttr.stFrameRate.s32DstFrameRate = -1;
	stVpssChnAttr.u32Width = width;
	stVpssChnAttr.u32Height = height;
	stVpssChnAttr.enCompressMode = COMPRESS_MODE_NONE;

	s32Ret = RK_MPI_VPSS_CreateGrp(s32Grp, &stGrpVpssAttr);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}

	s32Ret = RK_MPI_VPSS_SetChnAttr(s32Grp, VpssChn, &stVpssChnAttr);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}
	s32Ret = RK_MPI_VPSS_EnableChn(s32Grp, VpssChn);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}

	s32Ret = RK_MPI_VPSS_StartGrp(s32Grp);
	if (s32Ret != RK_SUCCESS) {
		return s32Ret;
	}
	return s32Ret;
}

cv::Mat letterbox(cv::Mat input)
{
	float scaleX = (float)model_width  / (float)width; //0.888
	float scaleY = (float)model_height / (float)height; //1.125	
	scale = scaleX < scaleY ? scaleX : scaleY;
	
	int inputWidth   = (int)((float)width * scale);
	int inputHeight  = (int)((float)height * scale);

	leftPadding = (model_width  - inputWidth) / 2;
	topPadding  = (model_height - inputHeight) / 2;	
	

	cv::Mat inputScale;
    cv::resize(input, inputScale, cv::Size(inputWidth,inputHeight), 0, 0, cv::INTER_LINEAR);	
	cv::Mat letterboxImage(640, 640, CV_8UC3,cv::Scalar(0, 0, 0));
    cv::Rect roi(leftPadding, topPadding, inputWidth, inputHeight);
    inputScale.copyTo(letterboxImage(roi));

	return letterboxImage; 	
}

void mapCoordinates(int *x, int *y) {	
	int mx = *x - leftPadding;
	int my = *y - topPadding;

    *x = (int)((float)mx / scale);
    *y = (int)((float)my / scale);
}
void rx_buffer_Handle(char *p)
{
if(strncmp(p,"close",5)==0){
	//close demo
	//exit(0);
	quit=true;//wei bian yi
}else if(strncmp(p,"reboot",6)==0){
	//reboot system
	system("reboot");
}else if(strncmp(p,"rkill",5)==0){
	//killall rkipc
	system("killall rkipc");
}	
}


rtsp_demo_handle g_rtsplive = NULL;
rknn_app_context_t rknn_app_ctx;
MPP_CHN_S stSrcChn, stvpssChn;
VENC_STREAM_S stFrame;
int serial_fd;
pthread_t Handle_thread;
//parameter release

void sigint_handler(int sig){
	//release
	fprintf(stderr, "signal %d-------------------------------\n", sig);
	//kill main thread
	quit=true;
	//kill read Thread
	int ret = pthread_cancel(Handle_thread); // 向子线程发送取消信号
    if (ret != 0) {
        perror("Failed to cancel thread");
        exit(-1);
    }	
}
static void *User_Handle(void *arg){
		//UART handle
		char rx_buffer[256];
		while(!quit){
		int bytes_read=read(serial_fd,rx_buffer,sizeof(rx_buffer));
		if(bytes_read < 0){
		perror("receive error");
		}else{
			rx_buffer[bytes_read]='\0';
			//printf("RX:%s\n",rx_buffer);
			write(serial_fd,rx_buffer,bytes_read);
			rx_buffer_Handle(rx_buffer);
		}
		memset(rx_buffer,0,sizeof(rx_buffer));
		}
}


int main(int argc, char *argv[]) {
	

	int flags = fcntl(serial_fd, F_GETFL,0);
	flags |= O_NONBLOCK;
	fcntl(serial_fd, F_SETFL, flags);
	RK_S32 s32Ret = 0; 
	int sX,sY,eX,eY; 
		
	// Rknn model
	char text[16];
		
	object_detect_result_list od_results;
    int ret;
	const char *model_path = "./model/yolov5.rknn";
    memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));	
    init_yolov5_model(model_path, &rknn_app_ctx);
	printf("init rknn model success!\n");
    init_post_process();

	//h264_frame	
		
	stFrame.pstPack = (VENC_PACK_S *)malloc(sizeof(VENC_PACK_S));
 	VIDEO_FRAME_INFO_S h264_frame;
 	VIDEO_FRAME_INFO_S stVpssFrame;

	// rkaiq init
	RK_BOOL multi_sensor = RK_FALSE;	
	const char *iq_dir = "/etc/iqfiles";
	rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
	//hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
	SAMPLE_COMM_ISP_Init(0, hdr_mode, multi_sensor, iq_dir);
	SAMPLE_COMM_ISP_Run(0);

	// rkmpi init
	if (RK_MPI_SYS_Init() != RK_SUCCESS) {
		RK_LOGE("rk mpi sys init fail!");
		return -1;
	}

	// rtsp init	
	
	rtsp_session_handle g_rtsp_session;
	g_rtsplive = create_rtsp_demo(554);
	g_rtsp_session = rtsp_new_session(g_rtsplive, "/live/0");
	rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);
	rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());
	
	// vi init
	vi_dev_init();
	vi_chn_init(0, width, height);

	// vpss init
	test_vpss_init(0, width, height);

	// bind vi to vpss
	
	stSrcChn.enModId = RK_ID_VI;
	stSrcChn.s32DevId = 0;
	stSrcChn.s32ChnId = 0;

	stvpssChn.enModId = RK_ID_VPSS;
	stvpssChn.s32DevId = 0;
	stvpssChn.s32ChnId = 0;
	printf("====RK_MPI_SYS_Bind vi0 to vpss0====\n");
	s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stvpssChn);
	if (s32Ret != RK_SUCCESS) {
		RK_LOGE("bind 0 ch venc failed");
		return -1;
	}

	// venc init
	RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_AVC;
	test_venc_init(0, width, height, enCodecType);
	printf("venc init success\n");

	//uart3 init
	int serial_port_num;
    const char serial_port[] = "/dev/ttyS3";
    
	signal(SIGINT, sigint_handler);

    serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
    if (serial_fd == -1) {
        perror("Failed to open serial port");
        return 1;
    }

    struct termios tty;
    memset(&tty, 0, sizeof(tty));

    if (tcgetattr(serial_fd, &tty) != 0) {
        perror("Error from tcgetattr");
        return 1;
    }

    cfsetospeed(&tty, B9600);
    cfsetispeed(&tty, B9600);

    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;

    if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
        perror("Error from tcsetattr");
        return 1;
    }

	//init fork
	char tx_buffer[256];
	
	pthread_create(&Handle_thread, NULL, User_Handle, NULL);
	int j;
	while(!quit)
	{	
		// get vpss frame
		s32Ret = RK_MPI_VPSS_GetChnFrame(0,0, &stVpssFrame,-1);
		if(s32Ret == RK_SUCCESS)
		{
			void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);	
			//opencv	
			//get camera frame
			cv::Mat frame(height,width,CV_8UC3,data);			
			//cv::Mat frame640;
        	//cv::resize(frame, frame640, cv::Size(640,640), 0, 0, cv::INTER_LINEAR);	
			//letterbox
			//change camera frame with black background and size 640x640
			cv::Mat letterboxImage = letterbox(frame);	
			memcpy(rknn_app_ctx.input_mems[0]->virt_addr, letterboxImage.data, model_width*model_height*3);		
			inference_yolov5_model(&rknn_app_ctx, &od_results);
			j=0;
			for(int i = 0; i < od_results.count; i++)
			{					
				//获取框的四个坐标 
				if(j>=5){
					break;
					}
				if(od_results.count >= 1)
				{
					object_detect_result *det_result = &(od_results.results[i]);
					
					/*printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
							 det_result->box.left, det_result->box.top,
							 det_result->box.right, det_result->box.bottom,
							 det_result->prop);
					*/
					//frame is camera photo but det_result before mapCoordinates(&sX,&sY) is yolov5 result 640x640 location so use mapCoordinates(&sX,&sY) to mate input photo
					//only person handle
					

					if(det_result->cls_id==0)
					{
					sX = (int)(det_result->box.left   );	
					sY = (int)(det_result->box.top 	  );	
					eX = (int)(det_result->box.right  );	
					eY = (int)(det_result->box.bottom );
					
					// printf("$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
					// 		 centerX,centerY,det_result->prop,
					// 		 det_result->box.left,det_result->box.right,
					// 		 det_result->box.top,det_result->box.bottom
					// 		 );
					//send rknn result and send frame after treatment of input camera frame 720x480
					mapCoordinates(&sX,&sY);
					mapCoordinates(&eX,&eY);
					int centerX = (sX + eX) / 2;
					int centerY = (sY + eY) / 2;
					sprintf(tx_buffer,"$RV1106,%s,%d,%d,%.3f,%d,%d,%d,%d\n", coco_cls_to_name(det_result->cls_id),
							 centerX,centerY,det_result->prop,
							 sX,eX,
							 sY,eY);
					write(serial_fd,tx_buffer,strlen(tx_buffer));
					memset(tx_buffer,0,sizeof(tx_buffer));
					cv::rectangle(frame,cv::Point(sX ,sY),
								        cv::Point(eX ,eY),
										cv::Scalar(0,255,0),3);
					sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
					cv::putText(frame,text,cv::Point(sX, sY - 8),
												 cv::FONT_HERSHEY_SIMPLEX,1,
												 cv::Scalar(0,255,0),2);
					//draw circle
					cv::circle(frame, cv::Point(centerX, centerY), 5, cv::Scalar(0, 0, 255), -1);
					j++;
					}
				}
			}
			memcpy(data, frame.data, width * height * 3);					
		}
		

		// send stream to venc to encode
		// encode H264
		RK_MPI_VENC_SendFrame(0, &stVpssFrame,-1);
		// rtsp
		s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
		if(s32Ret == RK_SUCCESS)
		{
			if(g_rtsplive && g_rtsp_session)
			{
				//printf("len = %d PTS = %d \n",stFrame.pstPack->u32Len, stFrame.pstPack->u64PTS);
				//get venc encode stream
				void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
				rtsp_tx_video(g_rtsp_session, (uint8_t *)pData, stFrame.pstPack->u32Len,
							  stFrame.pstPack->u64PTS);
				rtsp_do_event(g_rtsplive);
			}
		}
		// release frame 
		s32Ret = RK_MPI_VPSS_ReleaseChnFrame(0, 0, &stVpssFrame);
		if (s32Ret != RK_SUCCESS) {
			RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
		}
		s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
		if (s32Ret != RK_SUCCESS) {
			RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
			}
		memset(text,0,8);
		}
	//release thread
	pthread_join(Handle_thread, NULL);
	printf("exit result enter--------------------------------------------------------------------------------------------\n");
	close(serial_fd);
	RK_MPI_SYS_UnBind(&stSrcChn, &stvpssChn);
	
	RK_MPI_VI_DisableChn(0, 0);
	RK_MPI_VI_DisableDev(0);
	
	RK_MPI_VPSS_StopGrp(0);
	RK_MPI_VPSS_DestroyGrp(0);
	
	RK_MPI_VENC_StopRecvFrame(0);
	RK_MPI_VENC_DestroyChn(0);

	free(stFrame.pstPack);

	if (g_rtsplive)
	rtsp_del_demo(g_rtsplive);
	SAMPLE_COMM_ISP_Stop(0);

	RK_MPI_SYS_Exit();
	// Release rknn model
    release_yolov5_model(&rknn_app_ctx);		
    deinit_post_process();
	
	return 0;
}
虽然用条件让他只检测人的时候进行opencv的处理并且最多画5个框,但是画面还是很卡顿,我不知道是不是这个推理如果物品太多也会要很多时间,要修改哪里才能够减少这个检测推理的目标种类并且能提高一下rtsp流畅度呢,另外这个bytetrace的算法如果不用模型的话,有没有能够参考写入这个yolov5demo中的网址或例子呢?
您好,代码的优化和改进需要对 yolov5 模型有较为深刻的了解,仅在main函数通过屏蔽其他识别种类是无法有效减少卡顿的,我们的技术支持只能帮你解决例程使用的问题,对例程的二次开发还是需要您自行研究。

bytetrace 的算法请查阅您所参考的 deepsort-rknn 分支 https://github.com/Zhou-sx/yolov5_Deeps ... /bytetrack

由于我们目前没有识别追踪方面的开发计划,这个主题的技术支持只能到这,希望您能顺利实现您需要的功能。

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2025-03-24 13:41
by mchertz
what is the final result? Did you manage to implement target tracking?

I continued adapting the code (https://github.com/Zhou-sx/yolov5_Deepsort_rknn.git) for RV1106.

I fixed the above problems, and then when compiling I got the error "undefined reference to `rknn_set_core_mask'", that is, in the library "/3rdparty/librknn_api/Linux/armhf-uclibc/librknnmrt.so" there is no implementation of this function. Is this normal?

Code: Select all

ret = rknn_set_core_mask(ctx, core_mask);
    if(ret < 0)
    {
        printf("set NPU core_mask fail! ret=%d\n", ret);
        exit(-1);
    }
Then I commented rknn_set_core_mask and managed to compile and run the application on the board. However, the board returned an error
Image

This happened on these lines of code

Code: Select all

	// Create input tensor memory
	rknn_tensor_type   input_type   = RKNN_TENSOR_UINT8; // default input type is int8 (normalize and quantize need compute in outside)
    rknn_tensor_format input_layout = RKNN_TENSOR_NHWC; // default fmt is NHWC, npu only support NHWC in zero copy mode

	_input_attrs[0].type = input_type;
	_input_attrs[0].fmt = input_layout;
	_input_mems[0] = rknn_create_mem(ctx, _input_attrs[0].size_with_stride);

	// rknn outputs
	printf("output tensors:\n");
	memset(_output_attrs, 0, _n_output * sizeof(rknn_tensor_attr));
	for (uint32_t i = 0; i < _n_output; i++) {
		_output_attrs[i].index = i;
       // _output_attrs[i].fmt = RKNN_TENSOR_NHWC;//MY
		// query info
		ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(_output_attrs[i]), sizeof(rknn_tensor_attr));
		if (ret != RKNN_SUCC) {
            printf("rknn_query fail! ret=%d\n", ret);
			exit(-1);
		}
		dump_tensor_attr(&_output_attrs[i]);
	}

	// Create output tensor memory
	for (uint32_t i = 0; i < _n_output; ++i) {
		// default output type is depend on model, this require float32 to compute top5
		// allocate float32 output tensor
		int output_size = _output_attrs[i].n_elems * sizeof(float);
		_output_mems[i]  = rknn_create_mem(ctx, output_size);
	}

	// Set input tensor memory
	ret = rknn_set_io_mem(ctx, _input_mems[0], &_input_attrs[0]);
	if (ret < 0) {
        printf("_rknn_set_io_mem fail! ret=%d\n", ret);
		exit(-1);
	}

	// Set output tensor memory
	for (uint32_t i = 0; i < _n_output; ++i) {
		// default output type is depend on model, this require float32 to compute top5
		_output_attrs[i].type = RKNN_TENSOR_FLOAT32;
		// set output memory and attribute
		ret = rknn_set_io_mem(ctx, _output_mems[i], &_output_attrs[i]);
		if (ret < 0) {
            printf("__rknn_set_io_mem fail! ret=%d\n", ret);
			exit(-1);
		}
	}
}
Are there any suggestions on how to fix this?

Re: 关于RV1106 Pico max上yolov5和Deepsort实现物体跟踪请求

Posted: 2025-03-26 1:18
by Crocodile
Hello, the hardware environment used by the repository source code https://github.com/Zhou-sx/yolov5_Deepsort_rknn is different from the npu version of rv1106, and the model needs to be reconverted, and the inference also needs to call the API supported by rv1106.
Adapting the RV1106 to a new model is a complex undertaking that is outside the scope of our technical support, and we only provide advice. Since we don't have a dedicated deep learning engineer, we are limited in how much help we can provide