关于RKRTSP推流方法结合YOLOV5物体检测无法显示推理结果问题

  • 您好,感谢您对 yolov5 物体检测和 rtsp 推流的尝试。

    实例中结合 rknn 的操作方式是通过从 VPSS (视频处理子系统)中获取一帧数据(VIDEO_FRAME_INFO_S 结构体),将其数据读取出来进行模型推理、opencv-mobile图像处理等操作,再拷贝会原本的结构体中使用 RK_MPI_VENC_GetStream 传入 VENC(视频编码模块)编码为 H264 格式,最后使用 rkrtsp 接口推流。详细可以参考文档
    Downloaded 875 times
    您提供的 main.cc 同时使用了两种图像捕获的方式,在 opencv-mobile 初始化后就无法进行 VI 的初始化,这或许就是程序无法顺利运行的原因。

    这里是一个 rtsp 推流 yolov5 检测图像的例程,您可以参考一下。
    https://github.com/luckfox-eng29/luckfo ... tsp_yolov5
    注意: 64MB RAM 的资源不够支撑 yolov5 rtsp 推流,如果您使用的是 luckfox-pico mini/plus(rv1103)是无法运行的。
  • 很感谢官方给予的支持,我用了下demo确实效果还可以,还想问一下,如果不通过USB 0获取网络串流的话,即如果我想通过网线设备eth 0去看RTSP推流的话需要做哪些工作呢,我目前发现接上网线到设备后这个板子并没有eth 0 的IP地址:
    Image
    在电脑端手动设置了IP192.168.0.201但在串流上用了rtsp://192.168.0.201/live/0没有办法显示这个是不是也需要给eth 0 设置一下他的静态IP才可以用这个demo进行推流通过网线链接电脑显示呢,另外也尝试了都用DHCP方式获取IP但是均显示上面图片结果
    Attachments
    RTSP推流demo.png
  • 上面发的帖子网络串流可能是电脑网卡的问题分配不了这个IP地址,直接接路由器得以解决,除此之外想问如果想通过另一个单片机对这个RV1106的RTSP的demo的推理结果用串口进行分析,并且能通过串口进行重启RV1106设备或者开启关闭这个推理程序的操作该如何实现呢?开启的逻辑我想着可以用官方的启动脚本进行设置,一启动就关闭摄像头其他程序占用并开启推理,但是在程序中如果遇到死机等特殊情况,我希望可以用另一个单片机的串口给他发送重启或者关闭demo运行的指令,这个我目前没有想到好的解决方法,还想请官方提供一些帮助
  • chenmodegaoyang wrote: 2024-02-26 2:05 上面发的帖子网络串流可能是电脑网卡的问题分配不了这个IP地址,直接接路由器得以解决,除此之外想问如果想通过另一个单片机对这个RV1106的RTSP的demo的推理结果用串口进行分析,并且能通过串口进行重启RV1106设备或者开启关闭这个推理程序的操作该如何实现呢?开启的逻辑我想着可以用官方的启动脚本进行设置,一启动就关闭摄像头其他程序占用并开启推理,但是在程序中如果遇到死机等特殊情况,我希望可以用另一个单片机的串口给他发送重启或者关闭demo运行的指令,这个我目前没有想到好的解决方法,还想请官方提供一些帮助
    您好,将RTSP的推理结果通过串口输出请参考链接 viewtopic.php?p=982#p982

    在启动脚本中关闭摄像头占用请修改 /oem/usr/bin/RkLunch.sh 脚本,注释掉 rkipc 的相关启动脚本后重启就不会自动执行 rkipc 程序了。

    Code: Select all

            #if [ -d "/oem/usr/share/iqfiles" ];then
            #        rkipc -a /oem/usr/share/iqfiles &
            #else
            #       rkipc &
            #
    
    串口接收可以参考 wiki https://wiki.luckfox.com/zh/Luckfox-Pic ... -Pico-UART 编写一个循环获取串口数据的程序,判断接收数据进行操作。关闭 demo 可以调用 system() 函数使用 /usr/sh 执行 kill - 9 xxx 关闭进程,启动再运行可执行文件即可。
    注意:直接 kill 可能会导致申请的内存得不到释放,请作好内存释放管理。

    希望这个思路能对您解决问题提供帮助。
  • Crocodile wrote: 2024-02-26 3:36
    chenmodegaoyang wrote: 2024-02-26 2:05 上面发的帖子网络串流可能是电脑网卡的问题分配不了这个IP地址,直接接路由器得以解决,除此之外想问如果想通过另一个单片机对这个RV1106的RTSP的demo的推理结果用串口进行分析,并且能通过串口进行重启RV1106设备或者开启关闭这个推理程序的操作该如何实现呢?开启的逻辑我想着可以用官方的启动脚本进行设置,一启动就关闭摄像头其他程序占用并开启推理,但是在程序中如果遇到死机等特殊情况,我希望可以用另一个单片机的串口给他发送重启或者关闭demo运行的指令,这个我目前没有想到好的解决方法,还想请官方提供一些帮助
    您好,将RTSP的推理结果通过串口输出请参考链接 viewtopic.php?p=982#p982

    在启动脚本中关闭摄像头占用请修改 /oem/usr/bin/RkLunch.sh 脚本,注释掉 rkipc 的相关启动脚本后重启就不会自动执行 rkipc 程序了。

    Code: Select all

            #if [ -d "/oem/usr/share/iqfiles" ];then
            #        rkipc -a /oem/usr/share/iqfiles &
            #else
            #       rkipc &
            #
    
    串口接收可以参考 wiki https://wiki.luckfox.com/zh/Luckfox-Pic ... -Pico-UART 编写一个循环获取串口数据的程序,判断接收数据进行操作。关闭 demo 可以调用 system() 函数使用 /usr/sh 执行 kill - 9 xxx 关闭进程,启动再运行可执行文件即可。
    注意:直接 kill 可能会导致申请的内存得不到释放,请作好内存释放管理。

    希望这个思路能对您解决问题提供帮助。
    您好很感谢您提出的解决方法,还想问一下这个串口的话官方给的串口调试是用的串口一,这个串口可以进入根文件系统调试,进入时需要输入密码和账号,函数中打印的函数输出的我发现串口一也有对应输出,但是因为有根文件系统的影响,还需要通过串口进行一些Linux指令的操作才可以运行程序和关闭程序等,这个如果单独就想当做串口输出和接收数据使用和判断,不做调试进入根文件系统,是在代码中写入开启其他的串口吗?还是都必须进入根文件系统进行操作?
  • chenmodegaoyang wrote: 2024-02-26 6:31
    Crocodile wrote: 2024-02-26 3:36
    chenmodegaoyang wrote: 2024-02-26 2:05 上面发的帖子网络串流可能是电脑网卡的问题分配不了这个IP地址,直接接路由器得以解决,除此之外想问如果想通过另一个单片机对这个RV1106的RTSP的demo的推理结果用串口进行分析,并且能通过串口进行重启RV1106设备或者开启关闭这个推理程序的操作该如何实现呢?开启的逻辑我想着可以用官方的启动脚本进行设置,一启动就关闭摄像头其他程序占用并开启推理,但是在程序中如果遇到死机等特殊情况,我希望可以用另一个单片机的串口给他发送重启或者关闭demo运行的指令,这个我目前没有想到好的解决方法,还想请官方提供一些帮助
    您好,将RTSP的推理结果通过串口输出请参考链接 viewtopic.php?p=982#p982

    在启动脚本中关闭摄像头占用请修改 /oem/usr/bin/RkLunch.sh 脚本,注释掉 rkipc 的相关启动脚本后重启就不会自动执行 rkipc 程序了。

    Code: Select all

            #if [ -d "/oem/usr/share/iqfiles" ];then
            #        rkipc -a /oem/usr/share/iqfiles &
            #else
            #       rkipc &
            #
    
    串口接收可以参考 wiki https://wiki.luckfox.com/zh/Luckfox-Pic ... -Pico-UART 编写一个循环获取串口数据的程序,判断接收数据进行操作。关闭 demo 可以调用 system() 函数使用 /usr/sh 执行 kill - 9 xxx 关闭进程,启动再运行可执行文件即可。
    注意:直接 kill 可能会导致申请的内存得不到释放,请作好内存释放管理。

    希望这个思路能对您解决问题提供帮助。
    您好很感谢您提出的解决方法,还想问一下这个串口的话官方给的串口调试是用的串口一,这个串口可以进入根文件系统调试,进入时需要输入密码和账号,函数中打印的函数输出的我发现串口一也有对应输出,但是因为有根文件系统的影响,还需要通过串口进行一些Linux指令的操作才可以运行程序和关闭程序等,这个如果单独就想当做串口输出和接收数据使用和判断,不做调试进入根文件系统,是在代码中写入开启其他的串口吗?还是都必须进入根文件系统进行操作?
    您好,调试串口理论上可以通过调整 printk 的打印等级来屏蔽等级信息,但是由于这是一个可交互的串口,直接用来实现您需要的功能可能因为各种问题导致您的控制失败。

    推荐使用不被系统占用的 串口三 和 串口四 来作为您进行控制的串口,串口三 和 串口四 可以单独做串口输出和接收数据判断,可以控制输出指定内容,调试串口的输出不仅包含了 printf 输出的内容也包含了其他模块的打印信息。

    用串口调试需要登录后才能进入根文件系统进行指令操作,但是在 rootfs 的加载结束阶段后立即执行 /etc/init.d/rcS 脚本,运行流程是在验证登录之前。

    您可以通过开机脚本来实现您需要的功能,假设您目前使用串口三,您可以将编译好的可执行文件放置在/usr/bin 中。添加开机脚本 S99uart3control (99表示打印的顺序,越大越晚执行)到 /etc/init.d 中,使 rootfs 加载后执行串口控制程序。您在 luckfox-pico 初始化后就可以直接使用其他单片机的串口来控制 luckfox-pico 。
  • 好的,我试着用串口三进行另一个单片机的数据的读取和给另外一个单片机进行发送推理结果,这个阶段中我用了父子进程,这个时候是父进程回收子进程和不断循环读取数据进行判断,子进程是发送rknn推理结果,这个时候在处理子进程回收时,发现这个demo中的代码所有的回收资源处理都是在while循环之后进行但是我每次结束程序的时候却是用的CTRL+C进行的意外终止,这可能导致while后面的释放函数没有被调用,这个关于资源回收的话需要注意哪些方面呢,是不是需要把所有的释放资源的函数放入到信号处理函数中使用并且把对应参数弄成全局变量呢,或者有没有更简单的释放方法吗?
    Crocodile wrote: 2024-02-26 7:30
    chenmodegaoyang wrote: 2024-02-26 6:31
    Crocodile wrote: 2024-02-26 3:36 您好,将RTSP的推理结果通过串口输出请参考链接 viewtopic.php?p=982#p982

    在启动脚本中关闭摄像头占用请修改 /oem/usr/bin/RkLunch.sh 脚本,注释掉 rkipc 的相关启动脚本后重启就不会自动执行 rkipc 程序了。

    Code: Select all

            #if [ -d "/oem/usr/share/iqfiles" ];then
            #        rkipc -a /oem/usr/share/iqfiles &
            #else
            #       rkipc &
            #
    
    串口接收可以参考 wiki https://wiki.luckfox.com/zh/Luckfox-Pic ... -Pico-UART 编写一个循环获取串口数据的程序,判断接收数据进行操作。关闭 demo 可以调用 system() 函数使用 /usr/sh 执行 kill - 9 xxx 关闭进程,启动再运行可执行文件即可。
    注意:直接 kill 可能会导致申请的内存得不到释放,请作好内存释放管理。

    希望这个思路能对您解决问题提供帮助。
    您好很感谢您提出的解决方法,还想问一下这个串口的话官方给的串口调试是用的串口一,这个串口可以进入根文件系统调试,进入时需要输入密码和账号,函数中打印的函数输出的我发现串口一也有对应输出,但是因为有根文件系统的影响,还需要通过串口进行一些Linux指令的操作才可以运行程序和关闭程序等,这个如果单独就想当做串口输出和接收数据使用和判断,不做调试进入根文件系统,是在代码中写入开启其他的串口吗?还是都必须进入根文件系统进行操作?
    您好,调试串口理论上可以通过调整 printk 的打印等级来屏蔽等级信息,但是由于这是一个可交互的串口,直接用来实现您需要的功能可能因为各种问题导致您的控制失败。

    推荐使用不被系统占用的 串口三 和 串口四 来作为您进行控制的串口,串口三 和 串口四 可以单独做串口输出和接收数据判断,可以控制输出指定内容,调试串口的输出不仅包含了 printf 输出的内容也包含了其他模块的打印信息。

    用串口调试需要登录后才能进入根文件系统进行指令操作,但是在 rootfs 的加载结束阶段后立即执行 /etc/init.d/rcS 脚本,运行流程是在验证登录之前。

    您可以通过开机脚本来实现您需要的功能,假设您目前使用串口三,您可以将编译好的可执行文件放置在/usr/bin 中。添加开机脚本 S99uart3control (99表示打印的顺序,越大越晚执行)到 /etc/init.d 中,使 rootfs 加载后执行串口控制程序。您在 luckfox-pico 初始化后就可以直接使用其他单片机的串口来控制 luckfox-pico 。
  • chenmodegaoyang wrote: 2024-02-26 9:33
    Crocodile wrote: 2024-02-26 7:30
    chenmodegaoyang wrote: 2024-02-26 6:31

    您好很感谢您提出的解决方法,还想问一下这个串口的话官方给的串口调试是用的串口一,这个串口可以进入根文件系统调试,进入时需要输入密码和账号,函数中打印的函数输出的我发现串口一也有对应输出,但是因为有根文件系统的影响,还需要通过串口进行一些Linux指令的操作才可以运行程序和关闭程序等,这个如果单独就想当做串口输出和接收数据使用和判断,不做调试进入根文件系统,是在代码中写入开启其他的串口吗?还是都必须进入根文件系统进行操作?
    您好,调试串口理论上可以通过调整 printk 的打印等级来屏蔽等级信息,但是由于这是一个可交互的串口,直接用来实现您需要的功能可能因为各种问题导致您的控制失败。

    推荐使用不被系统占用的 串口三 和 串口四 来作为您进行控制的串口,串口三 和 串口四 可以单独做串口输出和接收数据判断,可以控制输出指定内容,调试串口的输出不仅包含了 printf 输出的内容也包含了其他模块的打印信息。

    用串口调试需要登录后才能进入根文件系统进行指令操作,但是在 rootfs 的加载结束阶段后立即执行 /etc/init.d/rcS 脚本,运行流程是在验证登录之前。

    您可以通过开机脚本来实现您需要的功能,假设您目前使用串口三,您可以将编译好的可执行文件放置在/usr/bin 中。添加开机脚本 S99uart3control (99表示打印的顺序,越大越晚执行)到 /etc/init.d 中,使 rootfs 加载后执行串口控制程序。您在 luckfox-pico 初始化后就可以直接使用其他单片机的串口来控制 luckfox-pico 。
    好的,我试着用串口三进行另一个单片机的数据的读取和给另外一个单片机进行发送推理结果,这个阶段中我用了父子进程,这个时候是父进程回收子进程和不断循环读取数据进行判断,子进程是发送rknn推理结果,这个时候在处理子进程回收时,发现这个demo中的代码所有的回收资源处理都是在while循环之后进行但是我每次结束程序的时候却是用的CTRL+C进行的意外终止,这可能导致while后面的释放函数没有被调用,这个关于资源回收的话需要注意哪些方面呢,是不是需要把所有的释放资源的函数放入到信号处理函数中使用并且把对应参数弄成全局变量呢,或者有没有更简单的释放方法吗?
    您好,您可以参考一下 <luckfox-sdk>/media/samples/simple_test/ 中瑞芯微提供的 demo 的用法,使用全局变量 quit 来控制 while 循环的运行,通过信号量来改变 quit 的值,使程序在跳出 while 循环后可以完成资源回收。
  • 您好我成功修改了您的demo并且编译成功其中修改后的rtsp_opencv.cc文件代码如下:

    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  ;
    
    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);
    }else if(strncmp(p,"reboot",5)==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;
    //parameter release
    
    void sigint_handler(int signal){
    	//release
    	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();
    	exit(0);	
    }
    
    
    
    int main(int argc, char *argv[]) {
    	
    
    
    	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
    	pid_t child_pid;
    	char tx_buffer[256];
    	child_pid=fork();
    	if(child_pid<0)
    	{
    		perror("fork error");
    		return -1;
    	}
    	if(child_pid==0){
    	while(1)
    	{	
    		// 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	
    			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
    			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);
    
    			for(int i = 0; i < od_results.count; i++)
    			{					
    				//获取框的四个坐标 
    				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);
    					*/
    					sX = (int)(det_result->box.left   );	
    					sY = (int)(det_result->box.top 	  );	
    					eX = (int)(det_result->box.right  );	
    					eY = (int)(det_result->box.bottom );
    					int centerX = (sX + eX) / 2;
    					int centerY = (sY + eY) / 2;
    					// 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
    					// 		 );
    					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,
    							 det_result->box.left,det_result->box.right,
    							 det_result->box.top,det_result->box.bottom
    							 );
    					//send rknn result
    					write(serial_fd,tx_buffer,sizeof(tx_buffer));
    					memset(tx_buffer,0,sizeof(tx_buffer));
    					mapCoordinates(&sX,&sY);
    					mapCoordinates(&eX,&eY);
    
    					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);
    				}
    			}
    
    			memcpy(data, frame.data, width * height * 3);					
    		}
    		
    
    		// send stream
    		// 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);
    				
    				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);
    		}
    	}else if(child_pid >0){
    		//UART handle
    		char rx_buffer[256];
    		int status;
    		while(1){
    		int ret = waitpid(child_pid, &status,WNOHANG);
    		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,sizeof(rx_buffer));
    			rx_buffer_Handle(rx_buffer);
    		}
    		memset(rx_buffer,0,sizeof(rx_buffer));
    		if(ret>0)
    		{
    			close(serial_fd);
    			exit(0);
    		}
    		}
    		
    	}
    
    	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;
    }
    
    
    我添加了串口3打印的逻辑,并且分为了父子进程,父进程用来处理发送过来的串口数据并做出相应系统操作,子进程用于发送RKNN推理结果,并且加入了SIGINT(ctrl+c信号)的处理函数,用于释放while循环之后一直没有被释放的资源,并将涉及到释放的资源弄成了全局变量,也添加了一些子进程的回收操作,想问这个从串口三判断完数据后用system(“lINUX指令”)方式执行操作这样的方式可行吗如下代码

    Code: Select all

    void rx_buffer_Handle(char *p)
    {
    if(strncmp(p,"close",5)==0){
    	//close demo
    	exit(0);
    }else if(strncmp(p,"reboot",5)==0){
    	//reboot system
    	system("reboot");
    }else if(strncmp(p,"rkill",5)==0){
    	//killall rkipc
    	system("killall rkipc");
    }	
    还是需要写一些执行脚本(包含Linux指令)去调用脚本运行Linux指令呢?如果要写的话执行脚本是怎样的格式呢放在哪里比较合适呢?另外这个自启动想要直接运行这个程序的话可以在inid中写一个开机启动执行这个demo的话,格式有什么要求吗