感知笔记3:平面和物体检测

  • 识别平面表面:这项技能使机器人能够检测物体通常所在的位置,如桌子和架子。这是搜索物体的第一步。
  • 识别物体:一旦您知道在哪里寻找,就必须在场景中识别不同的物体,并根据机器人的位置(坐标系)定位它们。

3.1 环境介绍

您将使用以下环境:

  • PR2 机器人:它是一种多功能机器人,可以全向移动,有两只手臂和一个可移动的躯干。它还配有激光器和点云相机。它是物体识别和操控的完美候选者。
  • 桌子上的物体选择:您会在桌子上找到几个物体。它们是为了在检测中提供多样性。物体中有一把枪,因为我们想解释如何检测有武装人员的危险情况。

您可以使用以下列出的键盘遥控和关节命令移动PR2机器人。

roslaunch pr2_tc_teleop keyboard_teleop.launch

使用Q键将速度增加到大约8.0,以查看PR2机器人移动。

点击图形界面图标,打开图形工具,通过简单的GUI移动PR2机器人的关节:

您应该看到与下图类似的图像:

选择 head_joint_controller以移动头部的俯仰和倾斜。这将有助于检查您的物体检测是否正常工作。

3.2 平面检测器

识别物体的第一步是知道这些物体的位置。您将使用 surface_perception 包来检测平面并在RViz中表示检测结果。surface_perception包还可以检测平面上的物体。这是一个优秀的ROS包,制作精良,考虑到它自ROS-indigo以来就没有更新过,并且它在ROS-Noetic中工作。

第一步是创建一个对象识别包:

bash 复制代码
cd /home/user/catkin_ws/src
catkin_create_pkg my_object_recognition_pkg rospy
cd my_object_recognition
mkdir launch
touch launch/surface_detection.launch
cd /home/user/catkin_ws
catkin_make
source devel/setup.bash
rospack profile
surface_detection.launch
bash 复制代码
<?xml version="1.0"?>
<launch>
    <node name="surface_perception_node" pkg="surface_perception" type="demo" output="screen" args="base_link">
        <remap from="cloud_in" to="/camera/depth_registered/points"/>
    </node>
</launch>

此二进制文件需要两个元素才能工作:

  • 输入我们将以此为基础进行检测的 Tf 坐标框架。在这种情况下,base_link 就足够了。
  • cloud_in 重新映射到您的机器人从深度传感器发布点云的主题。在我们的例子中,这是 /camera/depth_registered/points

让我们启动表面检测包并看看会发生什么:

bash 复制代码
roslaunch my_object_recognition_pkg surface_detection.launch

您现在应该看到类似下图的图像:

如果您没有看到标记,请确保在 RViz 面板中看到指向主题 /surface_objects 的元素类型标记:

您可以看到,仅使用此系统,您就可以获得:

  • 标记代表您的机器人检测到的不同水平表面。它们以紫色标记表示。
  • 标记代表检测到的物体。它们以绿色标记表示。

练习 3.2.1

  • 创建一个名为surface_data_extraction.py 的Python脚本,该脚本提取由surface_detection.launch生成的标记数据,并仅过滤与桌子高度相对应的水平表面物体。
  • 桌子高度约为0.8米,因此您应该过滤该高度周围的表面物体。
  • 您可以将表面与物体区分开来,因为它们的名称是surface_X ,而物体是surface_X_object_Y_axes

稍后,可以使用这些数据仅在该空间区域周围查找物体并用于抓取。

请记住使Python脚本可执行;否则,ROS将无法执行它:

bash 复制代码
chmod +x surface_data_extraction.py
my_object_recognition_pkg/scripts/surface_data_extraction.py
bash 复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
import numpy

from visualization_msgs.msg import Marker

class SurfaceObjectFilter:

   def __init__(self, table_height_init=0.8, error_height=0.2):

      self._rate = rospy.Rate(5)

      self.table_height = table_height_init
      self._error_height = error_height
      self.surface_dict = {}
      self.surface_topic = "/surface_objects"
      self._check_surface_ready()
      rospy.Subscriber(self.surface_topic, Marker, self.surface_callback)
     
      rospy.loginfo('Ready to detect Surfaces!')

   def _check_surface_ready(self):
      self._surface_data = None
      while self._surface_data is None and not rospy.is_shutdown():
         try:
               self._surface_data = rospy.wait_for_message(self.surface_topic, Marker, timeout=1.0)
               rospy.logdebug("Current "+self.surface_topic+" READY=>" + str(self._surface_data))

         except:
               rospy.logerr("Current "+self.surface_topic+" not ready yet, retrying.")

   def update_table_height(self,new_table_height):
      self.table_height = new_table_height

   def look_for_table_surface(self, z_value):
      """

      """
      delta_min = z_value - self._error_height
      delta_max = z_value + self._error_height
      is_the_table = delta_min < self.table_height < delta_max

      return is_the_table

   def surface_callback(self, msg):

      name = msg.ns
      surface_pose = msg.pose

      if "surface_" in name and not "_axes" in name:
         # We check the heigh in z to see if its the table
         if self.look_for_table_surface(msg.pose.position.z):
            if name in self.surface_dict:
               rospy.loginfo("This surface was alreday found")
            else:
               self.surface_dict[name] = surface_pose
               rospy.loginfo("Found New Surface=")
      else:
         rospy.logdebug("Surface Object Not found "+str(name))


   def get_surface_dict_detected(self):
      return self.surface_dict

   def run(self):


      while not rospy.is_shutdown():
         table_surfaces_detected = self.get_surface_dict_detected()
         rospy.loginfo(str(table_surfaces_detected))
         self._rate.sleep()



