开发环境:Ubuntu 18.04 LTS + ROS Melodic + ViSP 3.3.1
文章内容主要参考ViSP官方教学文档:https://visp-doc.inria.fr/doxygen/visp-daily/tutorial_mainpage.html

  本文主要介绍了如何使用ViSP实现运动的边缘跟踪,调用摄像头获取视频图像,并从第一帧图像中选择需要跟踪的物体边缘,确定好边缘后,图中的红色线条会跟随物体移动。本文主要参考了moving-edges中的tutorial-me-line-tracker.cpp例程。首先要获取这个例程文件并编译它

svn export https://github.com/lagadic/visp.git/trunk/tutorial/tracking/moving-edges
cd moving-edges/
mkdir build
cd build 
cmake .. -DCMAKE_BUILD_TYPE=Release -DVISP_DIR=$VISP_WS/visp-build
make 

  执行例程,查看效果

./tutorial-me-line-tracker

  打开第一帧使用鼠标左键选取待追踪的物体边缘的两个顶点
在这里插入图片描述
  选择好边缘后,移动物体可以观察到边缘线条会跟随物体移动
在这里插入图片描述

  直接运行程序可能会出现“No cameras found”或者“VIDIOC_QBUF: EINVAL”的报错。首先要保证摄像头正确连接,这里以普通的USB摄像头或笔记本自带摄像头为例,重新插拔一下USB摄像头,如果使用虚拟机还需要保证摄像头连接到虚拟机而不是主机。然后确保第三方库文件安装好了,Ubuntu环境下使用USB摄像头主要依赖v4l2库,安装方式

sudo apt-get install libv4l-dev

  最后查看是否调用了正确的设备号,程序中默认调用的设备号为video0,先查看一下自己的摄像头编号,Ubuntu环境下在dev文件夹下有以video开头的文件,如果文件名为video0,那说明设备编号为0,如果文件名不是video0,则需要修改程序,原代码为

#if defined(VISP_HAVE_DC1394)
    vp1394TwoGrabber g(false);
#elif defined(VISP_HAVE_CMU1394)
    vp1394CMUGrabber g;
#elif defined(VISP_HAVE_V4L2)
    vpV4l2Grabber g;
#elif defined(VISP_HAVE_OPENCV)
    cv::VideoCapture g(0); // open the default camera

我的修改方式如下

//把DC1394这个库屏蔽了
//#if defined(VISP_HAVE_DC1394)
  //  vp1394TwoGrabber g(false);
#if defined(VISP_HAVE_CMU1394)
    vp1394CMUGrabber g;
#elif defined(VISP_HAVE_V4L2)
    vpV4l2Grabber g;
    std::ostringstream device;
    device << "/dev/video" << 0;//此处的0就表示设备编号,可根据自己的情况修改成其他数字
    g.setDevice(device.str());
    g.setScale(1);
#elif defined(VISP_HAVE_OPENCV)
    cv::VideoCapture g(0); // 此处的0就表示设备编号,可根据自己的情况修改成其他数字

  下面介绍一下代码实现过程

#include <visp3/core/vpConfig.h>
#ifdef VISP_HAVE_MODULE_SENSOR
#include <visp3/sensor/vp1394CMUGrabber.h>
#include <visp3/sensor/vp1394TwoGrabber.h>
#include <visp3/sensor/vpV4l2Grabber.h>
#endif
#include <visp3/gui/vpDisplayGDI.h>
#include <visp3/gui/vpDisplayOpenCV.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/me/vpMeLine.h>
int main()
{
#if (defined(VISP_HAVE_DC1394) || defined(VISP_HAVE_CMU1394) || defined(VISP_HAVE_V4L2))
  try {
    vpImage<unsigned char> I;
#if defined(VISP_HAVE_DC1394)
    vp1394TwoGrabber g(false);//unix环境下调用firewire相机
#elif defined(VISP_HAVE_CMU1394)
    vp1394CMUGrabber g;//windows环境下调用firewire相机
#elif defined(VISP_HAVE_V4L2)
    vpV4l2Grabber g;//unix环境下调usb相机
#elif defined(VISP_HAVE_OPENCV)
    cv::VideoCapture g(0); // unix环境下调usb相机
    //以上代码都是寻找正确的打开摄像头的库
    if (!g.isOpened()) {   // check if we succeeded
      std::cout << "Failed to open the camera" << std::endl;
      return -1;
    }
    cv::Mat frame;
    g >> frame; // 从摄像头获取第一帧图像
    vpImageConvert::convert(frame, I);
#endif
    g.open(I);
    g.acquire(I);
#if defined(VISP_HAVE_X11)
    vpDisplayX d(I, 0, 0, "Camera view");
#elif defined(VISP_HAVE_GDI)
    vpDisplayGDI d(I, 0, 0, "Camera view");
#elif defined(VISP_HAVE_OPENCV)
    vpDisplayOpenCV d(I, 0, 0, "Camera view");
#else
    std::cout << "No image viewer is available..." << std::endl;
#endif
    vpDisplay::display(I);
    vpDisplay::flush(I);
    vpMe me;
    //初始化待跟踪的物体边缘的参数
    me.setRange(25);//相邻帧的跟踪范围是边缘法线方向上25个像素内
    me.setThreshold(15000);//对于沿着法线的每个像素,我们将计算有向卷积。
    				      //移动边缘算法选择的像素将是卷积大于15000的像素。
    me.setSampleStep(10);//在轮廓上两个连续移动的边缘之间,我们保持10个像素的空间。
    vpMeLine line;
    line.setMe(&me);
    line.setDisplay(vpMeSite::RANGE_RESULT);
    line.initTracking(I);
    while (1) {
#if defined(VISP_HAVE_DC1394) || defined(VISP_HAVE_V4L2) || defined(VISP_HAVE_CMU1394)
      g.acquire(I);
#elif defined(VISP_HAVE_OPENCV)
      g >> frame;
      vpImageConvert::convert(frame, I);
#endif
      vpDisplay::display(I);
      line.track(I);
      line.display(I, vpColor::red);
      vpDisplay::flush(I);
    }
  } catch (const vpException &e) {
    std::cout << "Catch an exception: " << e << std::endl;
  }
#endif
}

如果大家对于深度学习与计算机视觉领域感兴趣,希望获得更多的知识分享与最新的论文解读,欢迎关注我的个人公众号“深视”。在这里插入图片描述