Jetson Nano之ROS入门 -- YOLO目标检测与定位

文章目录

  • 前言
  • 一、yolo板端部署推理
  • 二、目标深度测距
  • 三、目标方位解算与导航点设定
    • 1、相机成像原理
    • 2、Python实现目标定位
  • 总结


前言

在这里插入图片描述

Darknet_ros是一个基于ROS(机器人操作系统)的开源深度学习框架,它使用YOLO算法进行目标检测和识别。YOLO算法是一种实时物体检测算法,它能够在单个前向传递中同时检测图像中的多个目标。

Darknet_ros将YOLO算法集成到ROS中,使得机器人可以实时地检测和识别周围环境中的物体。它提供了一些ROS节点和服务,可以在ROS系统中轻松使用YOLO算法进行目标检测和识别。同时,它还提供了一些示例程序,帮助用户快速了解如何在ROS中使用深度学习算法进行机器人视觉任务。

Darknet_ros的优点是速度快、准确度高,可以在实时应用中使用。它还可以在不同的机器人项目中使用,例如无人机、机器人车辆和机器人臂等。


一、yolo板端部署推理

首先确认CUDA,OpenCV,cuDNN已安装,可以用命令查看CUDA是否安装

ls -l /usr/local | grep cuda

查看opencv版本

opencv_version

接着从gitee上克隆darknet_ros源码下来

git clone https://gitee.com/bluesky_ryan/darknet_ros.git

按照如下指引下载权重文件,将下载的weights权重文件放在
darknet_ros/darknet_ros/yolo_network_config/weights

cd catkin_workspace/src/darknet_ros/darknet_ros/yolo_network_config/weights/COCO data set (Yolo v2):wget http://pjreddie.com/media/files/yolov2.weightswget http://pjreddie.com/media/files/yolov2-tiny.weightsVOC data set (Yolo v2):wget http://pjreddie.com/media/files/yolov2-voc.weightswget http://pjreddie.com/media/files/yolov2-tiny-voc.weightsYolo v3:wget http://pjreddie.com/media/files/yolov3.weightswget http://pjreddie.com/media/files/yolov3-voc.weights

使用jetson nano自带的opencv4.x编译会报错,需要安装opencv3.4.2版本,配置opencv cmake桥接目录

sudo vim /opt/ros/melodic/share/cv_bridge/cmake/cv_bridgeConfig.cmake 

在这里插入图片描述

接着cd到工作空间下,编译darknet_ros功能包

catkin_make -DCATKIN_WHITELIST_PACKAGES="darknet_ros"

配置launch文件图像输入的topic,可以打开摄像头节点后用rostopic命令查看

rostopic list

我的RGB图像发布的话题是/camera/rgb/image_raw,接着配置yolo网络参数,我用的是yolov2-tiny权重文件,检查一下ros.yaml文件也要配置成/camera/rgb/image_raw
在这里插入图片描述
打开终端,source一下工作空间下ros的环境变量

source /catkin_ws/devel/setup.bash

首先启动相机节点,需要有/camera/rgb/image_raw的话题输出,再运行darknet_ros 节点

roslaunch darknet_ros darknet_ros.launch

接着会弹出一个窗口,展示识别到的物体
在这里插入图片描述

二、目标深度测距

目标的深度测距的实现我们可以结合darknet_ros功能包,我这里用的是RGBD相机,型号是Astra_Pro,深度相机节点在启动后会输出深度图的话题

rostopic list/camera/depth/image_rect_raw

查看一下darknet_ros功能包的msg消息文件,下面是BoundingBoxes.msg消息文件

Header header
Header image_header
BoundingBox[] bounding_boxes

下面是BoundingBox.msg消息文件

float64 probability
int64 xmin
int64 ymin
int64 xmax
int64 ymax
int16 id
string Class

用rostopic info命令可以看到/darknet_ros/bounding_boxes话题的具体内容