if __name__ == '__main__':
   rospy.init_node('surface_data_extract_node', log_level=rospy.INFO)

   try:
      SurfaceObjectFilter().run()
   except KeyboardInterrupt:
      rospy.loginfo('Shutting down')
bash 复制代码
   def update_table_height(self,new_table_height):
      self.table_height = new_table_height
    
    
    ...
    
    def look_for_table_surface(self, z_value):
      """

      """
      delta_min = z_value - self._error_height
      delta_max = z_value + self._error_height
      is_the_table = delta_min < self.table_height < delta_max

      return is_the_table

我们如何检查一个检测是否是桌子。我们在 self.table_height 中设置了一个特定的高度值,通过 update_table_height 更新,然后确认通过 look_for_table_surface 得到的 z_value 大致等于更新后的高度。

通过同时启动表面检测和 surface_data_extraction.py,您应该只获得桌子的检测结果。

bash 复制代码
cd /home/user/catkin_ws
source devel/setup.bash
rospack profile
# Now launch
roslaunch my_object_recognition_pkg surface_detection.launch
bash 复制代码
cd /home/user/catkin_ws
source devel/setup.bash
rospack profile
# Now launch
rosrun my_object_recognition_pkg surface_data_extraction.py

当系统检测到给定高度周围的表面时,您应该得到类似于以下输出的输出:

bash 复制代码
[INFO] [1615891002.402422, 276.540000]: {'surface_1': position:
  x: 1.5979965925216675
  y: 1.1848139762878418
  z: 0.9700260162353516
orientation:
  x: 0.0
  y: 0.0
  z: 0.008941666223108768
  w: 0.9999600648880005}

3.3 物体检测:扩展物体检测

MoscowskyAnton 创建了这个扩展物体检测系统。该包试图将所有基本的物体和人类识别算法整合到一个统一、全面的结构中,以支持嵌套检测。

它有出色的文档,您可以在Wiki上查看。

您可以做的事情包括:

  • 检测斑点
  • 使用 Haar 特征级联
  • 使用 TensorFlow
  • QR 码跟踪
  • 特征匹配
  • 基本运动检测
  • 还有更多。在这一单元中,我们提供了多个示例,并解释如何将它们组合以创建您自己的检测器。

物体检测:简单/复杂物体检测

该系统的主要思想是使用 .xml 文件来定义您将用于检测物体的不同属性。然后,您将这些属性组合起来以检测特定的简单物体。让我们看看在这一单元中将使用的示例:

bash 复制代码
roscd my_object_recognition_pkg
mkdir -p config/object_base_example
roscd my_object_recognition_pkg/config/object_base_example
touch Simple_Gun.xml
Simple_Gun.xml
bash 复制代码
<?xml version="1.0" ?>

<AttributeLib>
    <Attribute Name="HistColorPortalGun" Type="HistColor" Histogram="histograms/PortalGun.yaml"/>
    <Attribute Name="PotalGunSize" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>
    <Attribute Name="NotFractal" Type="Size" MinAreaPc="0.5" MaxAreaPc="100"/>
    
    <Attribute Name="HSVColorBlackGun" Type="HSVColor" Hmin="0" Hmax="0" Smin="0" Smax="0" Vmin="31" Vmax="161"/>
    <Attribute Name="HaarGun" Type="HaarCascade" Cascade="gun_haar/classifier/cascade.xml"/>
    <Attribute Name="MyBlobAttribute" Type="Blob" minThreshold="54" maxThreshold="125" blobColor="0" minArea="1500" minCircularity="0.03" minConvexity="0.64" minInertiaRatio="0.00"/>

</AttributeLib>

<SimpleObjectBase>  
      
    <SimpleObject Name="PortalGun" ID="1">              
        <Attribute Type="Detect">HistColorPortalGun</Attribute>  
        <Attribute Type="Check">PotalGunSize</Attribute>  
        <Attribute Type="Check">NotFractal</Attribute> 
    </SimpleObject>    

    <SimpleObject Name="BlackGun" ID="2">              
        <Attribute Type="Detect">HSVColorBlackGun</Attribute> 
        <Attribute Type="Check">NotFractal</Attribute>
    </SimpleObject>

    <SimpleObject Name="HaarBlackGun" ID="3" Mode="Hard" MergingPolicy="Union">              
        <Attribute Type="Detect">HaarGun</Attribute>
        <Attribute Type="Detect">MyBlobAttribute</Attribute> 
    </SimpleObject>  

</SimpleObjectBase>


<RelationLib>    

    
    
</RelationLib>


<ComplexObjectBase>
    
    
</ComplexObjectBase>

