近
易百纳技术社区
易百纳技术社区
3.8k 访问量
0 原创专栏
0 资料
1 粉丝
个性签名:此E友还没有留下个性签名哦~
加入易百纳时间:2020-11-17

个人成就

易百纳技术社区 共获得 2 个点赞
易百纳技术社区 共获得 2 个收藏
易百纳技术社区 共获得 0 次评论/回复

个人勋章

分类专栏

Ta擅长的领域

暂无
按发布时间
按阅读量
按点赞量
  • 文章目录 一、概述二、参考资料三、准备工作四、皮肤检测算法基于YCrCb颜色空间的Cr分量+Otsu法阈值分割算法关于高斯滤波基于YCrCb颜色空间Cr, Cb范围筛选法基于HSV颜色空间H,S,V范围筛选法一、概述本文中的人体肤色检测功能采用 OpenCV 库实现。OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上. 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。 本文主要使用了OpenCV的图像色域转换, 颜色通道分割, 高斯滤波, OSTU自动阈值等功能。 二、参考资料OpenCV探索之路:皮肤检测技术;学习OpenCV—肤色检测。 三、准备工作安装 Python-OpenCV 库 pip install opencv-python -i https://mirrors.ustc.edu.cn/pypi/web/simple 利用 -i 为pip指令镜像源, 这里使用电子科技大学的源, 速度比官方源更快。 安装 Numpy 科学计算库 pip install numpy -i https://mirrors.ustc.edu.cn/pypi/web/simple 图像的基本操作 import numpy as np import cv2 imname = "6358772.jpg" # 读入图像 ''' 使用函数 cv2.imread() 读入图像。这幅图像应该在此程序的工作路径,或者给函数提供完整路径. 警告:就算图像的路径是错的,OpenCV 也不会提醒你的,但是当你使用命令print(img)时得到的结果是None。 ''' img = cv2.imread(imname, cv2.IMREAD_COLOR) ''' imread函数的第一个参数是要打开的图像的名称(带路径) 第二个参数是告诉函数应该如何读取这幅图片. 其中 cv2.IMREAD_COLOR 表示读入一副彩色图像, alpha 通道被忽略, 默认值 cv2.IMREAD_ANYCOLOR 表示读入一副彩色图像 cv2.IMREAD_GRAYSCALE 表示读入一副灰度图像 cv2.IMREAD_UNCHANGED 表示读入一幅图像,并且包括图像的 alpha 通道 ''' # 显示图像 ''' 使用函数 cv2.imshow() 显示图像。窗口会自动调整为图像大小。第一个参数是窗口的名字, 其次才是我们的图像。你可以创建多个窗口,只要你喜欢,但是必须给他们不同的名字. ''' cv2.imshow("image", img) # "image" 参数为图像显示窗口的标题, img是待显示的图像数据 cv2.waitKey(0) #等待键盘输入,参数表示等待时间,单位毫秒.0表示无限期等待 cv2.destroyAllWindows() # 销毁所有cv创建的窗口 # 也可以销毁指定窗口: #cv2.destroyWindow("image") # 删除窗口标题为"image"的窗口 # 保存图像 ''' 使用函数 cv2.imwrite() 来保存一个图像。首先需要一个文件名,之后才是你要保存的图像。 保存的图片的格式由后缀名决定. ''' #cv2.imwrite(imname + "01.png", img) cv2.imwrite(imname + "01.jpg", img) 运行截图 四、皮肤检测算法基于YCrCb颜色空间的Cr分量+Otsu法阈值分割算法YCrCb 即 YUV ,其中 Y 表示明亮度 Luminance 或 Luma , 也就是灰阶值. 而 U 和 V 表示的则是色度 Chrominance 或 Chroma ,作用是描述影像色彩及饱和度, 用于指定像素的颜色. 亮度 是透过RGB输入信号来建立的, 方法是将RGB信号的特定部分叠加到一起. 色度 则定义了颜色的两个方面─色调与饱和度,分别用 Cr 和 Cb 来表示. 其中, Cr 反映了RGB输入信号红色部分与RGB信号亮度值之间的差异. 而 Cb 反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。 该方法的原理也很简单: 将RGB图像转换到 YCrCb 颜色空间,提取 Cr 分量图像对 Cr 分量进行高斯滤波对Cr做自二值化阈值分割处理 OSTU 法 关于高斯滤波使用低通滤波器可以达到图像模糊的目的。这对与去除噪音很有帮助。其实就是去除图像中的高频成分(比如:噪音,边界)。所以边界也会被模糊一点。(当然,也有一些模糊技术不会模糊掉边界)。OpenCV 提供了四种模糊技术。高斯滤波就是其中一种。实现的函数是 cv2.GaussianBlur()。我们需要指定高斯滤波器的宽和高(必须是奇数)。以及高斯函数沿 X,Y 方向的标准差。如果我们只指定了 X 方向的的标准差,Y 方向也会取相同值。如果两个标准差都是 0,那么函数会根据核函数的大小自己计算。高斯滤波可以有效的从图像中去除高斯噪音。如果你愿意的话,你也可以使用函数 cv2.getGaussianKernel() 自己构建一个高斯滤波器。 # 肤色检测之一: YCrCb之Cr分量 + OTSU二值化 img = cv2.imread(imname, cv2.IMREAD_COLOR) ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) # 把图像转换到YUV色域 (y, cr, cb) = cv2.split(ycrcb) # 图像分割, 分别获取y, cr, br通道图像 # 高斯滤波, cr 是待滤波的源图像数据, (5,5)是值窗口大小, 0 是指根据窗口大小来计算高斯函数标准差 cr1 = cv2.GaussianBlur(cr, (5, 5), 0) # 对cr通道分量进行高斯滤波 # 根据OTSU算法求图像阈值, 对图像进行二值化 _, skin1 = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) cv2.imshow("image CR", cr1) cv2.imshow("Skin Cr+OSTU", skin1 ) 检测效果 基于YCrCb颜色空间Cr, Cb范围筛选法这个方法跟法一其实大同小异,只是颜色空间不同而已。据资料显示,正常黄种人的Cr分量大约在140至175之间,Cb分量大约在100至120之间。大家可以根据自己项目需求放大或缩小这两个分量的范围,会有不同的效果。 # 肤色检测之二: YCrCb中 140<=Cr<=175 100<=Cb<=120 img = cv2.imread(imname, cv2.IMREAD_COLOR) ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) # 把图像转换到YUV色域 (y, cr, cb) = cv2.split(ycrcb) # 图像分割, 分别获取y, cr, br通道分量图像 skin2 = np.zeros(cr.shape, dtype=np.uint8) # 根据源图像的大小创建一个全0的矩阵,用于保存图像数据 (x, y) = cr.shape # 获取源图像数据的长和宽 # 遍历图像, 判断Cr和Br通道的数值, 如果在指定范围中, 则置把新图像的点设为255,否则设为0 for i in range(0, x): for j in range(0, y): if (cr[i][j] > 140) and (cr[i][j] < 175) and (cb[i][j] > 100) and (cb[i][j] < 120): skin2[i][j] = 255 else: skin2[i][j] = 0 cv2.imshow(imname, img) cv2.imshow(imname + " Skin2 Cr+Cb", skin2) 检测效果 基于HSV颜色空间H,S,V范围筛选法这个方法跟上一方法类似,只是颜色空间不同而已。据资料显示,正常黄种人的H分量大约在7至20之间,S分量大约在28至256之间,V分量大约在50至256之间。大家可以根据自己项目需求放大或缩小这两个分量的范围,会有不同的效果。 # 肤色检测之三: HSV中 7 7) and (_h[i][j] < 20) and (_s[i][j] > 28) and (_s[i][j] < 255) and (_v[i][j] > 50) and (_v[i][j] < 255): skin3[i][j] = 255 else: skin3[i][j] = 0 cv2.imshow(imname, img) cv2.imshow(imname + " Skin3 HSV", skin3) 检测效果 三种检测算法效果对比
    2024-02-27
    0 0 871
  • 文章目录 1、sample的整体架构2、sample代码学习的关键3、sample_venc的大体分析4、图像像素格式深度理解4.1 颜色的学问4.2 rawRGB和图像采集过程5、RGB和YUV详解5.1 RGB方式表示颜色5.2 YUV6、海思MPP功能模块和视频缓存池6.1 MPP功能模块框图6.2 sample中SAMPLE_VENC_1080P_CLASSIC函数开始看7.2 相关的数据结构和API8、VI部分 知识要点9、VPSS部分 知识要点9.1 VPSS的手册部分解读10、VENC部分 知识要点1、sample的整体架构(1)sample其实是很多个例程,所以有很多个main (2)每一个例程面向一个典型应用,common是通用性主体函数,我们只分析venc (3)基本的架构是:venc中的main调用venc中的功能函数,再调用common中的功能函数,再调用mpp中的API,再调用HI3518E内部的硬件单元。 (4)sample的配置和编译,重点注意很多环境变量,目录结构不要乱动。 2、sample代码学习的关键(1)得理解很多基础概念,譬如图像采集原理、模拟数字、通道、绑定、组、视频缓冲池、在线/离线模式等等 (2)得从宏观上理解整个视频采集、内部传递、处理、编码输出、网络传输等的过程。 (3)得反复看代码,熟才能生巧,才能帮助理解整个代码。 (4)得查阅mpp手册,熟悉海思这一套API的规矩和一般用法。 3、sample_venc的大体分析(1)从main入手,main的传参分析 (2)几个重要的基本概念: H.264 H.265 MJPEG 视频编码规范标准 1080P、720P、VGA、D1 视频分辨率(清晰度) fps(frame per second) 帧率:每秒多少帧 4、图像像素格式深度理解4.1 颜色的学问(1)颜色是主观还是客观存在?是主观存在的,颜色的本质是光的波长,这些不同波长的光映射到人的眼中就成了不同的颜色,正因为有人去看才有了颜色这个概念 (2)颜色的三个关键:亮度、色度、饱和度 (3)人的眼睛并非理想完美的颜色识别器件,图像表达也有清晰度和质量高低的差异 (4)科学研究如何定义(或者表达、记录、计算)一种颜色?色彩空间的概念 色彩空间:如何用数字表达一种颜色,例如rgb888,rgb565等 4.2 rawRGB和图像采集过程(1)图像采集的过程:光照在成像物体被反射->镜头汇聚->Sensor光电转换->ADC为rawRGB 光照到成像物体上被反射到镜头汇聚起来传到焦点,Sensor就在焦点处,Sensor是一个平面,被分成很多区域,每一个最小区域就是一个像素,这一路像素就是一路单独的光电转换器,转出来的电信号是一个模拟值,光照到每个像素上就生成了这个像素的模拟电压。 Sensor有个参数叫做分辨率,或者说叫做像素个数,比如买手机时经常说多少w像素,指的就是这里的意思。 这些模拟电信号再由ADC转换成数字的电信号(rawRGB) (2)sensor上每个像素只采集一种颜色的光,因此sensor每个像素只能为R或G或B 也就是说手机摄像头上一个像素点是rgb的一个颜色。 而手机的LCD显示屏,一个像素点里面有三个小灯,rgb。 也就是说光电转换只能转换一种颜色分量,不可能一个点转换R、G、B三种分量。 (3)rawRGB和RGB都是用来描述图像的,图像采集时RGB是由rawRGB计算而来的 由rawRGB进行联合附近的分量进行加权平均计算得到RGB (4)因为图像颜色本身有一定连贯性,而且人眼是非理想的,因此图像采集和再显示给人这整个构成中有三个要素:sensor分辨率、pitch(两个像素点中心的距离)、观看距离 (5)如果是视频,质量好坏还要加上帧率framerate (6)图像的表达、压缩、修整等相关技术,就发生在rawRGB进来以后的各个环节 表达:rgb565、rgb888、1080p等 压缩:bmp、jpg、png等 修整:锐化、曝光等 5、RGB和YUV详解5.1 RGB方式表示颜色(1)RGB有RGB565和RGB888,ARGB等多种子分类 (2)RGB的本质:将色度分解为R、G、B三部分,然后记录下亮度数据,也就是说RGB没有记录颜色的色度,色度是固定的红绿蓝。 (3)RGB的优势:方便数字化表达,广泛用于数字化彩色显示器,计算机编程等领域。 (4)RGB的劣势:和传统的灰度图兼容不好,表达颜色的效率不高 灰度图只有亮度,没有颜色,而RGB又默认分解成三种基色,所以会兼容不好 5.2 YUV(1)YUV是一种色彩空间,Y表示亮度,U和V表示色度。只有Y就是黑白图像,也就是灰度图,再加上UV就是彩色图像了。YUV的一个好处就是让彩色系统和传统黑白系统很好的兼容。 (2)YUV和RGB的相同点是:都是用来表达颜色的数学方法;不同点是:对颜色的描述思路和方法不同。RGB将一个颜色拆解为3个纯色的亮度组合,YUV将一个颜色分解为一个亮度和2个色度的组合。 (3)RGB和YUV之间可以用数学方法互相换算,是个典型的浮点运算过程。 (4)YUV和YCbCr几乎可以看做一个概念,详细的区分以后再去慢慢体会。 (5)YUV格式分为packed和planar两种。具体参考:http://blog.csdn.net/sunnylgz/article/details/7580628 (6)有多种YUV相关的概念需要弄清楚(以下均为planar格式) YUV YUV422(YUYV) YUV420(YUV411) YUV422 planar(YUV422P) [Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,U2,U3,U4],[V1,V2,V3,V4] YUV420 Planar(YUV420P) [Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,U2],[V1,V2] YUV422 semi planar(YUV422SP) [Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,V1],[U2,V2],[U3,V3],[U4,V4] YUV420 semi Planar(YUV420SP) [Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,V1],[U2,V2] 参考:http://blog.csdn.net/bingqingsuimeng/article/details/50716390和https://www.2cto.com/kf/201303/198023.html 6、海思MPP功能模块和视频缓存池6.1 MPP功能模块框图(1)找到MPP手册 麦克风声电转换AD转换采样-》AI音频输入并降噪-》AENC编码-》音频码流 音频码流-》ADEC解码-》AO音频输出-》喇叭放大 镜头-》Sensor光电转换得到模拟电信号-》AD转换得到rawRGB-》VI视频输入-》VPSS接收并输出多路分辨率不同的图像-》VENC编码成H.264码流 (2)详见系统概述1.3部分 6.2 sample中SAMPLE_VENC_1080P_CLASSIC函数开始看(1)PAYLOAD_TYPE_E (2)PIC_SIZE_E (3)VB_CONF_S7、视频缓存池7.1、什么是视频缓冲池(1)视频的本质是多帧图片,图片的本质是RGB或rawRGB数据,要占用一段连续内存 (2)视频的裁剪、缩放、修正处理(马赛克)等各种操作,本质上就是对内存中的数据进行运算 (3)视频缓存池(VB, video buffer)就是一段很大,又被合理划分和管理的内存,用来做视频数据的暂存和运算场地 (4)公共视频缓存池的公共2字,可以理解为全局变量,也就是各个模块都能访问的一段内存 (5)看似视频缓存块在各个模块之间流转,实际上并没有内存复制,而是指针在传递 (6)视频缓存池的内存由MPP来维护,我们在系统启动时就把整个SDRAM分成了2部分:系统部分(由linux kernel来维护管理)和mpp部分(由mpp系统来维护管理) (7)缓存池需要几个,每个中包含几个缓存块,每个缓存块多大,都是可以由用户程序设置好参数,然后调用MPP的相应API来向MPP申请分配的。 7.2 相关的数据结构和API(1)VB_CONF_S结构体(2)HI_MPI_VB_SetConf(3)HI_MPI_VB_Init 8、VI部分 知识要点(1)常用Sensor的接口有三种:MIPI、LVDS、DC(2)WDR宽动态:一副图像里面,局部曝光和其它地方是不一样的(3)isp就是image signal process,图像信号处理。(4)HI3518E内部的ISP单元是隶属于VI模块的。VI模块就包含3大部分:第一部分是和Sensor对接的部分(Sensor是什么接口的,mipi,dc等,怎么去操作),第二部分就是ISP,第三部分就是VI dev和channeldev:就是用来采集图像的一个硬件单元 9、VPSS部分 知识要点9.1 VPSS的手册部分解读VI/VPSS 离/在线模式VI 和 VPSS 的协作模式分为以下 2 种(模式切换由 load 脚本参数控制,对应 sys 模块参数 vi_vpss_online): VI/VPSS 离线模式是指 VI 进行时序解析后将图像数据写出到 DDR,VPSS 从DDR 中载入 VI 采集的数据进行图像处理,是传统 Hi3518/Hi3520D 等芯片的VI/VPSS 的协作模式。 VI/VPSS 在线模式是指 VI 进行时序解析后直接在芯片内部将数据传递到 VPSS,中间无 DDR 写出的过程。在线模式可以省一定的带宽和内存,降低端到端的延时。需要注意的是,在线模式时,因为 VI 不写出数据到 DDR,无法进行CoverEx、OverlayEx、Rotate、LDC 等操作,需要在 VPSS 各通道写出后再进行Rotate/LDC 等处理,而且有些功能只在离线下能支持,比如 DIS。 总结:离线模式:公共视频缓冲池-》VI模块处理缓冲池那一份-》复制到DDR-》VPSS处理DDR中的那一份在线模式:公共视频缓冲池-》VI模块处理缓冲池那一份-》VI模块将缓冲池的指针传递给VPSS,VPSS处理缓冲池中的那一份 10、VENC部分 知识要点有了以上,VENC部分代码就很简单 学习博文:LCD常用接口:https://blog.csdn.net/wocao1226/article/details/23870149 yuv格式:http://blog.csdn.net/sunnylgz/article/details/7580628http://blog.csdn.net/bingqingsuimeng/article/details/50716390https://www.2cto.com/kf/201303/198023.html 图像编码原理:http://blog.csdn.net/newchenxf/article/details/51693753 Qp:http://blog.csdn.net/u013354805/article/details/51988171 VI、VPSS、VENC数据流向图 海思示例代码 函数调用关系 sample_venc.c main SAMPLE_VENC_1080P_CLASSIC SAMPLE_COMM_VI_GetSizeBySensor(step1) //获取Sensor采集图像的大小---》720P SAMPLE_COMM_SYS_CalcPicVbBlkSize //计算缓冲块大小---》1280 * 768 * 1.5+HeaderSize 1.5是yuv420图像中一个像素的大小 SAMPLE_COMM_SYS_GetPicSize //获取Sensor图像的大小---》1280 * 720 VB_PIC_HEADER_SIZE //计算图像头的大小---》HeaderSize SAMPLE_COMM_SYS_Init(step2) //MPP系统初始化 HI_MPI_SYS_Exit //去除 MPP 系统。禁用一切模块 HI_MPI_VB_Exit //去除 MPP 视频缓存池 HI_MPI_VB_SetConf //设置 MPP 视频缓存池属性---》最大缓冲池个数为128,实际缓冲池个数为16,每个缓冲块的大小和个数 HI_MPI_VB_Init //初始化 MPP 视频缓存池 HI_MPI_SYS_SetConf //配置系统控制参数---》64字节对齐 HI_MPI_SYS_Init //初始化 MPP 系统 SAMPLE_COMM_VI_StartVi(step3) //启动vi dev & CHN进行捕获 IsSensorInput //传感器输入是 电视或Sensor SAMPLE_COMM_VI_StartIspAndVi //启动Isp SAMPLE_COMM_VI_StartMIPI(1) //mipi接口的配置---》3.3V SAMPLE_COMM_VI_SetMipiAttr //mipi接口的配置 fd = open("/dev/hi_mipi", O_RDWR); //打开mipi的设备文件 ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr) //应用层操作Sensor的驱动,对Sensor做一些必要的初始化 SAMPLE_COMM_ISP_Init(2) //配置传感器和ISP(包括WDR宽动态模式)。 目的是启动3518e芯片内部的ISP单元 sensor_register_callback //传感器寄存器回调 HI_MPI_AE_Register //注册AE库,自动曝光 HI_MPI_AWB_Register //注册AWB库,自动白平衡 HI_MPI_AF_Register //注册AF库,自动对焦 HI_MPI_ISP_MemInit //初始化 ISP 外部寄存器 HI_MPI_ISP_SetWDRMode //设置 ISP 宽动态的模式---》不启用 HI_MPI_ISP_SetPubAttr //配置 ISP 属性---》rawRGB的排列顺序---GRBG、帧率为30、图像区域的起始点、图像区域的宽和高 HI_MPI_ISP_Init //初始化ISP系统 SAMPLE_COMM_ISP_Run(3) //运行isp线程 pthread_create(&gs_IspPid, &attr, (void* (*)(void*))Test_ISP_Run, NULL) //创建线程 Test_ISP_Run //线程函数 HI_MPI_ISP_Run //开始运行ISP系统 SAMPLE_COMM_VI_StartDev(4) //配置并打开Dev HI_MPI_VI_SetDevAttr //配置 Dev的属性---》接口模式为DC,单路工作方式,图像的扫描模式是逐行扫描,转换成yuv420,使用内部ISP,输入数据类型为RGB,不启用数据逆向 HI_MPI_ISP_GetWDRMode //获取 ISP 宽动态模式 HI_MPI_VI_SetWDRAttr //配置 WDR宽动态模式的 工作属性---》都不开启 HI_MPI_VI_EnableDev //启用Dev SAMPLE_COMM_VI_StartChn(5) //配置并打开通道chn(最多1个) HI_MPI_VI_SetChnAttr //设置 VI 通道chn属性---》通道支持的图像属性是720P,像素存储格式是yuv420sp,原始图像不镜像不翻转,不进行帧率控制,不压缩 HI_MPI_VI_SetRotate //设置 VI 图像旋转属性--》图像从通道中出来后的旋转角度---不旋转 HI_MPI_VI_EnableChn //启用通道chn SAMPLE_COMM_SYS_GetPicSize(step4) //获取Sensor图像的大小---》1280 * 720 SAMPLE_COMM_VPSS_StartGroup //启动VPSS的Group HI_MPI_VPSS_CreateGrp //创建Group HI_MPI_VPSS_GetNRParam //获取 vpss 3DNR 参数 HI_MPI_VPSS_SetNRParam //设置 vpss 3DNR 参数 HI_MPI_VPSS_StartGrp //启用Group SAMPLE_COMM_VI_BindVpss //Group绑定VI模块中的Dev0中的chn0 SAMPLE_COMM_VI_Mode2Param //获取VI的参数---》是有1个Dev和chn HI_MPI_SYS_Bind //VI通道chn0 绑定 vpss组Group0 SAMPLE_COMM_VPSS_EnableChn //在Group内部创建几路自己所用的chn HI_MPI_VPSS_SetChnAttr //设置 VPSS 通道属性---》不进行帧率控制 HI_MPI_VPSS_SetChnMode //设置 VPSS 通道工作模式---》VPSS通道工作模式为USER模式,目标图像的像素格式是yuv420sp,目标图像的宽度是720,目标图像的高是1280,设置 256byte 段式压缩 HI_MPI_VPSS_EnableChn //打开chn SAMPLE_COMM_VENC_Start(step5) //启动venc流模式(h264, mjpeg) SAMPLE_COMM_SYS_GetPicSize //获取Sensor图像的大小---》1280x720 HI_MPI_VENC_CreateChn //创建VENC chn---》编码通道的宽度是720、高度是1280,要编码的图片的宽度是720、高度是1280,流缓冲区的大小是1280x720,编码出的视频流的图像质量是高清还是啥啥,获取流的模式是切片模式,不支持B帧,设置码率控制模式:CBR、FIXQF、VBR,以及码率控制相关的参数; HI_MPI_VENC_StartRecvPic //开始接收图片 SAMPLE_COMM_VENC_BindVpss //VENC的Dev绑定VPSS的chn HI_MPI_SYS_Bind //VENC的Dev绑定VPSS的chn SAMPLE_COMM_VENC_StartGetStream(step6) //获取流,然后将其保存到文件。 SAMPLE_COMM_VENC_GetVencStreamProc //线程函数 HI_MPI_VENC_GetChnAttr //获取编码通道的编码属性。 SAMPLE_COMM_VENC_GetFilePostfix //获取文件名后缀--->.h.264 HI_MPI_VENC_GetFd //mpp内部把VENC编码好的视频流数据做成文件,然后把文件描述符通过这个API获取 HI_MPI_VENC_Query //查询编码通道状态---》判断当前这帧图像的码流包个数是否为0,为0则退出程序 HI_MPI_VENC_GetStream //获取编码码流。 SAMPLE_COMM_VENC_SaveStream //将帧保存到文件 SAMPLE_COMM_VENC_SaveH264 fwrite HI_MPI_VENC_ReleaseStream //释放码流缓存。 SAMPLE_COMM_VENC_StopGetStream(step7) //退出程序
    2024-02-22
    2 2 1589
  • 一、实验目的 1.进一步了解ROS通信机制; 2.了解Turtlebot各个节点之间的关系; 3.熟悉使用ROS消息类型; 4.了解小车闭环控制。 5.了解rviz是如何将目标点发送出去的。 二、实验环境 Ubuntu16.04+ROS 。 三、实验原理 发布者订阅者实现,发布者发出目标点,订阅者接受到后控制Turtlebo进行导航。 四、实验内容 1.获取rviz发送目标点的topic; 2.对已经建好的图获取相应目标点的坐标(多个,即小车要去的目标),还没建图先完成建图; 3.查阅资料,编写发布一目标点的python或c脚本; 4.编写发布多个目标点的python或c脚本。 五、实验步骤 1.获取rviz发送目标点的topic; 在这里插入图片描述 2.对已经建好的图获取相应目标点的坐标(多个,即小车要去的目标),还没建图先完成建图; 打开gazebo roslaunch nav_sim myrobot_world.launch rosrun teleop_twist_keyboard teleop_twist_keyboard.py 通过移动小车,设置目标点,记录左侧显示的位置坐标。x y z 和分别绕xyz轴旋转的角度:roll pitch yaw 3.查阅资料,编写发布一目标点的python或c脚本; #include #include #include #include using namespace std; int flag=1; class Goal{ public: geometry_msgs::PoseStamped goal; Goal(){ pub=n.advertise("/move_base_simple/goal",10); sub=n.subscribe("/cmd_vel",1,&Goal::callback,this); goal.header.frame_id = "map"; //改为自己记录目标点的坐标 goal.pose.position.x = pose.x; goal.pose.position.y = pose.y; goal.pose.position.z = pose.z; goal.pose.orientation.x = pose._x; goal.pose.orientation.y = pose._y; goal.pose.orientation.z = pose._z; goal.pose.orientation.w = pose._w; } private: ros::NodeHandle n; ros::Publisher pub; ros::Subscriber sub; void callback(const geometry_msgs::Twist &v); }; void Goal::callback(const geometry_msgs::Twist &v) { if(flag==1&&v.linear.x==0){ ROS_INFO("Sending goal!"); pub.publish(goal); } } int main(int argc,char **argv) { ros::init(argc,argv,"send_goal"); Goal g; ros::spin(); return 0; } 4.编写发布多个目标点的python或c脚本。 #include #include #include #include using namespace std; int flag=1; int g1=0,g2=0,g3=0; class Goal{ public: geometry_msgs::PoseStamped goal_1; geometry_msgs::PoseStamped goal_2; geometry_msgs::PoseStamped goal_3; Goal(){ pub=n.advertise("/move_base_simple/goal",10); sub=n.subscribe("/cmd_vel",1,&Goal::callback,this); goal_1.header.frame_id = "map"; goal_2.header.frame_id = "map"; goal_3.header.frame_id = "map"; //以下三个目标的改为自己目标点的信息 //Goal one goal_1.pose.position.x = 0.033449; goal_1.pose.position.y = 8.273015; goal_1.pose.position.z = 0.050003; goal_1.pose.orientation.x = 0; goal_1.pose.orientation.y = 0; goal_1.pose.orientation.z = 0; goal_1.pose.orientation.w = 1.487145; //Goal two goal_2.pose.position.x = -0.207746; goal_2.pose.position.y = 17.607371; goal_2.pose.position.z = 0.050003; goal_2.pose.orientation.x = 0; goal_2.pose.orientation.y = 0; goal_2.pose.orientation.z = 0; goal_2.pose.orientation.w = 1.483080; //Goal three goal_3.pose.position.x = 2.467109; goal_3.pose.position.y = 9.938154; goal_3.pose.position.z = 0.050002; goal_3.pose.orientation.x = 0; goal_3.pose.orientation.y = 0; goal_3.pose.orientation.z = 0; goal_3.pose.orientation.w = -1.889479; } private: ros::NodeHandle n; ros::Publisher pub; ros::Subscriber sub; void callback(const geometry_msgs::Twist &v); }; void Goal::callback(const geometry_msgs::Twist &v){ //发送第一个目标点,如果发送成功,v将大于0 if(flag==1&&v.linear.x==0){ ROS_INFO("Sending goal one!"); pub.publish(goal_1); g1=1; } if(v.linear.x>0&&flag==1) flag=2; if(flag==2&&v.linear.x==0&&g1){ ROS_INFO("Sending goal two!"); pub.publish(goal_2); g2=1; } if(v.linear.x>0&&flag==2&&g2) flag=3; if(flag==3&&v.linear.x==0&&g2){ ROS_INFO("Sending goal three!"); pub.publish(goal_3); g3=1; } } int main(int argc,char **argv) { ros::init(argc,argv,"many_goal"); Goal g; ros::spin(); return 0; } 在CMakeLists.txt文件中添加 add_executable(send_goal src/send_goal.cpp) target_link_libraries(send_goal ${catkin_LIBRARIES}) add_executable(many_goal src/many_goal.cpp) target_link_libraries(many_goal ${catkin_LIBRARIES}) 六、实验数据与结果评价 实验数据: 1.目标点数:3个 2.目标点位置: one:x:0.033449;y:8.273015;z:0.050003;_x:0;_y:0;_z:0;_w:1.487145; two:x:-0.207764;y:17.607371;z:0.050003;_x:0;_y:0;_z:0;_w:1.483080; three:x:2.467109;y:9.938154;z:0.050002;_x:0;_y:0;_z:0;_w:-1.889479; 3.坐标系frame_id :map 结果评价: 1.脚本能否发送目标点 可以,但需要手动点2D Nav Goal 2.Turtlebot到达一个目标点后能否继续发送第二个目标点 可以 注:也可以不用Turtlebot,使用nav _sim包的小车或者racecar的minicar。
    2023-04-17
    0 0 1336
易百纳技术社区
共3条
易百纳技术社区