rostopic info /darknet_ros/bounding_boxesType: darknet_ros_msgs/BoundingBoxesPublishers: * /darknet_ros (http://localhost:43545/)

这个话题就是我们需要的目标检测框的信息,将目标检测框输出到深度图我们就可以读取目标的深度

首先创建一个scripts文件夹,创建ObjectLocation.py文件

touch ObjectLocation.py

目标深度测距的代码思路首先导入rospy、cv2、numpy、darknet_ros_msgs等包,创建一个目标定位的类,实例化类的一些参数,订阅深度图话题并转化为深度矩阵,订阅目标检测框将坐标信息对齐到深度图中,按照3x3滑动窗口遍历检测框进行中值滤波,最后取中心深度作为目标的估计深度,并发布距离话题

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
from darknet_ros_msgs.msg import BoundingBoxes 
import numpy as np
from scipy.ndimage import median_filter
import mathclass ObjectLocation:def __init__(self):self.bridge = CvBridge()self.depth_image = Noneself.bounding_boxes = Noneself.probability = 0self.Class = Noneself.distance = 0self.centerx = 0self.centery = 0self.x_h = 0self.y_h = 0self.w_h = 0cv2.destroyAllWindows()'''get depth distance from found object rect'''def depthDistanceFromCoordinate(self, data):try:self.depth_image = self.bridge.imgmsg_to_cv2(data, "passthrough")depth_array = np.array(self.depth_image, dtype=np.float32)filter_depth_array = np.zeros_like(depth_array)if self.bounding_boxes != None:for bounding_box in self.bounding_boxes:# bounding box coordinates # less than 0 and larger than width or heightxmin = 0 if bounding_box.xmin < 0 else bounding_box.xminxmax = bounding_box.xmax if bounding_box.xmax < len(depth_array[0]) else len(depth_array[0])ymin = 0 if bounding_box.ymin < 0 else bounding_box.yminymax = bounding_box.ymax if bounding_box.ymax < len(depth_array) else len(depth_array)dep_aver = 0filter_depth_array = median_filter(depth_array, size=(3, 3))dep_aver = filter_depth_array[int((ymin + ymax) / 2), int((xmin + xmax) / 2)]self.probability = bounding_box.probabilityself.Class = bounding_box.Classself.distance = dep_averself.centerx =  (xmin + xmax) / 2self.centery =  (ymin + ymax) / 2rospy.loginfo("Class=%s, Probability=%f, Distance=%f", self.Class, self.probability, self.distance)pub = rospy.Publisher('/darknet_ros/distance', self.distance, queue_size = 100)pub.publish(self.distance)except Exception as e:print(e)def bbox_callback(self, msg):self.bounding_boxes = msg.bounding_boxesif __name__ == '__main__':od = ObjectLocation()rospy.init_node('ObjectLocation', anonymous=True)rospy.Subscriber('/darknet_ros/bounding_boxes', BoundingBoxes, od.bbox_callback)rospy.Subscriber('/camera/depth/image_rect_raw', Image, od.depthDistanceFromCoordinate)rate = rospy.Rate(10)rate.sleep()rospy.spin()

三、目标方位解算与导航点设定

1、相机成像原理

我们需要根据相机内外参去解算目标的方位,相机内参外参原理参照下面链接,依据成像原理我们可以将在像素坐标系下的目标映射到相机坐标系
https://zhuanlan.zhihu.com/p/389653208

2、Python实现目标定位

运行标定相机的demo就可以得到相机的内参外参矩阵,我的是出厂就标定好的附带内参矩阵,放在
home/wheeltec/.ros/camera_info/camera.yaml 文件里,内参矩阵是相机出厂时就决定了的

image_width: 640
image_height: 480
camera_name: camera
camera_matrix:rows: 3cols: 3data: [ 581.88585,    0.     ,  314.2472 ,0.     ,  592.27138,  210.27091,0.     ,    0.     ,    1.     ]
camera_model: plumb_bob
distortion_model: plumb_bob
distortion_coefficients:rows: 1cols: 5data: [0.221666, -0.575455, -0.014215, 0.003895, 0.000000]
rectification_matrix:rows: 3cols: 3data: [ 1.,  0.,  0.,0.,  1.,  0.,0.,  0.,  1.]
projection_matrix:rows: 3cols: 4data: [ 591.88599,    0.     ,  315.96148,    0.     ,0.     ,  603.39893,  205.72873,    0.     ,0.     ,    0.     ,    1.     ,    0.     ]

相机的外参矩阵则要确定机器人坐标系下的相机位姿,才能将目标方位解算到机器人bse_link坐标系下。用Python程序设定导航目标点的主要通过ROS中名为"move_base"的动作服务器(Action Server),负责接收和处理导航目标,我们将导航目标点位姿信息解算好,发送到move_base节点即可。

在原有的ObjectLocation.py上导入actionlib、tf、move_base_msgs等包,使用矩阵求逆加内积来将像素坐标系下的目标位置映射到相机坐标系,再通过tf坐标变换映射到机器人坐标系,实例化导航目标点,将目标点位姿发送到move_base节点,等待动作服务器响应即可

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
from darknet_ros_msgs.msg import  BoundingBoxes 
import numpy as np
from scipy.ndimage import median_filter
import actionlib
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal 
import tf.transformations as tr
import mathclass ObjectLocation:def __init__(self):self.bridge = CvBridge()self.depth_image = Noneself.bounding_boxes = Noneself.probability = 0self.Class = Noneself.distance = 0self.centerx = 0self.centery = 0self.x_h = 0self.y_h = 0self.w_h = 0cv2.destroyAllWindows()'''get depth distance from found object rect'''def depthDistanceFromCoordinate(self, data):try:self.depth_image = self.bridge.imgmsg_to_cv2(data, "passthrough")depth_array = np.array(self.depth_image, dtype=np.float32)filter_depth_array = np.zeros_like(depth_array)if self.bounding_boxes != None:for bounding_box in self.bounding_boxes:# bounding box coordinates # less than 0 and larger than width or heightxmin = 0 if bounding_box.xmin < 0 else bounding_box.xminxmax = bounding_box.xmax if bounding_box.xmax < len(depth_array[0]) else len(depth_array[0])ymin = 0 if bounding_box.ymin < 0 else bounding_box.yminymax = bounding_box.ymax if bounding_box.ymax < len(depth_array) else len(depth_array)dep_aver = 0filter_depth_array = median_filter(depth_array, size=(3, 3))dep_aver = filter_depth_array[int((ymin + ymax) / 2), int((xmin + xmax) / 2)]self.probability = bounding_box.probabilityself.Class = bounding_box.Classself.distance = dep_averself.centerx =  (xmin + xmax) / 2self.centery =  (ymin + ymax) / 2rospy.loginfo("Class=%s, Probability=%f, Distance=%f", self.Class, self.probability, self.distance)if self.Class == "pottedplant":fx = 581.88585fy = 592.27138cx = 314.2472cy = 210.27091K = np.array([[fx, 0., cx], [0., fy, cy], [0., 0., 1.]])point_pixel = np.array([self.centerx, self.centery, 1])point_camera = np.dot(np.linalg.inv(K), point_pixel) * self.distanceself.y_h = - point_camera[0] - 460self.x_h = point_camera[2] + 110orientation = tr.quaternion_from_euler(0, 0, math.atan2(self.y_h, self.x_h))self.w_h = orientation[3]rospy.loginfo("%s Goal location is x_h = %f, y_h = %f, w_h=%f", "pottedplant", self.x_h, self.y_h, self.w_h)self.movebase_callback()pub = rospy.Publisher('/darknet_ros/distance', self.distance, queue_size = 100)pub.publish(self.distance)except Exception as e:print(e)def movebase_callback(self):try:client = actionlib.SimpleActionClient('move_base', MoveBaseAction)client.wait_for_server()goal = MoveBaseGoal()goal.target_pose.header.frame_id = "base_link"goal.target_pose.pose.position.x = self.x_h * 4 / 5000goal.target_pose.pose.position.y = self.y_h * 4 / 5000goal.target_pose.pose.orientation.w = self.w_hclient.send_goal(goal)rospy.loginfo("move_base set goal success!")client.wait_for_result()except Exception as e:print("movebase_callback service failed")def bbox_callback(self, msg):self.bounding_boxes = msg.bounding_boxesif __name__ == '__main__':od = ObjectLocation()rospy.init_node('ObjectLocation', anonymous=True)rospy.Subscriber('/darknet_ros/bounding_boxes', BoundingBoxes, od.bbox_callback)rospy.Subscriber('/camera/depth/image_rect_raw', Image, od.depthDistanceFromCoordinate)rate = rospy.Rate(10)rate.sleep()rospy.spin()

下面是演示结果,其实还可以用其他滤波方法让深度估计更加精确,用重采样方法让方位估计更加精准
在这里插入图片描述


总结

darknet_ros软件包将ROS和YOLO很好的融合在一起,为机器人视觉任务开发提供了更多可能性。通过实时目标检测和识别,机器人能够感知和理解环境,实现人机交互,提高安全性,并在各种应用中发挥更智能和自主的作用。通过实时目标检测和识别,可以帮助机器人识别不同类型的物体,并根据目标物体的位置和特征来理解当前场景。这对于机器人在导航、路径规划和任务执行中具有重要意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/16601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代理模式:控制访问的设计模式

代理模式&#xff1a;控制访问的设计模式 什么是代理模式&#xff1f; 代理模式是一种常见的设计模式&#xff0c;它允许通过代理对象来控制对真实对象的访问。代理模式的主要目的是在不改变原始对象的情况下&#xff0c;提供额外的功能或控制访问。 为什么要使用代理模式&a…

2023年Q2京东环境电器市场数据分析(京东数据产品)

今年Q2&#xff0c;环境电器市场中不少类目表现亮眼&#xff0c;尤其是以净水器、空气净化器、除湿机等为代表的环境健康电器。此外&#xff0c;像冷风扇这类具有强季节性特征的电器也呈现出比较好的增长态势。 接下来&#xff0c;结合具体数据我们一起来分析Q2环境电器市场中…

所有流的知识都有,IO流原理及流的分类

1、Java IO流原理 I/O是Input/Output的缩写&#xff0c; I/O技术是非常实用的技术&#xff0c;用于处理设备之间的数据传输。如读/写文件&#xff0c;网络通讯等。 Java程序中&#xff0c;对于数据的输入/输出操作以”流(stream)” 的方式进行。java.io包下提供了各种“流”类…

微信小程序监测版本更新

在index.js里面 不放到app.js里面是因为有登录页面&#xff0c;在登录页面显示更新不太友好 onShow() {const updateManager wx.getUpdateManager()// 请求完新版本信息的回调updateManager.onCheckForUpdate(res > {if (res.hasUpdate) {// 新版本下载成功updateManage…

【JavaEE初阶】Servlet (二) Servlet中常用的API

文章目录 HttpServlet核心方法 HttpServletRequest核心方法 HttpServletResponse核心方法 Servlet中常用的API有以下三个: HttpServletHttpServletRequestHttpServletResponse HttpServlet 我们写 Servlet 代码的时候, 首先第一步就是先创建类, 继承自 HttpServlet, 并重写其…

以科技创新引领短交通行业发展,九号公司重磅新品亮相巴塞罗那MWC

2月27日&#xff0c;以“时不我待(VELOCITY) - 明日科技&#xff0c;将至已至”为主题的2023世界移动通信大会&#xff08;Mobile World Congress&#xff0c;以下简称MWC&#xff09;在西班牙巴塞罗那举办&#xff0c;全球创新短交通领军企业九号公司参加了大会。现场&#xf…

2023年FPGA好就业吗?

FPGA岗位有哪些&#xff1f; 从芯片设计流程来看&#xff0c;FPGA岗位可以分四类 产品开发期&#xff1a;FPGA系统架构师 芯片设计期&#xff1a;数字IC设计工程师、FPGA开发工程师 芯片流片期&#xff1a;FPGA验证工程师 产品维护期&#xff1a;FAE工程师 从行业上来说&#x…

6、Kubernetes核心技术 - Pod

目录 一、概述 二、Pod机制 2.1、共享网络 2.2、共享存储 三、Pod资源清单 四、 Pod 的分类 五、Pod阶段 六、Pod 镜像拉取策略 ImagePullBackOff 七、Pod 资源限制 八、容器重启策略 一、概述 Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。P…

时序预测 | Python实现NARX-DNN空气质量预测

时序预测 | Python实现NARX-DNN空气质量预测 目录 时序预测 | Python实现NARX-DNN空气质量预测效果一览基本介绍研究内容程序设计参考资料效果一览 基本介绍 时序预测 | Python实现NARX-DNN空气质量预测 研究内容 Python实现NARX-DNN空气质量预测,使用深度神经网络对比利时空气…

基于51单片机和proteus的加热洗手器系统设计

此系统是基于51单片机和proteus的仿真设计&#xff0c;功能如下&#xff1a; 1. 检测到人手后开启出水及加热。 2. LED指示加热出水及系统运行状态。 功能框图如下&#xff1a; Proteus仿真界面如下&#xff1a; 下面就各个模块逐一介绍&#xff0c; 模拟人手检测模块 通过…

mysql 非definer用户如何查看存储过程定义

当我们创建存储过程时&#xff0c;如果没有显示指定definer&#xff0c;则会默认当前用户为该sp的definer&#xff0c;如果没有相关授权&#xff0c;则其他用户是看不了这个sp的。 比如用户zhenxi1拥有如下权限&#xff1a; 它拥有对dev_nacos库的查询权限&#xff0c;这个时候…

Xamarin.Android实现加载中的效果

目录 1、说明2、代码如下2.1 图1的代码2.1.1、创建一个Activity或者Fragment&#xff0c;如下&#xff1a;2.1.2、创建Layout2.1.3、如何使用 2.2 图2的代码 4、其他补充4.1 C#与Java中的匿名类4.2 、其他知识点 5、参考资料 1、说明 在实际使用过程中&#xff0c;常常会用到点…

【ChatGPT辅助学Rust | 基础系列 | 基础语法】变量,数据类型,运算符,控制流

文章目录 简介&#xff1a;一&#xff0c;变量1&#xff0c;变量的定义2&#xff0c;变量的可变性3&#xff0c;变量的隐藏 二、数据类型1&#xff0c;标量类型2&#xff0c;复合类型 三&#xff0c;运算符1&#xff0c;算术运算符2&#xff0c;比较运算符3&#xff0c;逻辑运算…

python_在K线找出波段_01_找出所有转折点

目录 写在前面&#xff1a; 需要考虑的几种K线图情况&#xff1a; 寻找所有转折点逻辑&#xff1a; 代码&#xff1a; 寻找转折点方法&#xff1a;找到第一个转折点就返回 循环寻找峰谷方法 主方法 调用计算&#xff1a; 返回&#xff1a; 在【PyQt5开发验证K线视觉想…

数字图像处理(番外)图像增强

图像增强 图像增强的方法是通过一定手段对原图像附加一些信息或变换数据&#xff0c;有选择地突出图像中感兴趣的特征或者抑制(掩盖)图像中某些不需要的特征&#xff0c;使图像与视觉响应特性相匹配。 图像对比度 图像对比度计算方式如下&#xff1a; C ∑ δ δ ( i , j …

7 网络通信(上)

文章目录 网络通信概述ip地址ip的作用ip地址的分类私有ip 掩码和广播地址 linux 命令&#xff08;ping ifconfig&#xff09;查看或配置网卡信息&#xff1a;ifconfig(widows 用ipconfig)测试远程主机连通性&#xff1a;ping路由查看 端口端口是怎样分配的知名端口动态端口 查看…

【数据结构与算法】基数排序

基数排序 基数排序&#xff08;Radix Sort&#xff09;属于“分配式排序”&#xff0c;又称“桶子法”或 bin sort&#xff0c;顾名思义&#xff0c;它是通过键值的各个位的值&#xff0c;将要排序的元素分配至某些“桶”中&#xff0c;达到排序的作用。基数排序法是属于稳定性…

【C++】开源:Boost网络库Asio配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Asio网络库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次…

信息安全战线左移!智能网联汽车安全亟需“治未病”

当汽车由典型的工业机械产品逐步发展成为全新的智能移动终端&#xff0c;汽车的安全边界发生了根本性改变&#xff0c;信息安全风险和挑战不断增加。 面对复杂的异构网络、异构系统及车规级特异性要求&#xff0c;智能智能网联汽车信息安全到底要如何防护&#xff0c;已经成为…

八大排序算法--选择排序(动图理解)

选择排序 算法思路 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 选择排序的步骤&#xff1a; 1>首先在未排序序列中找到最小&#xff08;大&#xff09;元素…