这些 XML 文件有三个主要部分:

  • Attributes :在这里,我们定义每个检测器。在这个例子中,我们定义:
    • HistColorPortalGun:我们使用颜色直方图(我们将学习如何生成)来追踪特定的颜色轮廓(类似于斑点)。
    • PortalGunSize:类型为大小检查,物体的面积大于(MinAreaPc 图像面积)且小于(MaxAreaPc 图像面积)。
    • NotFractal:这是为了避免检测到非常小或非常大的斑点。
    • HSVColorBlackGun:在这里,我们不是通过直方图,而是通过基本颜色进行检测。
    • HaarGun:我们通过 Haar 特征级联进行检测,在这种情况下,检测枪的形态是通过 HaarGunGit 完成的。
    • MyBlobAttribute:这是一个黑白斑点检测器。有关斑点检测器的更多信息,请参见 BlobDocs。
  • Simple objects:在这里,我们定义我们想要检测的主要物体,使用哪些属性,以及如何将它们组合。这是通过模式(hard, soft)来完成的。基本上是设置 AND 或 OR 条件,如果某个属性检测到东西。还有合并策略 DOCS。这定义了属性的边界框是否合并为最大的边界框、所有框的联合,或任何其他组合。
  • Relation.lib and complex objects:这两个标签是一起使用的,因为它们定义了复杂物体的检测和构建方式。复杂物体不超过两个或更多简单物体的组合,并具有某种空间关系,例如检测一个物体在另一个物体内部或相邻特定距离。在这种情况下,我们没有定义任何。

简单物体:Portal Gun

我们使用 HistColorPortalGunNotFractal 。它的工作原理是,HistColorPortalGun 设置为检测类型;因此,我们将图像数据输入给它。如果它检测到某物,我们就通过 NotFractal 检查。如果没有发现任何分形,则检测有效。否则,就是无效的。

在下一部分中,我们将看到如何生成所有这些,但这里有一个例子,展示我们将使用颜色直方图生成的两个物体。您会看到,这作为物体的指纹非常有用。正如您所见,这两个物体具有非常独特的直方图,这使得它们的检测变得容易得多。

这些图是每个对象的颜色直方图。请注意,这是对象最具标志性的区域的直方图。如果我们要为整个对象创建图像的直方图,它们将非常相似,因为白色在两个图像中占主导地位。这些是输入到直方图生成器的图像:

创建直方图

我们将使用您可以在扩展对象检测包中找到的工具。

bash 复制代码
roscd my_object_recognition_pkg/config/object_base_example
mkdir histograms
# And now we create histogram generator launch:
roscd my_object_recognition_pkg
touch launch/hist_color_params_collector_point.launch

hist_color_params_collector_point.launch

bash 复制代码
<launch>
    <arg name="output" value="screen"/>
    <arg name="hist_name" default="PortalGun"/>
    <arg name="hist_path" default="$(find my_object_recognition_pkg)/config/object_base_example/histograms/$(arg hist_name).yaml"/>
      
    <node name="hist_color_params_collector_point_node" pkg="extended_object_detection" type="hist_color_params_collector_point_node" output="screen" required="true">        
        <param name="out_filename" value="$(arg hist_path)"/>
        <remap from="image_raw" to="/camera/rgb/image_raw"/>                
    </node>
          
    
</launch>

这些是您必须根据机器人和物体更改的变量:

  • hist_name:您将生成的直方图文件的名称。
  • hist_path:您希望程序保存直方图文件的位置。
  • /camera/rgb/image_raw:这是 RGB 相机图像主题。根据您的机器人,这可能会改变。

现在让我们启动它并生成传送枪的直方图文件。

首先,使用 PR2 机器人尽可能靠近桌子和物体。使用键盘命令,将机器人移近桌子并降低机器人的头部以更好地查看物体。

要让它移动,线速度必须至少为 10.0。所以如果它不动,不要惊慌。只需按 Q 直到线速度达到 10.0 左右即可

bash 复制代码
roslaunch pr2_tc_teleop keyboard_teleop.launch

左键单击对象上最具代表性的颜色。在本例中,我们单击的是灰色支架。

看到它生成了有意义的轮廓后,无需移动相机,右键单击图像。这将修复值并开始根据直方图值进行检测。当它变成绿色时,您就知道它起作用了,类似于下面的图片:

别担心大小或 thesh 值。它们在这里不使用。

如果一切顺利,当您在图形工具中按下 ESC 键时,选择 histogram point creator GUI 窗口,它应该会生成 PortalGun.yaml 文件并输出这两行。

这里告诉您在 SimpleObject.xml 文件中作为属性放置的内容,用于通过直方图检测 PortalGun。

bash 复制代码
<Attribute Name="MyHistColorAttribute" Type="HistColor" Histogram="/home/user/catkin_ws/src/perception_course_solutions/perception_unit3_solutions/my_object_recognition_pkg/config/object_base_example/histograms/PortalGun.yaml"/>
<Attribute Name="MySizeAttribute" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>

现在,让我们使用 Simple_Gun.xml 文件来测试它是否有效。

我们需要检查 Simple_Gun.xml 中是否设置了 PortalGun Histogram 的正确路径。路径可以是:

  • 相对路径:相对于您保存 Simple_Gun.xml 的路径。因此,在这种情况下为 histograms/PortalGun.yaml
  • 绝对路径:/home/user/catkin_ws/src/my_object_recognition_pkg/config/object_base_example/histograms/PortalGun.yaml

相对路径通常看起来更简洁,所以我们使用相对路径。

我们还将把属性的名称更改为 HistColorPortalGun

并且我们还将把大小属性的名称更改为 PortalGunSize

