精华内容
下载资源
问答
  • 一个简单的应用程序,可以跟踪活动,健身水平并找到喜欢的。 ! 目录 屏幕截图 登陆页面 个人资料 用户资料 健身数据 令振奋的个人资料 现场演示 如果您不想创建帐户,请使用以下演示凭据登录: 用户名: ...
  • 一种基于深度学习的解决方案,可检测办公室中的人员并找出他们之间的距离以跟踪社交距离。 算法概念 预处理数据集 在YoloV3上进行火车模型以进行人员检测 框架中的人物检测 人们在与遥远的警报系统的框架。
  • 测试应该知道的15款最好的Bug跟踪管理系统.对某个项目来说,最重要的一件事情就是需要跟踪和梳理各种bug和问题,找到并解决问题,否则,项目就会花费超多的时间,导致整个项目的重心偏移。而且,用户总想标记未...
  • 尽管可以手动执行名称和图片的搜索,但Social Mapper可以更快地自动执行此类扫描,并且可以同时大规模的处理数百或数千。 “在线进行情报收集是非常耗时的过程,通常首先尝试在各种社交媒体网站上找到的在线状态...

    2018年8月9日,斯瓦蒂·汗德瓦尔(Swati Khandelwal

    原文地址:https://thehackernews.com/2018/08/social-mapper-osint.html

    image.png

    image.png

    社交媒体监控软件Trustwave的安全研究人员发布了新的开源工具,该工具使用面部识别技术在大量社交媒体网络中定位目标。

    面部识别工具:Social Mapper,可自动搜索八个社交媒体平台的目标,包括Facebook,Instagram,Twitter,LinkedIn,Google +,俄罗斯社交网站VKontakte,以及中国的微博和豆瓣 - 基于他们的名字和图片。

    该工具的创建者声称他们开发了Social Mapper情报收集工具,主要用于帮助渗透测试者和红客进行社会工程攻击。

    尽管可以手动执行名称和图片的搜索,但Social Mapper可以更快地自动执行此类扫描,并且可以同时大规模的处理数百或数千人。

    “在线进行情报收集是非常耗时的过程,通常首先尝试在各种社交媒体网站上找到的在线状态,”Trustwave在一篇详细介绍该工具的博客文章中解释道。

    Social Mapper通过三个阶段运行:

    阶段1 - 根据您提供的输入创建目标列表(由名称和图片组成)。该列表可以通过CSV文件中的链接,文件夹中的图像或LinkedIn上注册到公司的人员。

    阶段2 自动开始在线搜索社交媒体网站以获得目标。

    建议通过良好的互联网连接在夜间运行该工具,因为搜索可能需要超过15个小时才能获得1000个人的列表并使用大量带宽。

    阶段3 - 搜索之后,社交映射器的第三阶段开始生成报告,例如包含指向目标列表的配置文件页面的链接的电子表格,或者包含用于快速检查和验证结果的照片的更直观的HTML报告。

    Trustwave已经在GitHub上提供了Social Mapper,并且免费提供给所有人。 Social Mapper available on GitHub

    Trustwave的Jacob Wilkin本周将在Black Hat USA会议上展示Social Mapper,IBM Research到也会详细介绍其AI驱动的恶意软件 DeepLocker.

    https://github.com/SpiderLabs/social_mapper

    image.png

    实现:Python selenium

    参考资料

    转载于:https://my.oschina.net/u/1433482/blog/1926817

    展开全文
  • 「PoseNet」是一种视觉模型...这种姿势估计模型不会鉴别图像中的是谁,只会找到关键身体部位的 位置。 TensorFlow Lite 分享了一个安卓示例应用程序,该应用程序利用设备的摄像头来实时地检测和显示一个的关键部位
  • Matlab代码考克斯...使用上述轮廓跟踪代码找到的轮廓可以使用此代码分解为傅立叶模式。 随时间绘制每个模式的振幅,以显示曲率动力学。 基于Cox等的工作。 执照 原始FiberApp软件的许可证如下:版权所有(c)201
  • 当使用粒子群优化(PSO)进行人体运动跟踪时,由于不可靠的图像可能性,粒子可能会被误导并且无法找到最合理的姿势空间。 本文提出了一种新的基于PSO的人体运动跟踪算法,即基于PSO的退火粒子滤波器(APSOPF)。 ...
  • 技术对组织的影响更大,它迫使其基本功能发生变化,而不管行业功能如何。 为了赶上需求,公司被迫... 目的是通过主成分分析算法找到申请面部的重复。 该研究测试了申请预先录制的图像,并得出了进一步的研究思路。
  • rqt 也可以查看 6、安装 ros 支持的opencv $ sudo apt-get install ros-indigo-vision-opencv libopencv-dev \ python-opencv $ rospack profile 7、安装 ros连接opencv 桥梁包 cv_bridge Packag ...

    机器人视觉

    一、准备工作

    1、开源库:

     OpenCV,                           
       二维图像处理和机器学习
       https://github.com/Ewenwan/MVision/tree/master/opencv_app
     OpenNI2 +OpenKinect(freenect),   
        深度传感器(MicrosoftKinect and Asus Xtion Pro)驱动和处理库
     PCL.                         
        点云库 处理三维点云数据
        https://github.com/Ewenwan/MVision/tree/master/PCL_APP
    
     2维特征提取包  find_object_2d (ROS package)
                   https://github.com/introlab/find-object
                   http://wiki.ros.org/find_object_2d
                   补充参考:https://github.com/introlab/find-object
    
     3D物体识别(https://github.com/wg-perception)
    

    2D & 3D Object Detection 目标检测 算法和论文

     直接安装
     # ROS Kinetic:
      $ sudo apt-get install ros-kinetic-find-object-2d
     # ROS Jade:
      $ sudo apt-get install ros-jade-find-object-2d
     # ROS Indigo:
      $ sudo apt-get install ros-indigo-find-object-2d
     # ROS Hydro:
      $ sudo apt-get install ros-hydro-find-object-2d
     源码安装
      $ cd ~/catkin_ws
      $ git clone https://github.com/introlab/find-object.git src/find_object_2d
      $ catkin_make
    
     运行
      $ roscore &
      # Launch your preferred usb camera driver
      $ rosrun uvc_camera uvc_camera_node &
      $ rosrun find_object_2d find_object_2d image:=image_raw
    

    2、图像分辨率:

     160x120 (QQVGA), 320x240 (QVGA), 640x480 (VGA) , 1280x960 (SXGA).
    

    3、安装深度传感器驱动: ROS OpenNI and OpenKinect (freenect) Drivers
    sudo apt-get install ros-indigo-openni-* ros-indigo-openni2-* ros-indigo-freenect-*
    $ rospack profile

    4、安装普通摄像头驱动 Webcam Driver

     源码安装
     usb_cam:
     cd ~/catkin_ws/src
     git clone https://github.com/bosch-ros-pkg/usb_cam.git
     cd ~/catkin_ws
     catkin_make
     rospack profile
    
     libuvc_ros:
     https://github.com/ros-drivers/libuvc_ros
    
     uvc_cam:
     cd cd ~/catkin_ws/src
     git clone https://github.com/ericperko/uvc_cam.git  
     rosmake uvc_cam
    

    5、测试图像传感器

     对于 rgb-d传感器
     使用 image_view 包 测试  http://wiki.ros.org/image_view
    
     发布数据 在/camera/rgb/image_raw话题上
       Microsoft Kinect:
     $ roslaunch freenect_launch freenect-registered-xyzrgb.launch
    
       Asus Xtion, Xtion Pro, or Primesense 1.08/1.09 cameras:
     $ roslaunch openni2_launch openni2.launch depth_registration:=true
    
     可视化查看 rgb图像
     rosrun image_view image_view image:=/camera/rgb/image_raw
     可视化查看 深度图像
     $ rosrun image_view image_view image:=/camera/depth_registered/image_rect
    
     对于Webcam Driver
     发布消息
     $ roslaunch rbx1_vision usb_cam.launch video_device:=/dev/video0
     or
     $ roslaunch rbx1_vision usb_cam.launch video_device:=/dev/video1
     可视化查看
     rosrun image_view image_view image:=/camera/rgb/image_raw
    
    
     <launch>
         <arg name="video_device" default="/dev/video0" />   驱动名字
    
         <node name="usb_cam" pkg="usb_cam" type="usb_cam_node" clear_params="true" output="screen">##节点信息
    
          <remap from="usb_cam/image_raw" to="/camera/rgb/image_raw" />  话题重定向
          <remap from="usb_cam/camera_info" to="/camera/rgb/camera_info" />
    
             <param name="video_device" value="$(arg video_device)" />
             <param name="image_width" value="640" />
             <param name="image_height" value="480" />
             <param name="framerate" value="30" />
             <param name="pixel_format" value="yuyv" />  这里注意需要和驱动程序输出的图片格式一致 原先为mmp格式
             <param name="contrast" value="32" />  对比度
             <param name="brightness" value="32" /> 亮度
             <param name="saturation" value="32" /> 饱和度
             <param name="autofocus" value="true" />
             <param name="camera_frame_id" value="camera_link" />
    
         </node>
     </launch>
    
    
    
     rqt 也可以查看
    

    6、安装 ros 支持的opencv

     $ sudo apt-get install ros-indigo-vision-opencv libopencv-dev \
     python-opencv
     $ rospack profile
    

    7、安装 ros连接opencv 桥梁包 cv_bridge Packag 转换 ros图片格式 与 opencv图片格式

    http://wiki.ros.org/cv_bridge
    rbx1_vision/nodes/cv_bridge.demo.py 展示了怎样使用  cv_bridge
    

    cv_bridge.demo.py

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import rospy
    import sys
    import cv2
    import cv2.cv as cv
    from sensor_msgs.msg import Image, CameraInfo
    from cv_bridge import CvBridge, CvBridgeError
    import numpy as np
    
    class cvBridgeDemo():
        def __init__(self):
            self.node_name = "cv_bridge_demo"
            
            rospy.init_node(self.node_name)
            
            # 关闭
            rospy.on_shutdown(self.cleanup)
            
            # 创建 rgb图像 显示窗口
            self.cv_window_name = self.node_name
            cv.NamedWindow(self.cv_window_name, cv.CV_WINDOW_NORMAL)
            cv.MoveWindow(self.cv_window_name, 25, 75)
            
            # 创建深度图像显示窗口
            cv.NamedWindow("Depth Image", cv.CV_WINDOW_NORMAL)
            cv.MoveWindow("Depth Image", 25, 350)
            
            # 创建 ros 图 到 opencv图像转换 对象
            self.bridge = CvBridge()
            
            # 订阅 深度图像和rgb图像数据发布的话题  以及定义 回调函数
            # the appropriate callbacks
            self.image_sub = rospy.Subscriber("input_rgb_image", Image, self.image_callback, queue_size=1)
            self.depth_sub = rospy.Subscriber("input_depth_image", Image, self.depth_callback, queue_size=1)
            # 登陆信息
            rospy.loginfo("Waiting for image topics...")
            rospy.wait_for_message("input_rgb_image", Image)
            rospy.loginfo("Ready.")
    
        # 收到rgb图像后的回调函数
        def image_callback(self, ros_image):
            # 转换图像格式到opencv格式
            try:
                frame = self.bridge.imgmsg_to_cv2(ros_image, "bgr8")
            except CvBridgeError, e:
                print e
            # 转换成 numpy 图像数组格式
            frame = np.array(frame, dtype=np.uint8)
            
            # 简单处理图像数据 颜色 滤波 边缘检测等
            display_image = self.process_image(frame)
                           
            # 显示图像
            cv2.imshow(self.node_name, display_image)
            
            # 检测键盘按键事件
            self.keystroke = cv2.waitKey(5)
            if self.keystroke != -1:
                cc = chr(self.keystroke & 255).lower()
                if cc == 'q':
                    # The user has press the q key, so exit
                    rospy.signal_shutdown("User hit q key to quit.")
    
        # 收到深度图像后的回调函数            
        def depth_callback(self, ros_image):
            # 转换图像格式到opencv格式
            try:
                # Convert the depth image using the default passthrough encoding
                depth_image = self.bridge.imgmsg_to_cv2(ros_image, "passthrough")
            except CvBridgeError, e:
                print e
    
            # 转换成 numpy 图像数组格式
            depth_array = np.array(depth_image, dtype=np.float32)
                    
            # 深度图像 数据 正则化到 二值图像
            cv2.normalize(depth_array, depth_array, 0, 1, cv2.NORM_MINMAX)
            
            # 深度图像处理
            depth_display_image = self.process_depth_image(depth_array)
        
            # 现实结果
            cv2.imshow("Depth Image", depth_display_image)
    
        # rgb图像处理      
        def process_image(self, frame):
            # 转化成灰度图像
            grey = cv2.cvtColor(frame, cv.CV_BGR2GRAY)
            
            # 均值滤波
            grey = cv2.blur(grey, (7, 7))
            
            # Canny 边缘检测
            edges = cv2.Canny(grey, 15.0, 30.0)
            
            return edges
        
        # 深度图像处理
        def process_depth_image(self, frame):
            # 这里直接返回原图   可做其他处理
            return frame
    
        # 关闭节点 销毁所有 窗口
        def cleanup(self):
            print "Shutting down vision node."
            cv2.destroyAllWindows()   
    
    # 主函数    
    def main(args):       
        try:
            cvBridgeDemo()
            rospy.spin()
        except KeyboardInterrupt:
            print "Shutting down vision node."
            cv.DestroyAllWindows()
    
    if __name__ == '__main__':
        main(sys.argv)
    

    安装 照相机驱动程序 获取视频流 usb_cam

          cd catkin_ws/src
          git clone git://github.com/bosch-ros-pkg/usb_cam.git
          catkin_make
          source ~/catkin_ws/devel/setup.bash
          
    使用rgb 摄像头获取的图像数据测试 上述节点功能   注意发布数据的话题 重映射到 上述节点指定的话题
    
     <launch>
       <node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen" >
         <param name="video_device" value="/dev/video0" />
         <param name="image_width" value="640" />
         <param name="image_height" value="480" />
         <param name="pixel_format" value="yuyv" />
         <param name="camera_frame_id" value="usb_cam" />
         <param name="io_method" value="mmap"/>
         <remap from="/usb_cam/image_raw" to="camera/image_raw"/>
       </node>
    
       </node> 
       <node name="cvDemo" pkg="vision_system" type="my_cv_bridge_demo.py" output="screen">
       </node>
     </launch>
    

    鼠标 选取 感兴趣区域

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    """
        使用opencv2 跟踪 用户鼠标选择的 区域
    """
    
    import rospy # ros系统操作
    import sys   # 系统程序 输入参数的获取等 
    import cv2   # 新版opencv2 api 
    import cv2.cv as cv # 老版 opencv api
    from std_msgs.msg import String       # ros系统 消息类型 来自 std_msgs.msg 标准消息类型 
    from sensor_msgs.msg import Image, RegionOfInterest, CameraInfo # ros 系统 消息类型 来自 sensor_msgs 传感器消息类型包 
    from cv_bridge import CvBridge, CvBridgeError                   # ros 系统 图像 格式 转换到 opencv图像格式  以及转换失败的错误信息处理
    import time        # 计时
    import numpy as np # numpy 的数组
    
    class ROS2OpenCV2(object):
        def __init__(self, node_name):        
            self.node_name = node_name
            rospy.init_node(node_name)
            rospy.loginfo("启动节点 " + str(node_name))
            # 关闭 
            rospy.on_shutdown(self.cleanup)
            
            # 一些参数 可由 launch文件 修改的参数
            self.show_text = rospy.get_param("~show_text", True)
            self.show_features = rospy.get_param("~show_features", True)
            self.show_boxes = rospy.get_param("~show_boxes", True)
            self.flip_image = rospy.get_param("~flip_image", False)
            self.feature_size = rospy.get_param("~feature_size", 10) # 点  圆形 的 半径
    
            # 传感器消息类型  感兴趣区域  发布话题 
            self.ROI = RegionOfInterest()
            self.roi_pub = rospy.Publisher("/roi", RegionOfInterest, queue_size=1)
            
            # 初始化 全局变量
            self.frame = None
            self.frame_size = None
            self.frame_width = None
            self.frame_height = None
            self.depth_image = None
            self.marker_image = None
            self.display_image = None
            self.grey = None
            self.prev_grey = None
            self.selected_point = None
            self.selection = None
            self.drag_start = None
            self.keystroke = None
            self.detect_box = None # 检测的目标区域位置框
            self.track_box = None  # 跟踪的目标区域位置框
            self.display_box = None
            self.keep_marker_history = False
            self.night_mode = False
            self.auto_face_tracking = False
            self.cps = 0            # 每秒 处理 次数 Cycles per second = number of processing loops per second.
            self.cps_values = list()
            self.cps_n_values = 20
            self.busy = False
            self.resize_window_width = 0  #窗口大小
            self.resize_window_height = 0
            self.face_tracking = False
            
            # 创建 显示 窗口
            self.cv_window_name = self.node_name
            cv.NamedWindow(self.cv_window_name, cv.CV_WINDOW_NORMAL)
            if self.resize_window_height > 0 and self.resize_window_width > 0:
                cv.ResizeWindow(self.cv_window_name, self.resize_window_width, self.resize_window_height)
    
            # 创建 ros 图 到 opencv图像转换 对象 bridge
            self.bridge = CvBridge()
            # 设置对应窗口 鼠标点击事件 回调函数
            cv.SetMouseCallback (self.node_name, self.on_mouse_click, None)
            
            # 订阅 深度图像和rgb图像数据发布的话题  以及定义 回调函数
            self.image_sub = rospy.Subscriber("input_rgb_image", Image, self.image_callback, queue_size=1)
            self.depth_sub = rospy.Subscriber("input_depth_image", Image, self.depth_callback, queue_size=1)
            
        # 鼠标点击事件回调函数                               
        def on_mouse_click(self, event, x, y, flags, param):
          # 允许用户用鼠标选者一个感兴趣区域   一个矩形框图  全局变量 selection 矩形框  <左上角点x 左上角点y  宽度 高度>
            if self.frame is None:
                return
            # 鼠标按下
            if event == cv.CV_EVENT_LBUTTONDOWN and not self.drag_start:
                self.features = []    #  初始化感兴趣区域
                self.track_box = None # 跟踪 框
                self.detect_box = None# 检测 框
                self.selected_point = (x, y)# 选择点
                self.drag_start = (x, y)    # 拖拽起点 后 开始拖拽
            # 鼠标抬起    
            if event == cv.CV_EVENT_LBUTTONUP:
                self.drag_start = None # 拖拽结束
                self.classifier_initialized = False
                self.detect_box = self.selection
            # 鼠标拖拽    
            if self.drag_start:
                xmin = max(0, min(x, self.drag_start[0]))# 起点 横坐标 为 鼠标选者区域的 横向 最小值 min(x, self.drag_start[0])
                ymin = max(0, min(y, self.drag_start[1]))# 起点 纵坐标
                xmax = min(self.frame_width, max(x, self.drag_start[0])) # 终点为最大值 鼠标选者区域的 横向 最大值 man(x, self.drag_start[0])
                ymax = min(self.frame_height, max(y, self.drag_start[1]))
                self.selection = (xmin, ymin, xmax - xmin, ymax - ymin)  # 矩形区域 左上角 起点(x,y) 长 宽
                
        def image_callback(self, data):
            # 图像 header  时间  大小等信息
            self.image_header = data.header
            # 这次循环开始时间
            start = time.time()      
            # 转换成opencv2图像格式
            frame = self.convert_image(data)       
            # 翻转图像  翻转方向:1:水平翻转;0:垂直翻转;-1:水平垂直翻转
            if self.flip_image:
                frame = cv2.flip(frame, 0)        
            # 设置图像 尺寸
            if self.frame_width is None:
                self.frame_size = (frame.shape[1], frame.shape[0])# 列 为 宽度  行为高度
                self.frame_width, self.frame_height = self.frame_size                        
            # 创建可视化  marker image  marker图像  可在rviz中查看
            if self.marker_image is None:
                self.marker_image = np.zeros_like(frame)           
            # 将祯图像 设置成全局变量
            self.frame = frame.copy()
            # 如果 不 记录历史图像 重置 可视化  marker image 
            if not self.keep_marker_history:
                self.marker_image = np.zeros_like(self.marker_image)
                
            # 处理图像 检测和跟踪 目标
            processed_image = self.process_image(frame)
            
            # 如果是 单通道  转化成  多通道  创建全局 处理后的图像
            #if processed_image.channels == 1:
                #cv.CvtColor(processed_image, self.processed_image, cv.CV_GRAY2BGR)
            #else:       
            # 创建全局 处理后的图像
            self.processed_image = processed_image.copy()
            
            # 显示户选择的 矩形框
            self.display_selection()
            
            # Night mode: 仅显示  processed_image
            if self.night_mode:
                self.processed_image = np.zeros_like(self.processed_image)
                
            # 混合 原图 marker image  和处理后的 图像
            self.display_image = cv2.bitwise_or(self.processed_image, self.marker_image)
    
            # 显示跟踪的 矩形框图
            # cvRect (x,y,w,h) or a rotated Rect (center, size, angle).
            if self.show_boxes:
                if self.track_box is not None and self.is_rect_nonzero(self.track_box):
                    if len(self.track_box) == 4:
                        x,y,w,h = self.track_box
                        size = (w, h)
                        center = (x + w / 2, y + h / 2)
                        angle = 0
                        self.track_box = (center, size, angle)
                    else:
                        (center, size, angle) = self.track_box   
    
                    # 对于人脸检测 的框  用垂直矩形框 更合适
                    if self.face_tracking:
                        pt1 = (int(center[0] - size[0] / 2), int(center[1] - size[1] / 2))
                        pt2 = (int(center[0] + size[0] / 2), int(center[1] + size[1] / 2))
                        cv2.rectangle(self.display_image, pt1, pt2, cv.RGB(50, 255, 50), self.feature_size, 8, 0)# 画 矩形
                    else:
                        # 其他 画 旋转的 矩形 
                        vertices = np.int0(cv2.cv.BoxPoints(self.track_box))
                        cv2.drawContours(self.display_image, [vertices], 0, cv.RGB(50, 255, 50), self.feature_size)
    
                # 显示检测 的 矩形 框图 
                elif self.detect_box is not None and self.is_rect_nonzero(self.detect_box):
                    (pt1_x, pt1_y, w, h) = self.detect_box
                    if self.show_boxes:
                        cv2.rectangle(self.display_image, (pt1_x, pt1_y), (pt1_x + w, pt1_y + h), cv.RGB(50, 255, 50), self.feature_size, 8, 0)
            
            # 发布感兴趣区域到 感兴趣区域 消息类型 话题上
            self.publish_roi()
                
            # 计算处理时间  返回 处理速度 帧/s
            end = time.time()
            duration = end - start
            fps = int(1.0 / duration)
            self.cps_values.append(fps)
            if len(self.cps_values) > self.cps_n_values:# 保持最新的 几个  处理速度 帧/s 
                self.cps_values.pop(0)
            self.cps = int(sum(self.cps_values) / len(self.cps_values)) # 计算均值
            
            # 显示 处理速度 帧/s CPS and image 以及图像分辨率 
            if self.show_text:
                font_face = cv2.FONT_HERSHEY_SIMPLEX
                font_scale = 0.5
    
                """ 显示 的位置 """
                if self.frame_size[0] >= 640:
                    vstart = 25
                    voffset = int(50 + self.frame_size[1] / 120.)
                elif self.frame_size[0] == 320:
                    vstart = 15
                    voffset = int(35 + self.frame_size[1] / 120.)
                else:
                    vstart = 10
                    voffset = int(20 + self.frame_size[1] / 120.)
                cv2.putText(self.display_image, "CPS: " + str(self.cps), (10, vstart), font_face, font_scale, cv.RGB(255, 255, 0))
                cv2.putText(self.display_image, "RES: " + str(self.frame_size[0]) + "X" + str(self.frame_size[1]), (10, voffset), font_face, font_scale, cv.RGB(255, 255, 0))
            
            # 更新图像显示
            cv2.imshow(self.node_name, self.display_image)
            
            # 处理键盘 按键命令
            self.keystroke = cv2.waitKey(5)
            if self.keystroke is not None and self.keystroke != -1:
                try:
                    cc = chr(self.keystroke & 255).lower()
                    if cc == 'n':
                        self.night_mode = not self.night_mode
                    elif cc == 'f':
                        self.show_features = not self.show_features
                    elif cc == 'b':
                        self.show_boxes = not self.show_boxes
                    elif cc == 't':
                        self.show_text = not self.show_text
                    elif cc == 'q':
                        # The has press the q key, so exit
                        rospy.signal_shutdown("User hit q key to quit.")
                except:
                    pass
        # 深度图像的 回调函数         
        def depth_callback(self, data):
            # 转换图像格式
            depth_image = self.convert_depth_image(data)      
            # 翻转图像  翻转方向:1:水平翻转;0:垂直翻转;-1:水平垂直翻转
            if self.flip_image:    
                depth_image = cv2.flip(depth_image, 0)       
            # 处理
            processed_depth_image = self.process_depth_image(depth_image)
            
            # 全局变量
            self.depth_image = depth_image.copy()
            self.processed_depth_image = processed_depth_image.copy()
        # 转换 rgb图像     
        def convert_image(self, ros_image):
            # Use cv_bridge() to convert the ROS image to OpenCV format
            try:
                cv_image = self.bridge.imgmsg_to_cv2(ros_image, "bgr8")       
                return np.array(cv_image, dtype=np.uint8)
            except CvBridgeError, e:
                print e
        # 转换深度图像      
        def convert_depth_image(self, ros_image):
            # Use cv_bridge() to convert the ROS image to OpenCV format
            try:
                depth_image = self.bridge.imgmsg_to_cv2(ros_image, "passthrough")            
                depth_image = np.array(depth_image, dtype=np.float32)           
                return depth_image        
            except CvBridgeError, e:
                print e
        # 发布  感兴趣区域 的尺寸 位置 到/roi话题上      
        def publish_roi(self):
            if not self.drag_start:
                if self.track_box is not None:
                    roi_box = self.track_box
                elif self.detect_box is not None:
                    roi_box = self.detect_box
                else:
                    return
            try:
                roi_box = self.cvBox2D_to_cvRect(roi_box)# 转换成 矩形区域
            except:
                return
            
            # 下限 为 0
            roi_box[0] = max(0, roi_box[0])
            roi_box[1] = max(0, roi_box[1])
            
            try:
                ROI = RegionOfInterest()
                ROI.x_offset = int(roi_box[0])
                ROI.y_offset = int(roi_box[1])
                ROI.width = int(roi_box[2])
                ROI.height = int(roi_box[3])
                self.roi_pub.publish(ROI)
            except:
                rospy.loginfo("发布ROI失败")
        # 处理图像  跟踪 感兴趣区域  
        def process_image(self, frame): 
            return frame   
        def process_depth_image(self, frame):
            return frame
        
        # 显示户选择的 矩形框
        def display_selection(self):
            # 显示 举行框
            if self.drag_start and self.is_rect_nonzero(self.selection):# 矩形框
                x,y,w,h = self.selection
                cv2.rectangle(self.marker_image, (x, y), (x + w, y + h), (0, 255, 255), self.feature_size)
                self.selected_point = None
            # 显示 点 圆 
            elif not self.selected_point is None:# 点
                x = self.selected_point[0]
                y = self.selected_point[1]
                cv2.circle(self.marker_image, (x, y), self.feature_size, (0, 255, 255), self.feature_size)
        # 检测矩形框 是否 为空   
        def is_rect_nonzero(self, rect):
            # 左上角点  宽度 高度 类型
            try:
                (_,_,w,h) = rect
                return (w > 0) and (h > 0)
            except:
                try:
                    # 左上角点  大小  角度
                    ((_,_),(w,h),a) = rect
                    return (w > 0) and (h > 0)
                except:
                    return False
        # 矩形款 格式转换      <左上角点  大小  角度>  到 <左上角点x 左上角点y  宽度 高度>
        def cvBox2D_to_cvRect(self, roi):
            try:
                if len(roi) == 3:
                    (center, size, angle) = roi
                    pt1 = (int(center[0] - size[0] / 2), int(center[1] - size[1] / 2))
                    pt2 = (int(center[0] + size[0] / 2), int(center[1] + size[1] / 2))
                    rect = [pt1[0], pt1[1], pt2[0] - pt1[0], pt2[1] - pt1[1]] # <左上角点x 左上角点y  宽度 高度>
                else:
                    rect = list(roi)
            except:
                return [0, 0, 0, 0]
                
            return rect
        # 矩形框  格式转换      <左上角点x 左上角点y  宽度 高度>   到   <左上角点  大小  角度>  
        def cvRect_to_cvBox2D(self, roi):
            try:
                if len(roi) == 3:
                    box2d = roi
                else:
                    (p1_x, p1_y, width, height) = roi
                    center = (int(p1_x + width / 2), int(p1_y + height / 2))
                    size = (width, height)
                    angle = 0
                    box2d = (center, size, angle)
            except:
                return None            
            return list(box2d)
        
        # 清理退出函数      关闭节点 销毁所有 窗口
        def cleanup(self):
            print "关闭了视觉信息处理节点。"
            cv2.destroyAllWindows()       # 关闭所有窗口 
    # 主函数
    def main(args):    
        try:
            node_name = "ros2opencv2"
            ROS2OpenCV2(node_name)
            rospy.spin()
        except KeyboardInterrupt:
            print "关闭了视觉信息处理节点。"
            cv.DestroyAllWindows()
    
    if __name__ == '__main__':
        main(sys.argv)
    

    ros_object_analytics 单帧点云(欧氏距离聚类分割) + Yolo_v2/MobileNet_SSD 3D物体检测

    代码

    简介:

       物体分析 Object Analytics (OA) 是一个ros包,
       支持实时物体检测定位和跟踪(realtime object detection, localization and tracking.)
       使用 RGB-D 相机输入,提供物体分析服务,为开发者开发更高级的机器人高级特性应用, 
       例如智能壁障(intelligent collision avoidance),和语义SLAM(semantic SLAM). 
    
       订阅:
             RGB-D 相机发布的点云消息[sensor_msgs::PointClould2](http://docs.ros.org/api/sensor_msgs/html/msg/PointCloud2.html) 
       发布话题到:
             物体检测 [object detection](https://github.com/intel/object_msgs), 
             物体跟踪 [object tracking](https://github.com/intel/ros_object_analytics/tree/master/object_analytics_msgs), 
             物体3d定位 [object localization](https://github.com/intel/ros_object_analytics/object_analytics_msgs) 
    

    2D 目标检测算法:

     1. 基于 图形处理器(GPU) 运行的目标检测 , 
        ros_opencl_caffe, Yolo v2 model and OpenCL Caffe framework
        https://github.com/intel/ros_opencl_caffe
        
     2. 基于 视觉处理器(VPU) 运行的目标检测 , 
         ros_intel_movidius_ncs (devel branch), 
         with MobileNet_SSD model and Caffe framework.
         
         https://github.com/Ewenwan/ros_intel_movidius_ncs
         
     (Movidius神经计算棒,首个基于USB模式的深度学习推理工具和独立的人工智能(AI)加速器)
     英特尔的子公司Movidius宣布推出Movidius Myriad X视觉处理器(VPU),
     该处理器是一款低功耗SoC,主要用于基于视觉的设备的深度学习和AI算法加速,比如无人机、智能相机、VR/AR头盔。
     就在不久前的上个月,Movidius还推出了基于Myriad 2芯片的神经计算棒Movidius Neural Compute Stick。
    

    节点订阅的 传感器发布的话题

    RGB图像 object_analytics/rgb (sensor_msgs::Image)

    点云 object_analytics/pointcloud (sensor_msgs::PointCloud2)

    节点发布的处理后得到的信息

    定位信息(3d边框) object_analytics/localization (object_analytics_msgs::ObjectsInBoxes3D)

    跟踪信息 object_analytics/tracking (object_analytics_msgs::TrackedObjects)

    检测信息(2d边框)object_analytics/detection (object_msgs::ObjectsInBoxes)

    object_analytics 节点分析

      1. RGBD传感器预处理分割器 splitter  
         输入: /camera/depth_registered/points
         输出: pointcloud   3d点 
         输出: rgb 2d图像
         object_analytics_nodelet/splitter/SplitterNodelet 
         
      2. 点云分割处理器 segmenter
         object_analytics_launch/launch/includes/segmenter.launch
         输入: pointcloud   3d点
         输出: segmentation 分割
         object_analytics_nodelet/segmenter/SegmenterNodelet 
         object_analytics_nodelet/src/segmenter/segmenter_nodelet.cpp
         订阅发布话题后
         std::unique_ptr<Segmenter> impl_;
         点云话题回调函数:
            boost::shared_ptr<ObjectsInBoxes3D> msg = boost::make_shared<ObjectsInBoxes3D>();// 3d框
            msg->header = points->header;
            impl_->segment(points, msg);//检测
            pub_.publish(msg);          //发布检测消息
            
         object_analytics_nodelet/src/segmenter/segmenter.cpp
         a. 首先 ros点云消息转化成 pcl点云消息
               const sensor_msgs::PointCloud2::ConstPtr& points;
               PointCloudT::Ptr pointcloud(new PointCloudT);
               fromROSMsg<PointT>(*points, pcl_cloud);
               
         b. 执行分割 Segmenter::doSegment()
            std::vector<PointIndices> cluster_indices;// 点云所属下标
            PointCloudT::Ptr cloud_segment(new PointCloudT);// 分割点云
              std::unique_ptr<AlgorithmProvider> provider_;
            std::shared_ptr<Algorithm> seg = provider_->get();// 分割算法
            seg->segment(cloud, cloud_segment, cluster_indices);// 执行分割
            
             AlgorithmProvider -> virtual std::shared_ptr<Algorithm> get() = 0;
             Algorithm::segment()
             object_analytics_nodelet/src/segmenter/organized_multi_plane_segmenter.cpp
             class OrganizedMultiPlaneSegmenter : public Algorithm
             OrganizedMultiPlaneSegmenter 类集成 Algorithm类
             分割算法 segment(){} 基于pcl算法
               1. 提取点云法线 OrganizedMultiPlaneSegmenter::estimateNormal()
               2. 分割平面     OrganizedMultiPlaneSegmenter::segmentPlanes()           平面系数模型分割平面
               3. 去除平面后 分割物体  OrganizedMultiPlaneSegmenter::segmentObjects()  欧氏距离聚类分割
             
         c. 生成消息  Segmenter::composeResult()
            for (auto& obj : objects)
            {
            object_analytics_msgs::ObjectInBox3D oib3;
            oib3.min = obj.getMin();
            oib3.max = obj.getMax();
            oib3.roi = obj.getRoi();
            msg->objects_in_boxes.push_back(oib3);
            }
            
      3. 3d定位器 merger
         输入: 2d检测分割结果 detection
         输入: 3d检测分割结果 segmentation
         输出: 3d定位结果   localization
         object_analytics_nodelet/merger/MergerNodelet
         
          2d物体 和 3d物体 关系 ====== 
            遍历 每一个2d物体
               遍历   每一个3d物体(3d物体点云反投影到像素平面上的2d框)
                 计算 2d物体边框 和3d物体投影2d边框的相似度  两边框的匹配相似度 match = IOU * distance /  AvgSize
                   记录和 该2d边框最相似的 3d物体id
    
      4. 目标跟踪器 tracker
         输入: 2d图像        rgb        input_rgb 
         输入: 2d检测分割结果 detection  input_2d 
         输出: 跟踪结果    tracking  output  
         参数: 跟踪帧队列长度: aging_th:default="30";
         参数: 跟踪置信度: probability_th" default="0.5"
         object_analytics_nodelet/tracker/TrackingNodelet
    

    object_analytics_visualization 可视化

      5. 3d定位可视化 visualization3d localization
         输入: 2d检测结果 "detection_topic" default="/object_analytics/detection" 
         输入: 3d检测结果 "localization_topic" default="/object_analytics/localization" 
         输入: 2d跟踪结果 "tracking_topic" default="/object_analytics/tracking" 
         输出: rviz可视化话题 "output_topic" default="localization_rviz" 
    
      6. 2d跟踪可视化 visualization2d 
         输入: 2d检测结果 "detection_topic" default="/object_analytics/detection" 
         输入: 2d跟踪结果 "tracking_topic" default="/object_analytics/tracking" 
         输入: 2d图像     "image_topic" default="/object_analytics/rgb" 
         输出: rviz可视化话题 ""output_topic" default="tracking_rviz"    
    

    目标检测接口

    GPU yolo_v2 目标检测后端

      opencl_caffe_launch/launch/includes/nodelet.launch 
    

    来源 ros_opencl_caffe 

      输入: 2d图像          /usb_cam/image_raw    input_topic
      输出: 2d检测分割结果  input_detection        output_topic
      参数文件: param_file default= find opencl_caffe_launch/launch/includes/default.yaml"
            模型文件 net_config_path:  "/opt/clCaffe/models/yolo/yolo416/yolo_fused_deploy.prototxt"
            权重文件 weights_path:     "/opt/clCaffe/models/yolo/yolo416/fused_yolo.caffemodel"
            类别标签文件 labels_path: "/opt/clCaffe/data/yolo/voc.txt"
    
      节点: opencl_caffe/opencl_caffe_nodelet
      opencl_caffe/src/nodelet.cpp
      Nodelet::onInit()  --->  loadResources() 
      检测器 detector_.reset(new DetectorGpu());
      载入配置文件 detector_->loadResources(net_config_path, weights_path, labels_path)
      订阅话题回调函数  sub_ = getNodeHandle().subscribe("/usb_cam/image_raw", 1, &Nodelet::cbImage, this);
      Nodelet::cbImage();
         网络前向推理 detector_->runInference(image_msg, objects)
         发布话题   pub_.publish(objects);
    
    
      DetectorGpu 类
      opencl_caffe/src/detector_gpu.cpp
      网络初始化:
      net.reset(new caffe::Net<Dtype>(net_cfg, caffe::TEST, caffe::Caffe::GetDefaultDevice()));
      net->CopyTrainedLayersFrom(weights);
    
      模式:
      caffe::Caffe::set_mode(caffe::Caffe::GPU);
      caffe::Caffe::SetDevice(0);
      载入图像:
      cv::cvtColor(cv_bridge::toCvShare(image_msg, "rgb8")->image, image, cv::COLOR_RGB2BGR);
      initInputBlob(resizeImage(image), input_channels);
      网络前传:
      net->Forward();
      获取网络结果:
      caffe::Blob<Dtype>* result_blob = net->output_blobs()[0];
      const Dtype* result = result_blob->cpu_data();
      const int num_det = result_blob->height();
      检测结果:
      object_msgs::ObjectInBox object_in_box;
      object_in_box.object.object_name = labels_list[classid];
      object_in_box.object.probability = confidence;
      object_in_box.roi.x_offset = left;
      object_in_box.roi.y_offset = top;
      object_in_box.roi.height = bot - top;
      object_in_box.roi.width = right - left;
      objects.objects_vector.push_back(object_in_box);
    

    VPU mobileNetSSD 目标检测后端

      movidius_ncs_launch/launch/includes/ncs_stream_detection.launch
    

    来源 ros_intel_movidius_ncs 

      输入: 2d图像         input_rgb        input_topic
      输出: 2d检测分割结果  input_detection  output_topic
      参数: 
         模型类型 name="cnn_type" default="mobilenetssd"
         模型配置文件 name="param_file" default="$(find movidius_ncs_launch)/config/mobilenetssd.yaml"
            网络图配置文件 graph_file_path: "/opt/movidius/ncappzoo/caffe/SSD_MobileNet/graph"
            类别文件voc21  category_file_path: "/opt/movidius/ncappzoo/data/ilsvrc12/voc21.txt"
            网络输入尺寸   network_dimension: 300
            通道均值 :
              channel1_mean: 127.5
              channel2_mean: 127.5
              channel3_mean: 127.5
            归一化:
              scale: 0.007843
          节点文件 movidius_ncs_stream/NCSNodelet movidius_ncs_stream/src/ncs_nodelet.cpp
      输入话题 input_topic : 2d图像       /camera/rgb/image_raw
       输出话题  output_topic : 2d检测框结果  detected_objects
          ncs_manager_handle_ = std::make_shared<movidius_ncs_lib::NCSManager>();
          movidius_ncs_lib::NCSManager 来自 movidius_ncs_lib/src/ncs_manager.cpp
          NCSImpl::init(){ }
          订阅 rgb图像的回调函数 cbDetect()
          sub_ = it->subscribe("/camera/rgb/image_raw", 1, &NCSImpl::cbDetect, this);
          cbDetect(){ }
          1. 从话题复制图像
            cv::Mat camera_data = cv_bridge::toCvCopy(image_msg, "bgr8")->image;
          2. 提取检测结果回调函数
            FUNP_D detection_result_callback = boost::bind(&NCSImpl::cbGetDetectionResult, this, _1, _2);
          3. 进行目标检测 
            ncs_manager_handle_->detectStream(camera_data, detection_result_callback, image_msg);
          NCSManager::detectStream(){}
          得到检测结果 : movidius_ncs_lib::DetectionResultPtr result;
          检测结果:
           for (auto item : result->items_in_boxes)
            object_msgs::ObjectInBox obj;
            obj.object.object_name = item.item.category;
            obj.object.probability = item.item.probability;
            obj.roi.x_offset = item.bbox.x;
            obj.roi.y_offset = item.bbox.y;
            obj.roi.width = item.bbox.width;
            obj.roi.height = item.bbox.height;
            objs_in_boxes.objects_vector.push_back(obj);
         发布检测结果:  
            objs_in_boxes.header = header;
            objs_in_boxes.inference_time_ms = result->time_taken;
            pub_.publish(objs_in_boxes);
    

    视觉控制结合视觉处理和运动控制

     关注两个应用 : 
    	 目标跟踪object tracking  和 
    	 人体跟踪(跟随) person following
    
    坐标系:
    	相机坐标系
    	右手坐标系
    	相机正前方为 z轴正方向
    	水平方向为 x轴
    	垂直方向为 y轴
    

    1. 目标跟踪object tracking

    上面 使用 opencv 跟踪 面部 关键点 和 颜色 
    跟踪的结果为 目标在 图像中的区域 ROI region of interest 感兴趣区域
    被发布在 ROS话题 /roi 上,如果相机安装在一个移动地盘上
    
    我们可以使用 ROI 的 x_offset 水平坐标偏置(相对于整个图像)
    我们可以旋转 移动底盘保证 ROI 的 x_offset位于图像的水平正中央
    (偏左 向左旋转,逆时针; 偏右 向右旋转,顺时针)
    如果相机加入垂直方向舵机 还可以 旋转舵机 使得 ROI 的 y_offset
    位于 图像的垂直 正中央
    
    还可以使用 roi区域对应的深度信息 控制 移动底盘 前进后者后退
    
    深度较大 前进
    深度较小 后退
    
    保持深度值在一个固定的值
    

    关键程序: rbx1_apps/nodes/object_tracker.py

    1) 先启动一个深度摄像头或者 普通相机
    深度摄像头 1 Microsoft Kinect:
    $ roslaunch freenect_launch freenect-registered-xyzrgb.launch

    深度摄像头 2华硕 Asus Xtion, Xtion Pro, or Primesense 1.08/1.09 cameras:
    $ roslaunch openni2_launch openni2.launch depth_registration:=true
    
    webcam  :
    $ roslaunch rbx1_vision usb_cam.launch video_device:=/dev/video0
    

    2)启动脸部追踪节点
    roslaunch rbx1_vision face_tracker2.launch
    运行了节点 /rbx1_vision/node/face_tracker2.py

    3)启动目标追踪节点
    roslaunch rbx1_apps object_tracker.launch
    运行了节点 /rbx1_apps/nodes/object_tracker.py

    4)使用 rqt_plot 显示 脸部 位置 和 移动速度信息
    rqt_plot /cmd_vel/angular/z

    5)仿真环境下测试跟踪效果

    $ roslaunch rbx1_bringup fake_turtlebot.launch
    $ rosrun rviz rviz -d `rospack find rbx1_nav`/sim.rviz
    移动脸部 , turtlebot会旋转
    

    6)代码分析 /rbx1_apps/nodes/object_tracker.py

    #!/usr/bin/env python 
    import rospy
    from sensor_msgs.msg import RegionOfInterest, CameraInfo
    from geometry_msgs.msg import Twist
    import thread
    
    class ObjectTracker():
        def __init__(self):
            rospy.init_node("object_tracker")
                    
            # 节点关闭 Set the shutdown function (stop the robot)
            rospy.on_shutdown(self.shutdown)
            
            # 更新频率 How often should we update the robot's motion?
            self.rate = rospy.get_param("~rate", 10)
            r = rospy.Rate(self.rate) 
            
            # 移动底盘最大旋转速度 The maximum rotation speed in radians per second
            self.max_rotation_speed = rospy.get_param("~max_rotation_speed", 2.0)
            
            # 移动底盘最小旋转速度 The minimum rotation speed in radians per second
            self.min_rotation_speed = rospy.get_param("~min_rotation_speed", 0.5)
            
            # Sensitivity to target displacements.  Setting this too high
            # can lead to oscillations of the robot.
            self.gain = rospy.get_param("~gain", 2.0) # 灵敏度,增益 相当于一个比例控制器 
            
            # The x threshold (% of image width) indicates how far off-center
            # the ROI needs to be in the x-direction before we react
            self.x_threshold = rospy.get_param("~x_threshold", 0.1) # 偏移阈值
    
            # Publisher to control the robot's movement  发布运动信息控制指令
            self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)
            
            # Intialize the movement command
            self.move_cmd = Twist() # 初始化 运动信息控制指令
            
            # Get a lock for updating the self.move_cmd values
            self.lock = thread.allocate_lock() # 线程上锁
            
            # We will get the image width and height from the camera_info topic
            self.image_width = 0
            self.image_height = 0
            
            # Set flag to indicate when the ROI stops updating
            self.target_visible = False
            
            # Wait for the camera_info topic to become available 等待
            rospy.loginfo("Waiting for camera_info topic...")
            rospy.wait_for_message('camera_info', CameraInfo)
            
            #订阅话题,获取相机图像信息 Subscribe the camera_info topic to get the image width and height
            rospy.Subscriber('camera_info', CameraInfo, self.get_camera_info, queue_size=1)
    
            # 等待相机工作正常 Wait until we actually have the camera data
            while self.image_width == 0 or self.image_height == 0:
                rospy.sleep(1)
                        
            # 订阅ROI话题 Subscribe to the ROI topic and set the callback to update the robot's motion
    	# 回调函数为 set_cmd_ve()
            rospy.Subscriber('roi', RegionOfInterest, self.set_cmd_vel, queue_size=1)
            
            # 等待ROI信息 Wait until we have an ROI to follow
            rospy.loginfo("Waiting for messages on /roi...")
            rospy.wait_for_message('roi', RegionOfInterest)
            
            rospy.loginfo("ROI messages detected. Starting tracker...")
            
            # 开始跟踪循环====
            while not rospy.is_shutdown():
                # Acquire a lock while we're setting the robot speeds
                self.lock.acquire() # 多线程锁
                
                try:
                    # If the target is not visible, stop the robot
                    if not self.target_visible:
                        self.move_cmd = Twist()# 视野中未看到目标,不动
                    else:
                        # Reset the flag to False by default
                        self.target_visible = False
                        
                    # Send the Twist command to the robot
                    self.cmd_vel_pub.publish(self.move_cmd)# 发布运动指令
                    
                finally:
                    # Release the lock
                    self.lock.release()
                    
                # Sleep for 1/self.rate seconds
                r.sleep()
    	    
        #  订阅ROI话题  的回调函数=================
        def set_cmd_vel(self, msg):
            # Acquire a lock while we're setting the robot speeds
            self.lock.acquire()
            
            try:
                # If the ROI has a width or height of 0, we have lost the target
                if msg.width == 0 or msg.height == 0:
                    self.target_visible = False # 目标不可见
                    return
                
                # If the ROI stops updating this next statement will not happen
                self.target_visible = True # 目标可见
        
                # Compute the displacement of the ROI from the center of the image
    	    # roi 中心 和 图像 中心的 水平方向偏移量=======================
                target_offset_x = msg.x_offset + msg.width / 2 - self.image_width / 2
                
    	    # 计算一个偏移比例=============
                try:
                    percent_offset_x = float(target_offset_x) / (float(self.image_width) / 2.0)
                except:
                    percent_offset_x = 0
        
                # Rotate the robot only if the displacement of the target exceeds the threshold
    	    # 直到 偏移比例 小于阈值=====
                if abs(percent_offset_x) > self.x_threshold:
                    # Set the rotation speed proportional to the displacement of the target
                    try:
                        speed = self.gain * percent_offset_x # 相当于一个比例控制器 
                        if speed < 0:
                            direction = -1  方向
                        else:
                            direction = 1
    		    # 旋转角速度
                        self.move_cmd.angular.z = -direction * max(self.min_rotation_speed,
                                                    min(self.max_rotation_speed, abs(speed)))
                    except:
                        self.move_cmd = Twist()
                else:
                    # Otherwise stop the robot
                    self.move_cmd = Twist()
    
            finally:
                # Release the lock
                self.lock.release()
    
        def get_camera_info(self, msg):
            self.image_width = msg.width
            self.image_height = msg.height
    
        def shutdown(self):
            rospy.loginfo("Stopping the robot...")
            self.cmd_vel_pub.publish(Twist())
            rospy.sleep(1)     
    
    if __name__ == '__main__':
        try:
            ObjectTracker()
            rospy.spin()
        except rospy.ROSInterruptException:
            rospy.loginfo("Object tracking node terminated.")
    

    2.目标跟随, 在目标跟踪上 引入深度信息 可旋转 前进 后退

    可以使用 face tracker, CamShift or LK tracker 节点 发现目标
    
    在 rbx1_apps/nodes/object_follower.py 
    
    /roi 话题 获取 目标 水平 和 垂直方向 的位置  让相机正对着 目标中央
    
    /camera/depth_registered/image_rect 深度图 话题 
        消息类型 sensor_msgs/Image  深度单位 mm毫米 除以1000 得到米m
        回调函数 使用 cv_bridge 将深度图 转换成 数组 可以计算 ROI区域的均值
    还可以使用 pcl 点运数据
    
    
    计算 roi 区域 的平均深度 来反应 目标物体 在 相机前方的距离 
    通过使移动底盘 前进、后退 保持一个给定的距离  (注意相机 和 底盘的安装 位置)
    

    6)代码分析

    /rbx1_apps/nodes/object_follower.py

    #!/usr/bin/env python
    import rospy
    from sensor_msgs.msg import Image, RegionOfInterest, CameraInfo
    from geometry_msgs.msg import Twist
    from math import copysign, isnan
    from cv2 import cv as cv
    from cv_bridge import CvBridge, CvBridgeError
    import numpy as np
    import thread
    
    class ObjectFollower():
        def __init__(self):
    	# 节点初始化
            rospy.init_node("object_follower")
                            
            # 节点关闭 析构函数 清理 Set the shutdown function (stop the robot)
            rospy.on_shutdown(self.shutdown)
            
            # How often should we update the robot's motion?
            self.rate = rospy.get_param("~rate", 10)
            
            r = rospy.Rate(self.rate)
            
            # 感兴趣区域 Scale the ROI by this factor to avoid background distance values around the edges
            self.scale_roi = rospy.get_param("~scale_roi", 0.9)
            
            # The max linear speed in meters per second
            self.max_linear_speed = rospy.get_param("~max_linear_speed", 0.3)
            
            # The minimum linear speed in meters per second
            self.min_linear_speed = rospy.get_param("~min_linear_speed", 0.02) 
            
            # The maximum rotation speed in radians per second
            self.max_rotation_speed = rospy.get_param("~max_rotation_speed", 2.0)
            
            # The minimum rotation speed in radians per second
            self.min_rotation_speed = rospy.get_param("~min_rotation_speed", 0.5)
            
            # The x threshold (% of image width) indicates how far off-center
            # the ROI needs to be in the x-direction before we react
            self.x_threshold = rospy.get_param("~x_threshold", 0.1)
            
            # How far away from the goal distance (in meters) before the robot reacts
            self.z_threshold = rospy.get_param("~z_threshold", 0.05)
            
            # The maximum distance a target can be from the robot for us to track
            self.max_z = rospy.get_param("~max_z", 1.6)
    
            # The minimum distance to respond to
            self.min_z = rospy.get_param("~min_z", 0.5)
            
            # The goal distance (in meters) to keep between the robot and the person
            self.goal_z = rospy.get_param("~goal_z", 0.75)
    
            # How much do we weight the goal distance (z) when making a movement
            self.z_scale = rospy.get_param("~z_scale", 0.5)
    
            # How much do we weight (left/right) of the person when making a movement        
            self.x_scale = rospy.get_param("~x_scale", 2.0)
            
            # Slow down factor when stopping
            self.slow_down_factor = rospy.get_param("~slow_down_factor", 0.8)
            
            # Initialize the global ROI
            self.roi = RegionOfInterest()
    
            # Publisher to control the robot's movement
            self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)
            
            # Intialize the movement command
            self.move_cmd = Twist()
            
            # Get a lock for updating the self.move_cmd values
            self.lock = thread.allocate_lock()
            
            # We will get the image width and height from the camera_info topic
            self.image_width = 0
            self.image_height = 0
            
            # We need cv_bridge to convert the ROS depth image to an OpenCV array
            self.cv_bridge = CvBridge()
            self.depth_array = None
            
            # Set flag to indicate when the ROI stops updating
            self.target_visible = False
            
            # Wait for the camera_info topic to become available
            rospy.loginfo("Waiting for camera_info topic...")
            
            rospy.wait_for_message('camera_info', CameraInfo)
            
            # Subscribe to the camera_info topic to get the image width and height
            rospy.Subscriber('camera_info', CameraInfo, self.get_camera_info, queue_size=1)
    
            # Wait until we actually have the camera data
            while self.image_width == 0 or self.image_height == 0:
                rospy.sleep(1)
                
            # Wait for the depth image to become available
            rospy.loginfo("Waiting for depth_image topic...")
            
            rospy.wait_for_message('depth_image', Image)
                        
            # Subscribe to the depth image
    	# 订阅深度图 话题 回调函数  convert_depth_image() 深度数据/1000 转换成 数组
    	# 话题名  在 launch 里 需要remap 重映射  
            self.depth_subscriber = rospy.Subscriber("depth_image", Image, self.convert_depth_image, queue_size=1)
            
            # Subscribe to the ROI topic and set the callback to update the robot's motion
            rospy.Subscriber('roi', RegionOfInterest, self.set_cmd_vel, queue_size=1)
            
            # Wait until we have an ROI to follow
            rospy.loginfo("Waiting for an ROI to track...")
            
            rospy.wait_for_message('roi', RegionOfInterest)
            
            rospy.loginfo("ROI messages detected. Starting follower...")
            
            # Begin the tracking loop
            while not rospy.is_shutdown():
                # Acquire a lock while we're setting the robot speeds
                self.lock.acquire()
                
                try:
                    if not self.target_visible:
                        # If the target is not visible, stop the robot smoothly
                        self.move_cmd.linear.x *= self.slow_down_factor
                        self.move_cmd.angular.z *= self.slow_down_factor
                    else:
                        # Reset the flag to False by default
                        self.target_visible = False
                        
                    # Send the Twist command to the robot
                    self.cmd_vel_pub.publish(self.move_cmd)
                        
                finally:
                    # Release the lock
                    self.lock.release()
                
                # Sleep for 1/self.rate seconds
                r.sleep()
        
       # 利用  ROI消息 和 深度数据  转换到 速度指令                     
        def set_cmd_vel(self, msg):
            # Acquire a lock while we're setting the robot speeds
            self.lock.acquire()
            
            try:
                # If the ROI has a width or height of 0, we have lost the target
                if msg.width == 0 or msg.height == 0:
                    self.target_visible = False
                    return
                else:
                    self.target_visible = True
        
                self.roi = msg
                            
                # Compute the displacement of the ROI from the center of the image
    	    # 原来 图像中心点 self.image_width / 2 水平方向
                # 目标区域 中心点 = 起点 + roi宽度  = msg.x_offset + msg.width / 2
    	    # 两者之差 为 目标 偏离相机中心为插值 
                target_offset_x = msg.x_offset + msg.width / 2 - self.image_width / 2
        
                try:
                    percent_offset_x = float(target_offset_x) / (float(self.image_width) / 2.0)
                except:
                    percent_offset_x = 0
                                                
                # Rotate the robot only if the displacement of the target exceeds the threshold
                if abs(percent_offset_x) > self.x_threshold: #设置阈值
                    # Set the rotation speed proportional to the displacement of the target
                    speed = percent_offset_x * self.x_scale
                    self.move_cmd.angular.z = -copysign(max(self.min_rotation_speed,
                                                min(self.max_rotation_speed, abs(speed))), speed)
                else:
                    self.move_cmd.angular.z = 0
                 
    	    # 计算目标 深度信息   
                # Now compute the depth component
                
                # Initialize a few depth variables
                n_z = sum_z = mean_z = 0
                 
                # Shrink the ROI slightly to avoid the target boundaries
    	    # 缩小 roi范围 精准  滤出边缘背景点 因子 0.9  roi是长方形 物体形状不规则
                scaled_width = int(self.roi.width * self.scale_roi)
                scaled_height = int(self.roi.height * self.scale_roi)
                # ROI像素坐标范围
                # Get the min/max x and y values from the scaled ROI
                min_x = int(self.roi.x_offset + self.roi.width * (1.0 - self.scale_roi) / 2.0)
                max_x = min_x + scaled_width
                min_y = int(self.roi.y_offset + self.roi.height * (1.0 - self.scale_roi) / 2.0)
                max_y = min_y + scaled_height
                # 得到 ROI区域深度信息 的均值
                # Get the average depth value over the ROI
                for x in range(min_x, max_x):
                    for y in range(min_y, max_y):
                        try:
                            # Get a depth value in meters
                            z = self.depth_array[y, x] #对应坐标的深度值
                            
                            # Check for NaN values returned by the camera driver
                            if isnan(z):# 验证是否存在
                                continue
                                                       
                        except:
                            # It seems to work best if we convert exceptions to 0
                            z = 0
                            
                        # A hack to convert millimeters to meters for the freenect driver
    		    # 毫米转换到 米m
                        if z > 100:
                            z /= 1000.0
                            
                        # Check for values outside max range
                        if z > self.max_z: #滤除 异常值
                            continue
                        
                        # Increment the sum and count
                        sum_z = sum_z + z # 深度值 纸盒
                        n_z += 1# 深度值 点数计数 用来计算均值 
                        
                # Stop the robot's forward/backward motion by default
                linear_x = 0 # 先停止前进后退 
                
                # If we have depth values...
                if n_z:#有记录到 有效的点
                    mean_z = float(sum_z) / n_z #深度均值
                                                                                                    
                    # Don't let the mean fall below the minimum reliable range
                    mean_z = max(self.min_z, mean_z)# 最小距离限制
                                                            
                    # Check the mean against the minimum range
                    if mean_z > self.min_z:
                        # Check the max range and goal threshold
    		    # 均值深度 在最小值和最大值之间 并且 均值深度值和 目标深度差值超过阈值  
                        # 向前向后移动
                        if mean_z < self.max_z and (abs(mean_z - self.goal_z) > self.z_threshold):
                            speed = (mean_z - self.goal_z) * self.z_scale
                            linear_x = copysign(min(self.max_linear_speed, max(self.min_linear_speed, abs(speed))), speed)
        
                if linear_x == 0:
                    # Stop the robot smoothly
                    self.move_cmd.linear.x *= self.slow_down_factor
                else:
                    self.move_cmd.linear.x = linear_x
            
            finally:
                # Release the lock
                self.lock.release()#释放进程锁
    
        # 深度图 话题 订阅 的回调函数  用cv_bridge 转换 深度图 到 深度数据数组
        def convert_depth_image(self, ros_image):
            # Use cv_bridge() to convert the ROS image to OpenCV format
            try:
                # Convert the depth image using the default passthrough encoding
      	    # 转换	     
                depth_image = self.cv_bridge.imgmsg_to_cv2(ros_image, "passthrough")
            except CvBridgeError, e:
                print e
    
            # Convert the depth image to a Numpy array
            self.depth_array = np.array(depth_image, dtype=np.float32)
    
        def get_camera_info(self, msg):
            self.image_width = msg.width
            self.image_height = msg.height
    
        def shutdown(self):
            rospy.loginfo("Stopping the robot...")
            # Unregister the subscriber to stop cmd_vel publishing
            self.depth_subscriber.unregister()
            rospy.sleep(1)
            # Send an emtpy Twist message to stop the robot
            self.cmd_vel_pub.publish(Twist())
            rospy.sleep(1)      
    
    if __name__ == '__main__':
        try:
            ObjectFollower()
            rospy.spin()
        except rospy.ROSInterruptException:
            rospy.loginfo("Object follower node terminated.")
    
    

    运行

    1)传感器

    深度摄像头 1 Microsoft Kinect:
    $ roslaunch freenect_launch freenect-registered-xyzrgb.launch
    
    深度摄像头 2华硕 Asus Xtion, Xtion Pro, or Primesense 1.08/1.09 cameras:
    $ roslaunch openni2_launch openni2.launch depth_registration:=true
    
    双面摄像头获取深度
    可编写
    

    2)启动脸部追踪节点

    roslaunch rbx1_vision face_tracker2.launch
    运行了节点 /rbx1_vision/node/face_tracker2.py
    或者 颜色 追踪 roslaunch rbx1_vision camshift.launch 鼠标框选 有颜色的物体
    或者 特征点 光流法追踪 roslaunch rbx1_vision lk_tracker.launch 鼠标框选 任意有结构纹理角点线的物体

    3)启动目标跟随节点

    roslaunch rbx1_apps object_follower.launch     
    运行了节点  /rbx1_apps/nodes/object_flower.py
    

    4)使用 rqt_plot 显示 脸部 位置 和 移动速度信息

    rqt_plot /cmd_vel/angular/z
    

    5)仿真环境下测试跟踪效果

    $ roslaunch rbx1_bringup fake_turtlebot.launch
    $ rosrun rviz rviz -d `rospack find rbx1_nav`/sim.rviz
    移动脸部 / 有颜色物体 , turtlebot会旋转
    
    走进 机器人退后  离开机器人跟随
    
    深度距离object_follower.launch默认 0.7 米 可修改
    

    3. 人体跟随 使用 PCL点运数据

    ROS sensor_msgs 包 定义了一个类  PointCloud2 消息类型
    和一个 point_cloud2.py 模块 由 点云数据 获取 深度 
    
    我们不知道 人体的确切形状 但是可是 找一个像人一样的 团块 距离相机 坐标系 一定距离的 空间范围内的点 
    避免认错 家具的一部分 椅子腿 
    
    对于深度相机 z轴 代表了深度信息 里人体的远近 
     1】 太远 前进  太近 后退
     2】 靠左 左转  靠右 右转
    

    /rbx1_apps/nodes/follower.py

    代码分析

    #!/usr/bin/env python
    
    import rospy
    from roslib import message
    from sensor_msgs import point_cloud2
    from sensor_msgs.msg import PointCloud2
    from geometry_msgs.msg import Twist
    from math import copysign
    
    class Follower():
        def __init__(self):
            # 节点初始化
            rospy.init_node("follower")
            
            # 节点关闭 清理内存 Set the shutdown function (stop the robot)
            rospy.on_shutdown(self.shutdown)
            
            # The dimensions (in meters) of the box in which we will search
            # for the person (blob). These are given in camera coordinates
            # where x is left/right,y is up/down and z is depth (forward/backward)
            # 近似 人体的 参数
    	# 人体点在空间 相对于 移动底盘的 空间坐标点集 范围  所有的点云在这个范围内的 认为是人体的点 
            self.min_x = rospy.get_param("~min_x", -0.2)
            self.max_x = rospy.get_param("~max_x", 0.2)
            self.min_y = rospy.get_param("~min_y", -0.3)
            self.max_y = rospy.get_param("~max_y", 0.5)
            self.max_z = rospy.get_param("~max_z", 1.2)
            
            # The goal distance (in meters) to keep between the robot and the person
            self.goal_z = rospy.get_param("~goal_z", 0.6)
            
            # How far away from the goal distance (in meters) before the robot reacts
            self.z_threshold = rospy.get_param("~z_threshold", 0.05)
            
            # How far away from being centered (x displacement) on the person
            # before the robot reacts
            self.x_threshold = rospy.get_param("~x_threshold", 0.05)
            
            # 深度差值 转出 前进后退运动速度 权重 How much do we weight the goal distance (z) when making a movement
            self.z_scale = rospy.get_param("~z_scale", 1.0)
    
            # 水平差值 转成旋转运动速度 权重  How much do we weight left/right displacement of the person when making a movement        
            self.x_scale = rospy.get_param("~x_scale", 2.5)
            
            # The maximum rotation speed in radians per second
            self.max_angular_speed = rospy.get_param("~max_angular_speed", 2.0)
            
            # The minimum rotation speed in radians per second
            self.min_angular_speed = rospy.get_param("~min_angular_speed", 0.0)
            
            # The max linear speed in meters per second
            self.max_linear_speed = rospy.get_param("~max_linear_speed", 0.3)
            
            # The minimum linear speed in meters per second
            self.min_linear_speed = rospy.get_param("~min_linear_speed", 0.1)
            
            # Slow down factor when stopping
            self.slow_down_factor = rospy.get_param("~slow_down_factor", 0.8)
            
            # Initialize the movement command
            self.move_cmd = Twist()
    
            # 发布 控制质量 消息话题 Publisher to control the robot's movement
            self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)
    
            # 订阅点云数据 回调函数 set_cmd_vel()  Subscribe to the point cloud
            self.depth_subscriber = rospy.Subscriber('point_cloud', PointCloud2, self.set_cmd_vel, queue_size=1)
    
            rospy.loginfo("Subscribing to point cloud...")
            
            # Wait for the pointcloud topic to become available
            rospy.wait_for_message('point_cloud', PointCloud2)
    
            rospy.loginfo("Ready to follow!")
            
        def set_cmd_vel(self, msg):
            # Initialize the centroid coordinates point count
            x = y = z = n = 0
    
            # Read in the x, y, z coordinates of all points in the cloud
            for point in point_cloud2.read_points(msg, skip_nans=True):#遍历 所有的三维 点云数据
                pt_x = point[0]
                pt_y = point[1]
                pt_z = point[2]
                
                # Keep only those points within our designated boundaries and sum them up
    	    # 在相对相机 特定范围内的点 认为是 人体 点
                if -pt_y > self.min_y and -pt_y < self.max_y and pt_x < self.max_x and pt_x > self.min_x and pt_z < self.max_z:
                    x += pt_x # 所有人体点 哥哥坐标值 求和取均值
                    y += pt_y
                    z += pt_z
                    n += 1
            
           # If we have points, compute the centroid coordinates
           # 计算 点云坐标 均值
            if n:
                x /= n 
                y /= n 
                z /= n
                
                # Check our movement thresholds
                # 深度距离差值 超过最小值阈值 进行 前进/后退 移动
                if (abs(z - self.goal_z) > self.z_threshold):
                    # Compute the angular component of the movement
                    linear_speed = (z - self.goal_z) * self.z_scale # 乘上 权重系数
                    
                    # Make sure we meet our min/max specifications
                    self.move_cmd.linear.x = copysign(max(self.min_linear_speed, 
                                            min(self.max_linear_speed, abs(linear_speed))), linear_speed)
                else:
                    self.move_cmd.linear.x *= self.slow_down_factor # 线速度 缓慢  减速  
                    
                if (abs(x) > self.x_threshold): # x值为水平方向 x=0 为相机光心 坐标值 过大 就偏转了 
                    # Compute the linear component of the movement
                    angular_speed = -x * self.x_scale
                    
                    # Make sure we meet our min/max specifications
                    # 最小最大角速度 限制
                    self.move_cmd.angular.z = copysign(max(self.min_angular_speed, 
                                            min(self.max_angular_speed, abs(angular_speed))), angular_speed)
                else:
                    # Stop the rotation smoothly
                    self.move_cmd.angular.z *= self.slow_down_factor # 角速度 缓慢减速
                    
            else: #未找到 人体点 
                # Stop the robot smoothly 缓慢减速
                self.move_cmd.linear.x *= self.slow_down_factor
                self.move_cmd.angular.z *= self.slow_down_factor
                
            # Publish the movement command
            self.cmd_vel_pub.publish(self.move_cmd)
    
            
        def shutdown(self):
            rospy.loginfo("Stopping the robot...")
            
            # Unregister the subscriber to stop cmd_vel publishing
            self.depth_subscriber.unregister()
            rospy.sleep(1)
            
            # Send an emtpy Twist message to stop the robot
            self.cmd_vel_pub.publish(Twist())
            rospy.sleep(1)        
                       
    if __name__ == '__main__':
        try:
            Follower()
            rospy.spin()
        except rospy.ROSInterruptException:
            rospy.loginfo("Follower node terminated.")
    

    实验

    1)传感器

    深度摄像头 1 Microsoft Kinect:
    $ roslaunch freenect_launch freenect-registered-xyzrgb.launch
    
    深度摄像头 2华硕 Asus Xtion, Xtion Pro, or Primesense 1.08/1.09 cameras:
    $ roslaunch openni2_launch openni2.launch depth_registration:=true
    
    双面摄像头获取深度
    可编写
    

    2)启动 人体跟随节点

    roslaunch rbx1_apps  follower.py
    

    5)仿真环境下测试 人体 跟踪效果

    $ roslaunch rbx1_bringup fake_turtlebot.launch
    $ rosrun rviz rviz -d `rospack find rbx1_nav`/sim.rviz
    走进 机器人退后  离开机器人跟随
    深度距离object_follower.launch默认 0.7 米 可修改
    

    在这里插入图片描述

    展开全文
  • 通过电话号码或CNIC跟踪人们到家庭住址。 仅在巴基斯坦有效,并且需要有效的互联网连接。 -在Android和Windows上可用-电话数据库版本为2011年及以前,因此不要指望新数字-对于您对收到的信息所做的处理,我不承担...
  • 可以在此处找到示例数据: https://www.dropbox.com/s/4iun8ztwguwkms7/TrackingEx.zip?dl=0 跟踪示例可应用于其他视频输入数据,但可能需要调整阈值 (th = 0.1490;) 和初始化卡尔曼滤波器参数 (R、H、Q、P)。 ...
  • 可以在此处找到添加的所有新功能的详细信息: : 已知的问题 iOS背景的“联系人跟踪”不起作用。 目录 开发环境设置 遵循《 ,并确保选择“ React Native CLI快速入门”选项卡。 注意:需要Mac才能将应用程序构建到...
  • 人脸跟踪:简单跟踪

    千次阅读 2018-03-23 21:59:16
    研究的很多,近几年也出现了很多很多的算法。大家看看淋漓满目的paper就知道了。但在这里,我们也聚焦下比较简单的算法,看看它的优势在哪里。毕竟有时候简单就是一种美。 在这里我们一起来欣赏下“模板匹配”这...

    一、概述

           目标跟踪是计算机视觉领域的一个重要分支。研究的人很多,近几年也出现了很多很多的算法。大家看看淋漓满目的paper就知道了。但在这里,我们也聚焦下比较简单的算法,看看它的优势在哪里。毕竟有时候简单就是一种美。

           在这里我们一起来欣赏下“模板匹配”这个简单点的跟踪算法。它的思想很简单,我们把要跟踪的目标保存好,然后在每一帧来临的时候,我们在整个图像中寻找与这个目标最相似的,我们就相信这个就是目标了。那如何判断相似呢?就用到了一些相关性的东西了,这个在我之前的一篇博文里面介绍过,大家可以参考下:

           模板匹配中差值的平方和(SSD)与互相关准则的关系

    http://blog.csdn.net/zouxy09/article/details/8549743

           然后为了适应目标的变化,我们就需要随时更新我们要跟踪的目标。换句话来说,在跟踪t帧的时候,也就是在第t帧寻找目标的时候,是与t-1帧中我们找到的目标来进行比较的。这样目标的外观变化就会及时的更新。这个就叫做在线跟踪方法。当然了,这个策略会导致跟踪漂移的问题,这就是近几年很多跟踪算法关注的重要问题之一了。

     

    二、代码实现

           我的代码是基于VS2010+ OpenCV2.4.2的。代码可以读入视频,也可以读摄像头,两者的选择只需要在代码中稍微修改即可。对于视频来说,运行会先显示第一帧,然后我们用鼠标框选要跟踪的目标,然后跟踪器开始跟踪每一帧。对摄像头来说,就会一直采集图像,然后我们用鼠标框选要跟踪的目标,接着跟踪器开始跟踪后面的每一帧。具体代码如下:

    simpleTracker.cpp

     

    [cpp]  view plaincopy
    1. // Object tracking algorithm using matchTemplate  
    2. // Author : zouxy  
    3. // Date   : 2013-10-28  
    4. // HomePage : http://blog.csdn.net/zouxy09  
    5. // Email  : zouxy09@qq.com  
    6.   
    7. #include <opencv2/opencv.hpp>  
    8.   
    9. using namespace cv;  
    10. using namespace std;  
    11.   
    12. // Global variables  
    13. Rect box;  
    14. bool drawing_box = false;  
    15. bool gotBB = false;  
    16.   
    17. // bounding box mouse callback  
    18. void mouseHandler(int event, int x, int y, int flags, void *param){  
    19.   switch( event ){  
    20.   case CV_EVENT_MOUSEMOVE:  
    21.     if (drawing_box){  
    22.         box.width = x-box.x;  
    23.         box.height = y-box.y;  
    24.     }  
    25.     break;  
    26.   case CV_EVENT_LBUTTONDOWN:  
    27.     drawing_box = true;  
    28.     box = Rect( x, y, 0, 0 );  
    29.     break;  
    30.   case CV_EVENT_LBUTTONUP:  
    31.     drawing_box = false;  
    32.     if( box.width < 0 ){  
    33.         box.x += box.width;  
    34.         box.width *= -1;  
    35.     }  
    36.     if( box.height < 0 ){  
    37.         box.y += box.height;  
    38.         box.height *= -1;  
    39.     }  
    40.     gotBB = true;  
    41.     break;  
    42.   }  
    43. }  
    44.   
    45.   
    46. // tracker: get search patches around the last tracking box,  
    47. // and find the most similar one  
    48. void tracking(Mat frame, Mat &model, Rect &trackBox)  
    49. {  
    50.     Mat gray;  
    51.     cvtColor(frame, gray, CV_RGB2GRAY);  
    52.   
    53.     Rect searchWindow;  
    54.     searchWindow.width = trackBox.width * 3;  
    55.     searchWindow.height = trackBox.height * 3;  
    56.     searchWindow.x = trackBox.x + trackBox.width * 0.5 - searchWindow.width * 0.5;  
    57.     searchWindow.y = trackBox.y + trackBox.height * 0.5 - searchWindow.height * 0.5;  
    58.     searchWindow &= Rect(0, 0, frame.cols, frame.rows);  
    59.   
    60.     Mat similarity;  
    61.     matchTemplate(gray(searchWindow), model, similarity, CV_TM_CCOEFF_NORMED);   
    62.   
    63.     double mag_r;  
    64.     Point point;  
    65.     minMaxLoc(similarity, 0, &mag_r, 0, &point);  
    66.     trackBox.x = point.x + searchWindow.x;  
    67.     trackBox.y = point.y + searchWindow.y;  
    68.     model = gray(trackBox);  
    69. }  
    70.   
    71. int main(int argc, char * argv[])  
    72. {  
    73.     VideoCapture capture;  
    74.     capture.open("david.mpg");  
    75.     bool fromfile = true;  
    76.     //Init camera  
    77.     if (!capture.isOpened())  
    78.     {  
    79.         cout << "capture device failed to open!" << endl;  
    80.         return -1;  
    81.     }  
    82.     //Register mouse callback to draw the bounding box  
    83.     cvNamedWindow("Tracker", CV_WINDOW_AUTOSIZE);  
    84.     cvSetMouseCallback("Tracker", mouseHandler, NULL );   
    85.   
    86.     Mat frame, model;  
    87.     capture >> frame;  
    88.     while(!gotBB)  
    89.     {  
    90.         if (!fromfile)  
    91.             capture >> frame;  
    92.   
    93.         imshow("Tracker", frame);  
    94.         if (cvWaitKey(20) == 'q')  
    95.             return 1;  
    96.     }  
    97.     //Remove callback  
    98.     cvSetMouseCallback("Tracker", NULL, NULL );   
    99.       
    100.     Mat gray;  
    101.     cvtColor(frame, gray, CV_RGB2GRAY);   
    102.     model = gray(box);  
    103.   
    104.     int frameCount = 0;  
    105.   
    106.     while (1)  
    107.     {  
    108.         capture >> frame;  
    109.         if (frame.empty())  
    110.             return -1;  
    111.         double t = (double)cvGetTickCount();  
    112.         frameCount++;  
    113.   
    114.         // tracking  
    115.         tracking(frame, model, box);      
    116.   
    117.         // show  
    118.         stringstream buf;  
    119.         buf << frameCount;  
    120.         string num = buf.str();  
    121.         putText(frame, num, Point(20, 20), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 3);  
    122.         rectangle(frame, box, Scalar(0, 0, 255), 3);  
    123.         imshow("Tracker", frame);  
    124.   
    125.   
    126.         t = (double)cvGetTickCount() - t;  
    127.         cout << "cost time: " << t / ((double)cvGetTickFrequency()*1000.) << endl;  
    128.   
    129.         if ( cvWaitKey(1) == 27 )  
    130.             break;  
    131.     }  
    132.   
    133.     return
    展开全文
  • 目标跟踪

    千次阅读 2019-11-27 19:54:52
    本篇是基于单目标跟踪的论述 目标跟踪概述 1.1 定义: 1,单目标,即在给定的视频中只跟踪一个目标 2,在第一帧中会通过矩形的bounding box将目标给出。给定后,使用tracker找出每一帧的目标。 3,短期 ...

    本篇是基于单目标跟踪的论述 

    目标跟踪概述

              1.1 定义:

                    1,单目标,即在给定的视频中只跟踪一个目标

                    2,在第一帧中会通过矩形的bounding box将目标给出。给定后,使用tracker找出每一帧的目标。

                    3,短期

              1.2 目标跟踪面临的挑战有:

                    1,运动模糊(Motion Blur)

                          

                          在获取视频时由于环境因素,相机抖动或物体运动等多种因素的影响,导致获取的视频帧像素退化,这种退化会导致角点,边缘等显著特征受损甚至消失。一般存在两种情况,当点扩散函数处于未知状态时,叫做盲去模糊,当点扩散函数已知时叫做非盲去模糊。

                    2,遮挡(Occlusion)

                         

                         遮挡是目标跟踪中比较常见的挑战因素。遮挡又分为部分遮挡(Partial Occlusion)和完全遮挡(Full Occlusion)。解决部分遮挡目前较为常用的大致有两种思路:(1)利用检测机制判断目标是否被遮挡,从而决定是否更新模板,保证模板对遮挡的鲁棒性。(2)把目标分成多个块,利用没有被遮挡的块进行有效的跟踪。而对于完全遮挡目前并没有特别好的办法完全解决这个问题。

                    3,形变(Deformation)(与第一帧差异过大)

                          

                          通常而言跟踪的目标并非一层不变的。而跟踪目标的形变,如果过大则会导致跟踪发生漂移(Drift)。而解决这个挑战的主要解决点就在解决漂移问题。常用的方法是更新目标的表观模型,使其适应表观的变化。因此面对这个问题时,至关重要的是模型更新方法。能否及时,准时更新,能否确定好更新的频率变成面对这个挑战时要关注的问题。

                    4,尺度变化(Changing In Scale)(镜头的拉近或拉远)

                          

                          尺度变换是指目标在运动过程中距离拍摄的镜头距离的变化而产生的尺度大小的变化现象。由于尺度变换如果不能快速准确的预测出跟踪目标变化的系数就会影响跟踪的准确率。现在通常的做法有:(1)在运动模型产生候选样本的时候,生成大量的尺度大小不等的候选框,选择最优作为目标。(2)在多个不同尺度的目标上进行目标跟踪,产生多个预测结果,选择其中最优作为最后的预测目标。

                    5,快速移动(Fast Motion)

                          

                          快速移动指的是要跟踪的目标在接下来的帧中,快速的变换位置。这样很可能会导致目标丢失,因此也是目标跟踪的一个比较重要的点。

                    还有背景杂斑(Background Clutter),光照变化(illumination variation)等其他挑战。总而言之对于视觉跟踪而言,由于运动目标的运动场景大多较为复杂,并且经常发生变化,或者要跟踪的目标本身也会发生变化。这样就导致要考虑的问题变成了,如何在复杂变换的场景中识别并跟踪不断变化的目标。

                    经过上述的方法总结就个人而言感觉视觉跟踪大致有两个比较困难的点:

                    1.上述的各个挑战,由于要考虑的视频中跟踪的目标的具体情况不同,所以对应的挑战也不相同,想要一劳永逸的解决是不现实的。可能一个算法在面对一个挑战时表现的很好,但面对另一个挑战时表现的又很差。

                     2.缺乏训练样本,假如我们使用深度学习的方法来进行目标跟踪。那么我们需要对应的数据集来训练网络,但因为目标跟踪任务的特殊性,只有初始帧的图片数据可以利用,因此缺乏数据供神经网络学习。

              1.3 目标跟踪方法:

                    就目前为止,追踪器大致分为两大类生成性追踪器和鉴别性追踪器。

                     (1)生成性追踪器(Generative Method):通过在线学习的方式建立目标模型,然后使用模型搜索重建误差最小的图像区域,完成目标定位。这一类方法没有考虑目标的背景信息,图像信息没有得到较好的应用。通俗点讲就是在当前帧对目标区域建模,下一帧寻找与模型最相似的区域就是预测位置,比较著名的有卡尔曼滤波,粒子滤波,mean-shift等。

                     (2)鉴别性追踪器(Discriminative Method):将目标跟踪看作是一个二元分类问题,同时提取目标和背景信息用来训练分类器,将目标从图像序列背景中分离出来,从而得到当前帧的目标位置。CV中的经典套路图像特征+机器学习, 当前帧以目标区域为正样本,背景区域为负样本,机器学习方法训练分类器,下一帧用训练好的分类器找最优区域:与生成类方法最大的区别是,分类器采用机器学习,训练中用到了背景信息,这样分类器就能专注区分前景和背景,所以判别类方法普遍都比生成类好。

              1.4 跟踪方法:

                    稀疏表示(Sparse Representation):对于生成性追踪器来说,较为典型的就是稀疏矩阵了。给定一组过完备字典,将输入信号用这组过完备字典线性表示,对线性表示的系数做一个稀疏性的约束(即使得系数向量的分量尽可能多的为0),那么这一过程就称为稀疏表示。基于稀疏表示的目标跟踪方法则将跟踪问题转化为稀疏逼近问题来求解。但实际上近些年来生成性追踪器使用的较少。因此系数表示也用的也比较少。基本上相关滤波和深度学习占据了目标跟踪的大半。

                    相关滤波(Correlation Filter):相关滤波本身源于信号领域。其基本思想为衡量两个信号是否相关,两个信号越相似,那么相关的操作越强。对于目标跟踪而言,对应的上一帧得到的目标与下一帧中的区域越相似,响应越高。通常使用卷积表示相关的操作。当其应用到目标跟踪上时,其基本思想就是,寻找一个滤波模板,让下一帧的图像与得到的滤波模板做卷积操作,响应最大的区域就是预测的目标。

                    深度学习(CNN-Based):对于神经网络来说由于CNN引入了卷积层和池化层的概念。而卷积层在输入的时候不仅考虑到了输入的值,还可以保持输入的形状不变。当输入数据是图像时,卷积层会以三维数据的形式接收输入数据,并且同样以三维数据的形式输出至下一层,因此,CNN可以正确理解图像等具有形状的数据。所以对于计算机视觉领域有着独特的优势。对于检测,人脸识别等早CNN早以发出自己的声音。但对于目标跟踪领域而言,开始并不顺畅。正如上文所述由于目标跟踪的特殊,只有初始帧的图片数据可以用,所以缺乏大量的数据供神经网络学习。直到后来将在分类图象数据集上训练的卷积神经网络应用到目标跟踪上后,基于深度学习的目标跟踪方法才得到充分的发展。

              1.5 数据集:

                    OTB:OTB分为OTB50和OTB100,其中OTB100包含OTB50,该数据集的特点是人工标注的groundtruth,同时包含有25%的灰度数据集。

                    VOT:本身是竞赛数据集更具有代表性。同时VOT每年更新。

                    VOT与OTB的区别:这两个数据集都是目标跟踪常用的数据集,但还有一定的差别。

                     (1)OTB包括有25%的灰度序列,但VOT都是彩色序列,这也导致了很多颜色特征算法性能的差异。

                     (2)两个库的评价标准也不一样。

                     (3)OTB有随机帧开始,或者矩形框加随机干扰初始化去跑,但VOT是第一帧初始化跑,每次跟踪失败时,5帧之后重新初始化,VOT以短时跟踪为主,并且认为跟踪监测应该在一起不分离,detecter会多次初始化tracker。

     

    目标跟踪基本流程

              2.1 基本流程

                    单目标视觉跟踪的任务就是在给定某一个视频序列初始帧的目标大小与位置的情况下,预测后续帧中该目标的大小与位置,其基本流程如下图所示:

                                  

                      输入初始化目标框,在下一帧中产生众多候选框(Motion Model),提取候选框的特征(Feature Extractor),然后对这些候选框评分(OBservation Model),最后在这些评分中找到一个最高得分的候选框作为预测的目标(Prediction A),或者对多个预测值进行融合(Ensemble)提高准确率。

                      基于上述过程将该流程大致分为以下五个模块进行研究:

                      1.运动模型(Motion Model):基于对前一帧的估计,运动模型生成一组可能包含当前帧中目标的候选区域或包围盒。

                          运动模型旨在描述帧与帧目标运动状态之间的关系,显式或隐式地在视频帧中预测目标图像区域,并给出一组可能的候选区域。常用的有两种方法:粒子滤波和滑动窗口。其中粒子滤波是一种序贯贝叶斯推断方法,通过递归的方式推断目标的隐含状态。滑动窗口是一种穷举搜索方法,它列出目标附近的所有可能的样本作为候选样本。

                      2.特征提取(Feature Extractor):征提取器使用一些特征表示候选集中的每个候选者。

                          适用于目标跟踪的特征一般要求,既能较好地描述跟踪目标又能快速计算。常用的特征也被分成两类:手工设计的特征和深度特征。常用的手工设计的特征有:灰度特征,颜色特征,纹理特征等。而深度特征则是通过大量的训练样本学习出来的特征,更具有鉴别性。

                     3.观测模型(Observation Model):观察模型根据从候选人中提取的特征判断候选人是否是目标。

                        观测模型返回给定目标候选人的置信度,因此通常被认为是跟踪器的关键部件。与特征提取器和观察模型组件相比,运动模型对性能的影响一般很小。然而,在尺度变化和快速运动的情况下,合理地设置参数仍然是获得良好性能的关键。如上文中提到的,追踪器大致分为两大类生成性追踪器和鉴别性追踪器一致。观测模型可分为两类即生成式模型和鉴别式模型,生成式模型通常寻找与目标模板最为相似的候选作为跟踪结果,可简单视为模板匹配。较为常用为上文中提到的稀疏表示。而鉴别式模型则通过训练一个分类器去区分目标与背景,选择置信度最高的候选样本作为预测结果。判别式方法已经成为目标跟踪中的主流方法,如上文中提到的相关滤波,深度学习。

                     4.模型更新(Model Update):模型更新器控制更新观测模型的策略和频率。它必须在模型适应和漂移之间取得平衡。

                        为了捕捉目标( 和背景) 在跟踪过程中的变化,目标跟踪需要包含一个在线更新机制,在跟踪过程中不断更新外观模型。在本文中考虑两种方法。1.每当目标可信度低于阈值时更新模型。这样做可以确保目标始终具有很高的信心。 2.当目标的置信度与背景样本的置信度之差低于阈值时,对模型进行更新。这种策略只是在正面和负面的例子之间保持足够大的差距,而不是强迫目标有很高的信心。

                       5.集成结果处理Ensemble Method):当一个跟踪系统由多个跟踪器组成时,集成后处理器获取组成跟踪器的输出,并使用集成学习方法将它们组合成最终结果。

                          单个跟踪器的结果有时可能非常不稳定,因为即使在很小的扰动下,性能也会发生很大的变化。参数采用集成方法的目的就是为了克服这一限制。

             2.2 总结

                   由上述的过程可得知模块之间的关系为:运动模型负责描述帧与帧目标运动状态之间的关系,给出一组目标可能会出现的候选区域。特征提取则能够很好的跟随目标同时又保证计算较为简洁。而观测模型作用于当前帧,用来判断区域内是否是要跟踪的目标。因为在较长的跟踪过程中目标的特征可能会出现变化,因此需要一个目标更新模块来不时的对观测模型进行实时更新以此来确保跟踪目标的正确性。而单个跟踪器其结果不确定。并不能一定确保跟踪的稳定性。所以需要集成结果处理来确保结果的稳定性。

    相关算法

              就目前来说相关滤波与深度学习在视觉目标跟踪领域占据主要的地位。如下图所示。

              

              3.1基于相关滤波的典型算法

                   3.1.1相关滤波在视频跟踪的应用方法:设计一个对目标高响应,同时对背景低响应的滤波器,由此实现对目标模式的快速检测。简单来说就是设计一个滤波模板,利用该模板与目标候选区域做相关运算,最大输出响应的位置即为当前帧的目标位置。

                   

                      其中y表示响应输出,x表示输入图像,w表示滤波模板。利用相关定理,将相关转换为计算量更小的点击。

                      

                       如上图所示的分别是y,x,w的傅里叶变换。而相关滤波的任务就是寻找最优的滤波模板w。

                   3.1.2具体的算法:

                           (1)MOSSE

                                    如同在3.1.1中所提出的相关滤波的应用方法一样,MOSSE的具体做法就是利用了信号处理中的相关性,通过提取目标特征来训练相关滤波器,对下一帧的输入图像进行滤波,当两个信号越相似(后一帧中图像的某个位置与前一帧用于训练的特征越相似),那么在该位置滤波器所计算得到的相关值越高。如下图所示为相关值得计算。

                                    

                                  其中g表示的是计算的相关值,f为输入的图像,h为滤波器模板。运算的过程大致如下,卷积中的卷积层和池化层。

                                   

                                    为了减少计算量,加快响应,通过快速傅里叶变换(FFT)将卷积操作变成了点乘操作。同时为了在每一帧后更新相关滤波器,采用将前面的图像都相加的办法,求得相加最小。

                                     所以MOSSE的工作流程大致为:

                                     1.先手动或者条件给定第一帧目标区域,提取特征。

                                     2.对下一帧输入图像裁剪下预测区域,进行特征提取,做FFT运算,与相关滤波相乘后将结果做IFFT运算,得到输出的相应点,其中最大响应点为该帧目标的位置。

                                     3.将该帧的目标区域加入到训练样本中,对相关滤波进行更新。

                                     4.重复步骤2,3.  

                           (2)CSK

                                    CSK针对MOSSE采用稀疏采样造成样本冗余的问题,扩展了岭回归,基于循环移位的近似密集采样方法,以及核方法。

                                    岭回归:

                                    CSK为求解滤波模板的使用了岭回归。如下图:

                                     

                                       

                                      其中x是训练样本,而X是x构成的样本矩阵,y是样本的响应值,w是待求得滤波模板,而λ是正则化系数。使用岭回归为了防止过拟合。使得求到的滤波器在下一帧的图像中的泛化能力更强。

                                     循环移位:

                                     CSK的训练样本是通过循环移位产生的。密集采样与循环移位产生的样本很像,可以用循环移位来近似。循环矩阵原理如图,第一行是实际采集的目标特征,其他行周期性地把最后的矢量依次往前移产生的虚拟目标特征。

                                       

                                     对图像进行循环移位的效果实例如图

                                                     

                                    

                                    循环移位的样本集是隐性的,并没有真正产生过,只是在推导过程中用到,所以也不需要真正的内存空间去存储这些样本。同时生成的近似样本集结合FFT极大地减少了计算量,但这种近似引入边界效应。

                           (3)CN

                                    MOSSE与CSK处理的都是单通道灰度图像。引入多通道特征扩展只需要对频域通道响应求和即可。HOG+CN在近年来的跟踪算法中是常用的特征搭配,HOG是梯度特征,而CN是颜色特征,二者可以互补。

                                    CN其实是一种颜色的命名方式,与RGB,HSV同属于一类。CN在CSK的基础上扩展了多通道颜色。将RGB的3通道图像投影到11个颜色通道,,分别对应英语中常用的语言颜色分类,分别是black, blue, brown, grey, green, orange, pink, purple, red, white, yellow,并归一化得到10通道颜色特征。也可以利用PCA方法,将CN降维到2维。

                           (4)KCF/DCF

                                    KCF可以说是对CSK的完善。论文中对岭回归、循环矩阵、核技巧、快速检测等做了完整的数学推导。KCF在CSK的基础上扩展了多通道特征。KCF采用的HoG特征,核函数有三种高斯核、线性核和多项式核,高斯核的精确度最高,线性核略低于高斯核,但速度上远快于高斯核。

                           在前面提到的挑战中有一种挑战是尺度变化。对于这一问题上述的KCF/DCF和CN都没有涉及到。这样的话如果目标发生尺度变化,那么滤波器就会学习到大量的背景信息,如果目标扩大,滤波器可能会跟踪到目标局部纹理。这两种情况都可能出现非预期的结果,导致跟踪漂移和失败。基于此提出SAMF(基于KCF,特征是HOG+CN。采用多尺度检测。取响应最大的平移位置及所在的尺度。因此可以同时检测目标中心变化和尺度变化),DSST(将目标跟踪分解为目标中心平移和目标尺度变化两个独立问题,这样对应的模块只负责一部分,如尺度滤波器仅需要检测出最佳匹配尺度无须关心平移的情况。)

              3.2基于深度学习的典型算法

                           (1)MDNet

                                    MDNet直接使用跟踪视频预训练CNN获得的general目标表示能力,但实际上训练序列也存在问题,因为不同的视频中我们要跟定的目标是不相同的,可能这个视频中要跟踪的目标在下一个视频中就是背景,因此只使用单独一个CNN完成所有的训练序列中前景和背景区分的任务较为困难。

                                  

                                  上图包含了MDNet的基本思想。MD分为共享层和domain-specific层两部分。其具体做法是将每个训练序列当成一个单独的domain,每个domain都有一个针对它的二分类层(fc6),用于区分当前序列的前景和背景,而网络之前的所有层都是序列共享的。这样共享层达到了学习跟踪序列中目标general的特征表达的目的,而domain-specific层又解决了不同训练序列分类目标不一致的问题。在具体的训练时,MDNet的每一个mini-batch只由一个特定序列的训练数据构成,只更新共享层和针对当前序列的特定fc6层。这样使得共享层获得了所有的序列共有特征的表达能力,而对应于特定序列的fc6层则只保存有当前序列的特征。

                                  在具体的跟踪阶段,MDNet的主要做法为:

                                  (1)随机初始化一个新的fc6层

                                  (2)使用第一帧的数据来训练该序列的bounding box回归模型。

                                  (3)用第一帧提取正样本和负样本,更新fc4,fc5和fc6层的权重。

                                  (4)之后产生256个候选样本,并从中选择置信度最高的,之后做bounding-box regression得到的结果。

                                  (5)如果当前帧的最终结果置信度比较高,那么采样更新样本库,否则根据情况对模型做短期或者长期的更新。

                           (2)TCNN

                                    TCNN用了很多个CNN的模型,并构建成一棵树的结构,如图1所示,红色的框越粗说明对应的CNN模型的可靠性(reliability)越高。连接的红色的线越粗,说明两个CNN之间的相关性越高(affinity)。黑色的箭头越粗表示对应的CNN模型对目标估计的权重越高。TCNN还对每一个CNN模型进行了可靠性评估。如下图所示:

                                      

                                     每个CNN的网络结构是一样的,前面的卷积层的参数共享,是来自于事先用imageNet训练好的VGG-M网络,再加上后面的全连接层。构成了TCNN。其在第一帧的时候随机初始化并进行迭代训练,后面每次更新的时候都只更新全连接层的参数。如下图所示:

                                      

                                        总的来说TCNN效果较好,但差于ECO。

                                        效果好的原因:

                                        (1)使用了多个CNN模型进行检测(10个)

                                        (2)使用了树的结构来组织CNN模型,避免它们只对最近的帧过拟合

                                        (3)CNN会一直有新的模型加进来,且经过fine-tuning。

                                        (4)在确定最终的位置时还做了Bounding Box Regression,进一步提高定位准确性。

                           

              3.3深度学习与相关滤波相结合

                           (1)SRDCF&DeepSRDCF

                                    SRDCF在KCF优化目标的基础上加入了空域正则化,增强了模型的判别能力,优化目标变为:

                                                      

                                    其中的指的是对w施加的空间正则化权重。这表明,某些位置(主要是边界)的滤波器系数会受到惩罚。

                                    

                                   DCF(左)与SRDCF(右)的效果对比。

                                   传统方式获取特征是HOG+CN,后来发现CNN浅层特征比HOG手工特征效果要好后。于是作者将SRDCF的模型更改为使用CNN,也就形成了一个新的模型,即:DeepSRDCF

                           (2)C-COT

                                    使用一种隐式的插值方式将模型的学习投射到一个连续的空间域中,提出了一种在连续空间域上的卷积算子。C-COT将多种分辨率的深度特征进行了高效的集成,使得模型在各个数据集上的性能都得到了很大的提升。

                                    

                                  C-COT的特征图,卷积核,各层置信图和融合后连续空间的输出置信图。

                           (3)ECO

                                     ECO在C-COT的基础上进一步提升。主要有两点。①ECO降低了C-COT的参数量,对特征提取作了降维简化,提升效率,防止过拟合。②使用高斯混合模型生成不同样本组合,简化训练集的同时还增加了多样性;另外,提出了一种高效的模型更新策略,在提升速度的同时还提升了鲁棒性。

                                     

                                     C-COT学习后的卷积核与ECO学习后的卷积核。

                           (4)SiamFC

                                    SiamFC开创了端到端深度学习相关滤波方法的先河,同时也为深度学习方法逐渐超越相关滤波方法拉开了序幕。其对应的网络如下:

                                    

                                     图中φ是CNN编码器,而上下使用的两个CNN结构相同,同时参数也共享。而z和x分别是要跟踪的目标模板图像和新的一桢中的搜索范围(255*255).二者经过同样的编码器后得到各自的特征图,对二者进行互相关运算后则会得到一个如上图所示的响应图(17*17),其每一个像素的值对应了x中与z等大的一个对应区域出现跟踪目标的概率。

                           (5)SiamRPN&DaSiamRPN

                                    SiamRPN在x和y经过孪生CNN得到各自的特征图后,没有直接对二者进行互相关运算,而是将这两个特征图各自放入RPN部分的两个分支中,每个分支中的两个特征图分别经过一个CNN再进行互相关运算。RPN部分的两个分支分别用于进行目标概率的预测和目标边框的回归,并且同样借鉴了目标检测领域的anchor方法,从而降低了目标边框回归的训练难度。                                 其具体步骤如下图:

                                   

                                  在SiamRPN提出之后,又提出其改进型------DaSiamRPN,对训练数据进行了增强以提升模型对同类别物体干扰的判别能力。同时,DaSiamRPN加入了增量学习的Distractor-aware模块,在运行时采样并更新模型的参数。使得模型模型能够更好的迁移到当前视频的域中。

      

                        

    参考文献

              [1] 张微, 康宝生. 相关滤波目标跟踪进展综述[J]. 中国图象图形学报, 2017(8).

              [2] 李娟. 基于目标跟踪的视频去运动模糊[D]. 电子科技大学, 2016.

              [3] 吴小俊, 徐天阳, 须文波. 基于相关滤波的视频目标跟踪算法综述[J]. 指挥信息系统与技术,2017(3).

              [4] 王硕. 基于相关滤波的目标跟踪算法[D].

              [5] Wang N , Shi J , Yeung D Y , et al. Understanding and Diagnosing Visual Tracking Systems[J]. 2015.

              [6] https://www.zhihu.com/question/26493945/answer/156025576

              [7] https://www.cnblogs.com/jjwu/p/8512730.html

              [8] https://blog.csdn.net/qq_34919792/article/details/89893433

              [9] https://blog.csdn.net/zhu_hongji/article/details/80515031

              [10] https://blog.csdn.net/weixin_39467358/article/details/84568474

              [11] https://www.zhihu.com/question/26493945

             

              

                              

                                 

     

    展开全文
  • 是一个插件,它使该机器人可以找到负责损坏另一个实体的。 一个简单的用法示例可以在/ examples文件夹中找到 攻击类型支持: 近战伤害(剑,拳等) 射弹(箭头,药水等)-已计划 猎犬不是100%可靠的,在许多...
  • 该代码对由经验派生的人类操作员信息参数和现实世界的非线性组成的 ... 该工具为输入设备的设计(设计变量是控制增益)找到解决方案,该设备在加权复杂性的选择/跟踪任务期间将人类操作员与非线性机器连接起来。
  • 有多种方法可以查找和跟踪您喜爱的文件的作者。 该视频由马修·奥利芬特 (Matthew Oliphant) 创建。
  • 目标跟踪算法

    千次阅读 2017-08-30 17:14:50
    运动目标跟踪主流算法大致分类:a) 不依赖先验知识,直接从图像序列中检测到运动目标,并进行目标识别,最终对目标进行跟踪.b) 依赖于目标的先验知识,首先为运动目标建模,然后在图像序列中实时找到相匹配的运动...
  • 目前完成的程序在我的笔记本上运行大概是一帧80-100ms,直接用检测算法来做跟踪算法其实也马马虎虎可以用了。   开发环境如下: 系统:Windows 10 IDE:Visual Studio 2013 语言:C++ 算法库:OpenC
  • 不管是kinect还是华硕的xtion (openNI),里面把定位、分割segmentation并且跟踪 tracking得都好好啊,而且这也是后续做姿势识别和骨骼跟踪的基础。 找了很久论文没有看到合适的,最后决定用Google学术搜索专利,...
  • 预算跟踪应用 目录: ••••• 概念说明 该应用程序的目的是帮助个人概述他们的支出,以便做出更好的财务决策。 写下您的支出的举动足以帮助您变得更明智。 该应用程序将通过记录购买和每月支出来关注意识。 目标...
  • 目标跟踪简介

    千次阅读 2019-07-13 10:04:15
    文章目录目标跟踪简介3.1 引言3.2 目标跟踪算法分类3.2.1 生成式算法(1)核方法(2)粒子滤波方法(3)卡尔曼滤波方法(4)稀疏表示方法3.2.2 判别式方法(1)相关滤波方法(2)深度学习方法3.3单摄像机多目标跟踪...
  • 目标检测跟踪算法综述

    千次阅读 2019-07-09 16:19:22
    在特定的场景中,有一些经典的算法可以实现比较好的目标跟踪效果。本文介绍了一般的目标跟踪算法,对几个常用的算法进行对比,并详细介绍了粒子滤波算法和基于轮廓的目标跟踪算法。最后简单介绍了目标遮挡的处理、多...
  • 运动目标跟踪算法

    万次阅读 多人点赞 2019-02-17 12:53:17
    在特定的场景中,有一些经典的算法可以实现比较好的目标跟踪效果。本文介绍了一般的目标跟踪算法,对几个常用的算法进行对比,并详细介绍了粒子滤波算法和基于轮廓的目标跟踪算法。最后简单介绍了目标遮挡的处理、多...
  • 目标跟踪综述

    千次阅读 2018-05-22 10:12:42
    相信很多来这里的人和我第一次到这里一样,都是想找一种比较好的目标跟踪算法,或者想对目标跟踪这个领域有比较深入的了解,虽然这个问题是经典目标跟踪算法,但事实上,可能我们并不需要那些曾经辉...
  • opencv颜色跟踪

    2018-03-07 21:02:15
    最近被问到如何做跟踪算法,找到一个挺好的,在此记录下来 http://blog.csdn.net/akadiao/article/details/78881026
  • 可以在此存储库的文件夹下找到Server Open API定义。 计算:AWS Lambda 数据存储:DynamoDB 路由和负载平衡:API网关 权限管理:IAM 服务器部署 基础设施设置自动化是使用完成的。 通过以下步骤,您将可
  • 运动目标跟踪

    千次阅读 2017-10-25 09:59:57
    目标检测之后就是目标跟踪,目标跟踪是在事先不了解目标运动信息的条件下,通过来自信息源的数据实时估计出目标的运动状态,从而实现对目标的位置和运动趋势的判定。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 167,852
精华内容 67,140
关键字:

哪里可以找到跟踪的人