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

  本文介绍了如何使用ViSP实现常见的图像滤波,如高斯滤波、梯度计算、卷积运算、Canny边缘检测等。在vpImageFilter类中提供了多种滤波函数,使用者只需调用即可。本文的介绍主要参考了image中的tutorial-image-filter.cpp例程,大家可以按照之前的教程轻松的编译和使用它。
cd ~/visp_ws/image/build
make tutorial-image-filter
./tutorial-image-filter monkey.pgm

  我们按照顺序逐步介绍一下代码的内容

#include <visp3/core/vpImageFilter.h> //添加ImageFilter头文件,提供了与图像滤波相关的类和函数
#include <visp3/gui/vpDisplayD3D.h>
#include <visp3/gui/vpDisplayGDI.h>
#include <visp3/gui/vpDisplayGTK.h>
#include <visp3/gui/vpDisplayOpenCV.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/io/vpImageIo.h>
void display(vpImage<unsigned char> &I, const std::string &title); 
void display(vpImage<double> &D, const std::string &title);

//定义了一个显示无符号字符型图像的函数
void display(vpImage<unsigned char> &I, const std::string &title)
{
#if defined(VISP_HAVE_X11)
  vpDisplayX d(I);
#elif defined(VISP_HAVE_OPENCV)
  vpDisplayOpenCV d(I);
#elif defined(VISP_HAVE_GTK)
  vpDisplayGTK d(I);
#elif defined(VISP_HAVE_GDI)
  vpDisplayGDI d(I);
#elif defined(VISP_HAVE_D3D9)
  vpDisplayD3D d(I);
#else
  std::cout << "No image viewer is available..." << std::endl;
#endif
  vpDisplay::setTitle(I, title.c_str());
  vpDisplay::display(I);
  vpDisplay::displayText(I, 15, 15, "Click to continue...", vpColor::red);
  vpDisplay::flush(I);
  vpDisplay::getClick(I);
}

//定义了一个显示双精度浮点型图像的函数
void display(vpImage<double> &D, const std::string &title)
{
  vpImage<unsigned char> I; // Image to display
  vpImageConvert::convert(D, I);//把双精度浮点型图像转化为无符号字符型图像
  display(I, title);
}

 下面介绍主函数部分

  try {
    if (argc != 2) {
      printf("Usage: %s <image name.[pgm,ppm,jpeg,png,bmp]>\n", argv[0]);
      //提示用户在运行该程序时需要提供图像的名字
      return -1;
    }
    vpImage<unsigned char> I;
    try {
      vpImageIo::read(I, argv[1]); //按照图像的名字从文件夹中读取图像
    } catch (...) {
      std::cout << "Cannot read image \"" << argv[1] << "\"" << std::endl;
      return -1;
    }
    display(I, "Original image"); //显示原始图像

  显示效果如下

在这里插入图片描述

  • 高斯滤波(默认参数)

    vpImage<double> F;
    vpImageFilter::gaussianBlur(I, F); //使用默认参数对图像进行高斯滤波
    display(F, "Blur (default)"); //显示高斯滤波后的图像

  显示效果如下

在这里插入图片描述

  • 高斯滤波(核尺寸为7,方差为2)

    vpImageFilter::gaussianBlur(I, F, 7, 2); //使用核尺寸为7,方差为2高斯滤波
    display(F, "Blur (var=2)"); //显示高斯滤波后的图像

 显示效果如下

在这里插入图片描述

  • 计算X方向上的梯度

    vpImage<double> dIx;
    vpImageFilter::getGradX(I, dIx); // 计算X方向上的梯度
    display(dIx, "Gradient dIx"); //显示梯度图像

显示效果如下

在这里插入图片描述

  • 计算Y方向上的梯度

    vpImage<double> dIy;
    vpImageFilter::getGradY(I, dIy); // 计算Y方向上的梯度
    display(dIy, "Gradient dIy"); //显示梯度图像

 显示效果如下

在这里插入图片描述

  • 使用Canny算子实现边缘检测

    vpImage<unsigned char> C;
    vpImageFilter::canny(I, C, 5, 15, 3); //Canny算子的阈值下限为5,上限为15(下限的三倍),核尺寸为3
    display(C, "Canny"); //显示Canny算子边缘检测效果

  显示效果如下

在这里插入图片描述

  • 卷积运算

    vpMatrix K(3, 3); // 定义一个3*3的矩阵作为卷积核
    //确定卷积核内的参数
    K[0][0] = 1;
    K[0][1] = 0;
    K[0][2] = -1;
    K[1][0] = 2;
    K[1][1] = 0;
    K[1][2] = -2;
    K[2][0] = 1;
    K[2][1] = 0;
    K[2][2] = -1;
    vpImage<double> Gx;
    vpImageFilter::filter(I, Gx, K); //使用卷积核进行卷积运算
    display(Gx, "Sobel x"); //显示卷积运算结果
    //因为定义的卷积核的参数与Sobel算子在X方向上的计算方法相同,上述方法也可以看作手动实现X方向的Sobel算子

 显示效果如下

在这里插入图片描述

  • 高斯金字塔

    size_t nlevel = 3; // 定义高斯金字塔层级
    std::vector<vpImage<unsigned char> > pyr(nlevel); //定义一个图像向量
    pyr[0] = I; //向量首位为原始图像
    for (size_t i = 1; i < nlevel; i++) {
      vpImageFilter::getGaussPyramidal(pyr[i - 1], pyr[i]); //逐层进行高斯下采样
      display(pyr[i], "Pyramid"); //显示高斯下采样结果
    }

在这里插入图片描述

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

在这里插入图片描述