最终的内容应类似于以下示例:

Simple_Gun.xml
XML 复制代码
<?xml version="1.0" ?>

<AttributeLib>
    <Attribute Name="HistColorPortalGun" Type="HistColor" Histogram="histograms/PortalGun.yaml"/>
    <Attribute Name="PotalGunSize" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>
    <Attribute Name="NotFractal" Type="Size" MinAreaPc="0.5" MaxAreaPc="100"/>
    
    <Attribute Name="HSVColorBlackGun" Type="HSVColor" Hmin="0" Hmax="0" Smin="0" Smax="0" Vmin="31" Vmax="161"/>
    <Attribute Name="HaarGun" Type="HaarCascade" Cascade="gun_haar/classifier/cascade.xml"/>
    <Attribute Name="MyBlobAttribute" Type="Blob" minThreshold="54" maxThreshold="125" blobColor="0" minArea="1500" minCircularity="0.03" minConvexity="0.64" minInertiaRatio="0.00"/>

</AttributeLib>

<SimpleObjectBase>  
      
    <SimpleObject Name="PortalGun" ID="1">              
        <Attribute Type="Detect">HistColorPortalGun</Attribute>  
        <Attribute Type="Check">PotalGunSize</Attribute>  
        <Attribute Type="Check">NotFractal</Attribute> 
    </SimpleObject>    

    <SimpleObject Name="BlackGun" ID="2">              
        <Attribute Type="Detect">HSVColorBlackGun</Attribute> 
        <Attribute Type="Check">NotFractal</Attribute>
    </SimpleObject>

    <SimpleObject Name="HaarBlackGun" ID="3" Mode="Hard" MergingPolicy="Union">              
        <Attribute Type="Detect">HaarGun</Attribute>
        <Attribute Type="Detect">MyBlobAttribute</Attribute> 
    </SimpleObject>  

</SimpleObjectBase>


<RelationLib>    

    
    
</RelationLib>


<ComplexObjectBase>
    
    
</ComplexObjectBase>

我们创建启动器来使用 Simple_Gun.xml

XML 复制代码
roscd my_object_recognition_pkg
touch launch/gun_detection.launch

gun_detection.launch

XML 复制代码
<launch>
    <arg name="output" default="screen"/>
    <arg name="objectBasePath" default="$(find my_object_recognition_pkg)/config/object_base_example/Simple_Gun.xml"/>
    
    <node name="extended_object_detection" pkg="extended_object_detection" type="extended_object_detection_node" output="screen">
        
        <param name="objectBasePath" value="$(arg objectBasePath)"/>
        <param name="videoProcessUpdateRate" value="5"/>
        <param name="screenOutput" value="false"/>
        <param name="publishImage" value="true"/>
        <param name="publishMarkers" value="true"/>
        <param name="subscribeDepth" value="false"/>        
        <param name="maxContourPoints" value="-1"/>        
        
        <rosparam param="selectedOnStartSimple">[1]</rosparam>
        <rosparam param="selectedOnStartComplex">[-1]</rosparam>
        
    </node>        
    
</launch>

对 gun_detection-launch 文件中几个值得注意的元素的注释:

XML 复制代码
<arg name="objectBasePath" default="$(find my_object_recognition_pkg)/config/object_base_example/Simple_Gun.xml"/>

这里我们指出了 Simple_Gun.xml 文件,我们将在其中定义所有简单对象和属性。

XML 复制代码
<rosparam param="selectedOnStartSimple">[1]</rosparam>
<rosparam param="selectedOnStartComplex">[-1]</rosparam>

在这里,我们设置了将在检测中激活和搜索的简单物体和复杂物体。

  • []:如果数组中没有放置任何内容,则所有简单或复杂物体将被激活。
  • [1,4,...,25]:每个数字表示简单或复杂物体的 ID。例如,如果我们只放置 [1],这意味着只有 ID=1 的简单物体会被激活,此时是 PortalGun。[-1]:表示不会激活任何物体。

启动它并查看 RViz:

XML 复制代码
roslaunch my_object_recognition_pkg gun_detection.launch

点击图形界面图标以查看直方图 GUI 生成器。如果您的 RViz 界面与所示的不一样,您可以在本单元的解决方案中查看 RViz 配置文件,路径为 my_object_recognition_pkg/rviz/object_recognition.rviz

练习 3.3.1

  • 根据我们用于 PortalGun 的相同步骤,为香蕉创建直方图检测器。
  • 将修改添加到 Simple_Gun.xml 和 gun_detector.launch 以检测香蕉和 PortalGun。
  • 注意:由于香蕉的形状,您可能需要删除分形属性。
Simple_Gun.xml
XML 复制代码
<?xml version="1.0" ?>

<AttributeLib>
    <Attribute Name="HistColorPortalGun" Type="HistColor" Histogram="histograms/PortalGun.yaml"/>
    <Attribute Name="PotalGunSize" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>
    <Attribute Name="NotFractal" Type="Size" MinAreaPc="0.5" MaxAreaPc="100"/>

    <Attribute Name="HistColorBanana" Type="HistColor" Histogram="histograms/Banana.yaml"/>
    <Attribute Name="BananaSize" Type="Size" MinAreaPc="0.05" MaxAreaPc="100"/>
    
    <Attribute Name="HSVColorBlackGun" Type="HSVColor" Hmin="0" Hmax="0" Smin="0" Smax="0" Vmin="22" Vmax="61"/>
    
    <Attribute Name="HaarGun" Type="HaarCascade" Cascade="gun_haar/classifier/cascade.xml"/>
    <Attribute Name="MyBlobAttribute" Type="Blob" minThreshold="54" maxThreshold="125" blobColor="0" minArea="1500" minCircularity="0.03" minConvexity="0.64" minInertiaRatio="0.00"/>

</AttributeLib>

<SimpleObjectBase>  
      
    <SimpleObject Name="PortalGun" ID="1">              
        <Attribute Type="Detect">HistColorPortalGun</Attribute>  
        <Attribute Type="Check">PotalGunSize</Attribute>  
        <Attribute Type="Check">NotFractal</Attribute> 
    </SimpleObject>

    <SimpleObject Name="Banana" ID="2">              
        <Attribute Type="Detect">HistColorBanana</Attribute>  
        <Attribute Type="Check">BananaSize</Attribute>  
         
    </SimpleObject>    

    <SimpleObject Name="BlackGun" ID="3">              
        <Attribute Type="Detect">HSVColorBlackGun</Attribute> 
        <Attribute Type="Check">NotFractal</Attribute>
    </SimpleObject>

    <SimpleObject Name="HaarBlackGun" ID="4" Mode="Hard" MergingPolicy="Union">              
        <Attribute Type="Detect">HaarGun</Attribute>
        <Attribute Type="Detect">MyBlobAttribute</Attribute> 
    </SimpleObject>  

</SimpleObjectBase>


<RelationLib>    

    
    
</RelationLib>


<ComplexObjectBase>

gun_detection.launch

XML 复制代码
<launch>
    <arg name="output" default="screen"/>
    <arg name="objectBasePath" default="$(find my_object_recognition_pkg)/config/object_base_example/Simple_Gun.xml"/>
    
    <node name="extended_object_detection" pkg="extended_object_detection" type="extended_object_detection_node" output="screen">
        
        <param name="objectBasePath" value="$(arg objectBasePath)"/>
        <param name="videoProcessUpdateRate" value="5"/>
        <param name="screenOutput" value="false"/>
        <param name="publishImage" value="true"/>
        <param name="publishMarkers" value="true"/>
        <param name="subscribeDepth" value="false"/>        
        <param name="maxContourPoints" value="-1"/>        
        
        <rosparam param="selectedOnStartSimple">[1,2]</rosparam>
        <rosparam param="selectedOnStartComplex">[-1]</rosparam>
        
    </node>        
    
</launch>

一些解决方案的注意事项:

  • 如您所见,NotFractal属性未被使用。这是因为在香蕉上用直方图检测到的部分太小,因而被视为分形,无法检测。
  • 但是,如果您移除分形属性,您将获得过多的检测结果。这是因为每个与直方图对应的小区域都被视为一个检测。因此,我们必须调整大小。
  • 将最小大小设置为 MinAreaPc=0.05 后,我们只考虑大于该值的有效检测区域,从而清理检测结果,只保留一到两个。
  • 以下是带有分形属性的结果:
  • 请参见以下未调整分形和尺寸的结果:
bash 复制代码
# This variable set is because of current Accademy system being remote. Localy you wouldn't need to do it.
QT_X11_NO_MITSHM=1
echo $QT_X11_NO_MITSHM
roslaunch my_object_recognition_pkg hist_color_params_collector_point_banana.launch
bash 复制代码
roslaunch my_object_recognition_pkg gun_detection.launch

简单对象:黑色枪

它的工作原理与上一个练习相同,但使用 HSVColorBlackGun 属性。

创建 HSV 检测

我们将使用您可以在扩展对象检测包中找到的工具。

bash 复制代码
# We create a HSV sampler launch:
roscd my_object_recognition_pkg
touch launch/hsv_color_params_collector.launch

hsv_color_params_collector.launch

bash 复制代码
<launch>
    <arg name="output" value="screen"/>
    
    <node name="hsv_color_params_collector_node" pkg="extended_object_detection" type="hsv_color_params_collector_node" output="screen" required="true" >                
        <remap from="image_raw" to="/camera/rgb/image_raw"/>                 
    </node>
          
    
</launch>

启动launch文件获取HSV的值:

bash 复制代码
# This variable set is because of current Accademy system being remote. Localy you wouldn't need to do it.
QT_X11_NO_MITSHM=1
echo $QT_X11_NO_MITSHM
roslaunch my_object_recognition_pkg hsv_color_params_collector.launch

如您所见,如果我们仅调整 HSV 值,它将检测到所有具有黑色枪的点。不仅在枪中,而且在瓶子或甜甜圈的阴影中。

为了初步了解 HSV 的值,我们建议您使用基于 Web 的颜色选择器,例如 ColorZilla 或任何允许您获取图像的 HSV 值的浏览器插件,然后选择此笔记本中显示枪的图像(例如,上面几行)。

再次,我们将使用 size 属性来检测明显较大的区域以避免这种情况。

但这并不能解决巨大的暗区(如桌子的侧面)也会被检测为枪的问题。为了解决这个问题,我们还必须限制最大尺寸。但这必须在 Simple_Gun.xml 属性定义中完成。

一旦您获得了满意的值,请在 GUI 处于焦点状态时按下键盘上的 ESC 键,启动将终止,并输出您需要添加到 Simple_Gun.xml 的属性,以使用 HSV 检测枪。

bash 复制代码
[ WARN] [1615908901.726154378, 4258.786000000]: YOUR ATTRIBUTES
<Attribute Name="MyHSVColorAttribute" Type="HSVColor" Hmin="0" Hmax="0" Smin="0" Smax="0" Vmin="22" Vmax="61"/>
<Attribute Name="MySizeAttribute" Type="Size" MinAreaPc="0.01" MaxAreaPc="100"/>
Simple_Gun.xml

我们更改了 BlackGunSizeAttribute 中的 MaxAreaPc=20 以避免检测桌子的侧面。

XML 复制代码
<?xml version="1.0" ?>

<AttributeLib>
    <Attribute Name="HistColorPortalGun" Type="HistColor" Histogram="histograms/PortalGun.yaml"/>
    <Attribute Name="PotalGunSize" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>
    <Attribute Name="NotFractal" Type="Size" MinAreaPc="0.5" MaxAreaPc="100"/>

    <Attribute Name="HistColorBanana" Type="HistColor" Histogram="histograms/Banana.yaml"/>
    <Attribute Name="BananaSize" Type="Size" MinAreaPc="0.05" MaxAreaPc="100"/>


    <Attribute Name="HSVColorBlackGun" Type="HSVColor" Hmin="0" Hmax="0" Smin="0" Smax="0" Vmin="22" Vmax="61"/>
    <Attribute Name="BlackGunSizeAttribute" Type="Size" MinAreaPc="0.01" MaxAreaPc="20"/>
    
    <Attribute Name="HaarGun" Type="HaarCascade" Cascade="gun_haar/classifier/cascade.xml"/>
    <Attribute Name="MyBlobAttribute" Type="Blob" minThreshold="54" maxThreshold="125" blobColor="0" minArea="1500" minCircularity="0.03" minConvexity="0.64" minInertiaRatio="0.00"/>

</AttributeLib>

<SimpleObjectBase>  
      
    <SimpleObject Name="PortalGun" ID="1">              
        <Attribute Type="Detect">HistColorPortalGun</Attribute>  
        <Attribute Type="Check">PotalGunSize</Attribute>  
        <Attribute Type="Check">NotFractal</Attribute> 
    </SimpleObject>

    <SimpleObject Name="Banana" ID="2">              
        <Attribute Type="Detect">HistColorBanana</Attribute>  
        <Attribute Type="Check">BananaSize</Attribute>  
         
    </SimpleObject>    

    <SimpleObject Name="BlackGun" ID="3">              
        <Attribute Type="Detect">HSVColorBlackGun</Attribute> 
        <Attribute Type="Check">NotFractal</Attribute>
        <Attribute Type="Check">BlackGunSizeAttribute</Attribute>
    </SimpleObject>

    <SimpleObject Name="HaarBlackGun" ID="4" Mode="Hard" MergingPolicy="Union">              
        <Attribute Type="Detect">HaarGun</Attribute>
        <Attribute Type="Detect">MyBlobAttribute</Attribute> 
    </SimpleObject>  

</SimpleObjectBase>


<RelationLib>    

    
    
</RelationLib>


<ComplexObjectBase>
    
    
</ComplexObjectBase>
gun_detection.launch
XML 复制代码
<launch>
    <arg name="output" default="screen"/>
    <arg name="objectBasePath" default="$(find my_object_recognition_pkg)/config/object_base_example/Simple_Gun.xml"/>
    
    <node name="extended_object_detection" pkg="extended_object_detection" type="extended_object_detection_node" output="screen">
        
        <param name="objectBasePath" value="$(arg objectBasePath)"/>
        <param name="videoProcessUpdateRate" value="5"/>
        <param name="screenOutput" value="false"/>
        <param name="publishImage" value="true"/>
        <param name="publishMarkers" value="true"/>
        <param name="subscribeDepth" value="false"/>        
        <param name="maxContourPoints" value="-1"/>        
        
        <rosparam param="selectedOnStartSimple">[3]</rosparam>
        <rosparam param="selectedOnStartComplex">[-1]</rosparam>
        
    </node>        
    
</launch>

我们仅设置ID=3来稍微清理一下。

XML 复制代码
roslaunch my_object_recognition_pkg gun_detection.launch

您应该看到,现在桌子边框不再被检测到。当然,限制检测尺寸也有其缺点,因为如果机器人太近,枪将停止检测它。您需要了解机器人的正常工作条件才能做出这些决定。

练习 3.3.2

  • 为甜甜圈创建一个 HSV 检测器。
  • 将修改添加到 Simple_Gun.xml 和 gun_detector.launch 以检测枪和甜甜圈。
Parts to Add to Simple_Gun.xml
XML 复制代码
    <Attribute Name="HSVColorPinkDonut" Type="HSVColor" Hmin="68" Hmax="179" Smin="79" Smax="173" Vmin="142" Vmax="255"/>
    <Attribute Name="DonutSizeAttribute" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>
    
    ...
    
    
    <SimpleObject Name="PinkDonut" ID="4">              
        <Attribute Type="Detect">HSVColorPinkDonut</Attribute> 
        <Attribute Type="Check">NotFractal</Attribute>
        <Attribute Type="Check">DonutSizeAttribute</Attribute>
    </SimpleObject>
Parts to Change in the gun_detection.launch
XML 复制代码
<rosparam param="selectedOnStartSimple">[3,4]</rosparam>

简单对象:HaarBlackGun

这里,它使用 HaarGun 属性,我们还会寻找斑点。如果 BOTH 检测到某些东西(HARD 模式),我们会将两个边界框合并为一个。添加此斑点检测是为了避免 Haar Cascade 检测到任何地方的"枪",例如桌子侧面、桌腿、地平线或非常小的黑色伪影。

Haar in a Nutshell

基本的 Haar 操作是:

  • 我们获取一张图像并提取所有基本特征(之前图像中显示的黑白图案)。
  • 我们以群集或群组的形式执行此操作,以便更快地处理大图像。
  • 然后,我们使用 Adaboost 训练来选择能够提供更好结果(检测我们想要的内容)的特征。
  • 它使用级联分类器(本质上是机器学习)来完成繁重的工作。

要了解 Haar 的来源,请查看这篇论文:Paper Haar

Use Haar

下载已由 Saksham00799 训练并创建的 Haar 分类器,在本例中用于检测枪支:

XML 复制代码
roscd my_object_recognition_pkg/config/object_base_example
git clone https://github.com/Saksham00799/opencv-gun-detection
mv opencv-gun-detection gun_haar

修改 Simple_Gun.xml 以查找 Haar 文件:

Simple_Gun.xml
XML 复制代码
<?xml version="1.0" ?>

<AttributeLib>
    <Attribute Name="HistColorPortalGun" Type="HistColor" Histogram="histograms/PortalGun.yaml"/>
    <Attribute Name="PotalGunSize" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>
    <Attribute Name="NotFractal" Type="Size" MinAreaPc="0.5" MaxAreaPc="100"/>

    <Attribute Name="HistColorBanana" Type="HistColor" Histogram="histograms/Banana.yaml"/>
    <Attribute Name="BananaSize" Type="Size" MinAreaPc="0.05" MaxAreaPc="100"/>


    <Attribute Name="HSVColorBlackGun" Type="HSVColor" Hmin="0" Hmax="0" Smin="0" Smax="0" Vmin="22" Vmax="61"/>
    <Attribute Name="BlackGunSizeAttribute" Type="Size" MinAreaPc="0.01" MaxAreaPc="20"/>


    <Attribute Name="HSVColorPinkDonut" Type="HSVColor" Hmin="68" Hmax="179" Smin="79" Smax="173" Vmin="142" Vmax="255"/>
    <Attribute Name="DonutSizeAttribute" Type="Size" MinAreaPc="0.00" MaxAreaPc="100"/>
    
    <Attribute Name="HaarGun" Type="HaarCascade" Cascade="gun_haar/classifier/cascade.xml"/>
    <Attribute Name="MyBlobAttribute" Type="Blob" minThreshold="54" maxThreshold="125" blobColor="0" minArea="1500" minCircularity="0.03" minConvexity="0.64" minInertiaRatio="0.00"/>

</AttributeLib>

<SimpleObjectBase>  
      
    <SimpleObject Name="PortalGun" ID="1">              
        <Attribute Type="Detect">HistColorPortalGun</Attribute>  
        <Attribute Type="Check">PotalGunSize</Attribute>  
        <Attribute Type="Check">NotFractal</Attribute> 
    </SimpleObject>

    <SimpleObject Name="Banana" ID="2">              
        <Attribute Type="Detect">HistColorBanana</Attribute>  
        <Attribute Type="Check">BananaSize</Attribute>  
         
    </SimpleObject>    

    <SimpleObject Name="BlackGun" ID="3">              
        <Attribute Type="Detect">HSVColorBlackGun</Attribute> 
        <Attribute Type="Check">NotFractal</Attribute>
        <Attribute Type="Check">BlackGunSizeAttribute</Attribute>
    </SimpleObject>

    <SimpleObject Name="PinkDonut" ID="4">              
        <Attribute Type="Detect">HSVColorPinkDonut</Attribute> 
        <Attribute Type="Check">NotFractal</Attribute>
        <Attribute Type="Check">DonutSizeAttribute</Attribute>
    </SimpleObject>

    <SimpleObject Name="HaarBlackGun" ID="5" Mode="Hard" MergingPolicy="Union">              
        <Attribute Type="Detect">HaarGun</Attribute>
        <Attribute Type="Detect">MyBlobAttribute</Attribute> 
    </SimpleObject>  

</SimpleObjectBase>


<RelationLib>    

    
    
</RelationLib>


<ComplexObjectBase>
    
    
</ComplexObjectBase>
gun_detection.launch
XML 复制代码
<launch>
    <arg name="output" default="screen"/>
    <arg name="objectBasePath" default="$(find my_object_recognition_pkg)/config/object_base_example/Simple_Gun.xml"/>
    
    <node name="extended_object_detection" pkg="extended_object_detection" type="extended_object_detection_node" output="screen">
        
        <param name="objectBasePath" value="$(arg objectBasePath)"/>
        <param name="videoProcessUpdateRate" value="5"/>
        <param name="screenOutput" value="false"/>
        <param name="publishImage" value="true"/>
        <param name="publishMarkers" value="true"/>
        <param name="subscribeDepth" value="false"/>        
        <param name="maxContourPoints" value="-1"/>        
        
        <rosparam param="selectedOnStartSimple">[5]</rosparam>
        <rosparam param="selectedOnStartComplex">[-1]</rosparam>
        
    </node>        
    

启动检测器并查看其性能:

XML 复制代码
roslaunch my_object_recognition_pkg gun_detection.launch

这是没有属性的:

XML 复制代码
<Attribute Type="Detect">MyBlobAttribute</Attribute> 

正如你所见,Haar 探测器在甜甜圈、香蕉上,甚至桌子侧面都看到了很多可能的枪。

这就是我们添加 MyBlobAttribute 属性的原因。这将检测限制为仅检测大块黑白斑点。

练习 3.3.3

  • 下载 Haar 瓶分类器,看看它是否适用于 monster_can 饮料。
  • 您可以从 https://github.com/jemgunay/bottle-classifier.git 下载。您还可以在本课程的解决方案 Git 中找到 lint 版本。在完整的 Git 中,您可以检测杰克丹尼、伏特加、红牛和其他饮料。
XML 复制代码
roscd my_object_recognition_pkg/config/object_base_example
git clone https://github.com/jemgunay/bottle-classifier.git
  • 另外,请注意,当您尽可能靠近并且 PR2 机器人的躯干最大程度降低时,分类器的效果最佳。使用控制器 GUI 降低躯干并稍微向下倾斜头部以获得最佳性能。
Simple_Gun.xml 的新增内容
XML 复制代码
    <Attribute Name="HaarBottle" Type="HaarCascade" Cascade="bottle-classifier/classifier/classifier_monster/classifier/cascade.xml"/>

    ...
    
    
    <SimpleObject Name="HaarBottle" ID="6" Mode="Hard" MergingPolicy="Union">              
        <Attribute Type="Detect">HaarBottle</Attribute>
    </SimpleObject>    
编辑 gun_detection.launch
XML 复制代码
<rosparam param="selectedOnStartSimple">[5,6]</rosparam>

请注意,在这种情况下,我们不使用 blob。这是因为它不是进行检测所必需的,并且没有误报。如果一切顺利,您应该会得到类似于下图的结果:

复杂对象:

但在项目中,我们会使用复杂对象。它本质上是结合简单物体来检测更复杂的物体,例如,持枪的人。但那是最终项目。

请参阅下面的示例,了解如何完成此操作:

ArmedPerson.xml
XML 复制代码
<?xml version="1.0" ?>

<AttributeLib>
    <Attribute Name="HaarGun" Type="HaarCascade" Cascade="gun_haar/classifier/cascade.xml"/>
    <Attribute Name="MyBlobAttribute" Type="Blob" minThreshold="54" maxThreshold="125" blobColor="0" minArea="1500" minCircularity="0.03" minConvexity="0.64" minInertiaRatio="0.00"/>

    <Attribute Name="CnnPerson" Type="Dnn" framework="tensorflow" weights="ssd_mobilenet_v1_coco_2017_11_17/frozen_inference_graph.pb" config="ssd_mobilenet_v1_coco_2017_11_17/config.pbtxt" labels="ssd_mobilenet_v1_coco_2017_11_17/mscoco_label_map.pbtxt" inputWidth="300" inputHeight="300" Probability="0.5" obj_id="1"/> 
    

</AttributeLib>

<SimpleObjectBase>  
      
    <SimpleObject Name="HaarBlackGun" ID="3" Mode="Hard" MergingPolicy="Union">              
        <Attribute Type="Detect">HaarGun</Attribute>
        <Attribute Type="Detect">MyBlobAttribute</Attribute> 
    </SimpleObject>  

    <SimpleObject Name="CnnPerson" ID="67">              
        <Attribute Type="Detect">CnnPerson</Attribute>        
    </SimpleObject>    

</SimpleObjectBase>


<RelationLib>    

        <RelationShip Type="SpaceIn" Name="in"/>
    
</RelationLib>


<ComplexObjectBase>
    
    <ComplexObject ID="10" Name="ArmedPerson">
        <SimpleObject Class="CnnPerson" InnerName="Person"/>
        <SimpleObject Class="HaarBlackGun" InnerName="Gun"/>
        
        <Relation Obj1="Gun" Obj2="Person" Relationship="in"/>        
        
    </ComplexObject>
    
</ComplexObjectBase>
相关推荐
云边有个稻草人1 小时前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
冷眼看人间恩怨10 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
Hejjon15 小时前
SpringBoot 整合 SQLite 数据库
笔记
西洼工作室18 小时前
【java 正则表达式 笔记】
java·笔记·正则表达式
初学者7.18 小时前
Webpack学习笔记(2)
笔记·学习·webpack
新手上路狂踩坑19 小时前
Android Studio的笔记--BusyBox相关
android·linux·笔记·android studio·busybox
stm 学习ing20 小时前
HDLBits训练3
c语言·经验分享·笔记·算法·fpga·eda·verilog hdl
尘觉20 小时前
算法的学习笔记—扑克牌顺子(牛客JZ61)
数据结构·笔记·学习·算法
bohu8321 小时前
sentinel学习笔记1-为什么需要服务降级
笔记·学习·sentinel·滑动窗口
初学者7.1 天前
Webpack学习笔记(3)
笔记·学习·webpack