机器人视觉检测+跟踪:行人跟随过程中对目标提取特征+匹配

2023-05-16

今天上午也是没有很大的成效,一直到下午睡醒(论好的睡眠的重要性),在一篇帖子中看到一种新的写法,opencv3将IplImage转换为Mat格式的写法,在我们的代码中采用这种方式,改到哪里哪里的问题就消失了,这种感觉非常爽!

写完整一点,记录准确以后参考。

我在机器人视觉检测中将kinect采集到的视频数据流进行特征提取和匹配,用的是成熟快速兼于一体的surf加速鲁棒特征进行匹配,这其中的一个方法是需要先将ros中的图像信息格式sensor::message/image通过cv_bridge转换为我们的Mat格式,之后需要将Mat格式再进一步转换为IplImage格式的图像,这是因为我们需要用到cvCreateImage()函数取出来图像的像素深度和图像通道信息,这一步只能对IplImage格式进行操作,需要对原图象进行深拷贝,转换操作完后,我们要不嫌麻烦地再将IplImage图像转换为Mat图像,之后就是愉快的送入到特征检测计算器中计算,detectAndCompute()需要的参数格式很严格,上述的转换格式的原因就是需要满足这样的参数格式,详细的注释都给出在代码中。

走了很多弯路,主要就是格式转换中的代码写的原因,版本不同有不同的写法,可能只有一种合适版本的写法可以编译成功。

看代码:

  //beginging  
  Ptr<SURF> surf;
  surf = SURF::create(800);

  vector<KeyPoint>keypoint1, keypoint2;

  frame = get_one_frame(); 
  body_rect = client->getBodyRect(frame); 
  //image1 = resize(frame, rect.x:(rect.x+rect.width), rect.y:(rect.y+rect.higth))
  //Mat image1; 
  cv_bridge::CvImagePtr cv_ptr1 =cv_bridge::toCvCopy(frame, "bgr8");
  cv::Mat imframe = cv_ptr1->image;


  IplImage *im, *img1;
  CvRect rectInImage1;
  rectInImage1 = cvRect(body_rect.x, body_rect.y,body_rect.width, body_rect.height);
  CvSize size1;
  size1.width = rectInImage1.width;
  size1.height = rectInImage1.height;
  img1 = cvCreateImage(size1, imframe.depth(), imframe.channels());
  //frame->depth
  //img1 = cvCreateImage(size1, IPL_DEPTH_8U, 3);
  im = cvCreateImage(imframe.size(), imframe.depth(), imframe.channels());
  cvConvert(&imframe, im);    //深拷贝,Mat imframe -> IplImage* im
  cvSetImageROI(im, rectInImage1);//void cvSetImageROI(IplImage* image,CvRect rect);
  cvCopy(img1, im);//img1是从im上提取的目标框区域
  //cvtcolor(img1, img_1, CV_RGB2GRAY);
  //将IplImage格式的img1转换为cvMat格式的img01
  //CvMat *img01 = cvCreateMat(img1->height, img1->width, CV_64FC3);
  //cvConvert(img1, img01);
  
  //直接利用Mat定义一个Mat类矩阵,强制将括号内的IplImage*类型图像转换成Mat类
  //cv::Mat img01(IplImage* img1); 
  //Mat img01(IplImage* img1);//高版本不行
  cv::Mat img01 = cv::cvarrToMat(img1);//对应的写法可以编译
  Mat img_1, image1;  
  //void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 );
  cvtColor(img01, img_1, COLOR_RGB2GRAY);//灰度图img_1
  //检测特征点
  //detector.detect(img_1, keypoint1)
  /* detectAndCompute (InputArray image, InputArray mask, 
  std::vector< KeyPoint > &keypoints, OutputArray descriptors, 
  bool useProvidedKeypoints=false) */
  surf->detectAndCompute(img_1, Mat(), keypoint1, image1); //输出mat存放所有的特征点描述向量
  //ending 

我们机器人上的相机获得一帧图像后保存,之后目标跟踪后丢失后会出现问题,再次检测目标时进行特征匹配,并作目标筛选,获得精确目标。

为求完整性,继续上代码

    //Mat image2;
    cv_bridge::CvImagePtr cv_ptr2 =cv_bridge::toCvCopy(tracking_frame, "bgr8");
    cv::Mat imgframe = cv_ptr2->image;
    IplImage *ime, *img2;
    CvRect rectInImage2;
    rectInImage2 = cvRect(body_track_rect.x, body_track_rect.y,
                          body_track_rect.width, body_track_rect.height);
    CvSize size2;
    size2.width = rectInImage2.width;
    size2.height = rectInImage2.height;
    img2 = cvCreateImage(size2, imgframe.depth(), imgframe.channels());
    //img2 = cvCreateImage(size2, IPL_DEPTH_8U, 3);  //bug
    ime =cvCreateImage(imgframe.size(), imgframe.depth(), imgframe.channels());
    cvConvert(&imgframe, ime);
    cvSetImageROI(ime, rectInImage2);
    cvCopy(img2, ime);//img2是从tracking_frame上提取的目标框区域
    //cvtColor(img2, img_2, COLOR_RGB2GRAY);
    //这是
    //CvMat *img02 = cvCreateMat(img2->height, img2->width, CV_64FC3);
    //cvConvert(img2, img02);

    //cv::Mat img02(IplImage* img2); 
    cv::Mat img02 = cv::cvarrToMat(img2);
    cv::Mat img_2, image2; 
    cvtColor(img02, img_2, COLOR_RGB2GRAY);

    //检测特征点
    //detector.detect(img_2, keypoint2);
    surf->detectAndCompute(img_2, Mat(), keypoint2, image2);

    //计算特征点描述子
    //SurfDescriptorExtractor extractor;
    //Mat descriptor1, descriptor2;

    //extractor.compute(img1, keypoint1, descriptor1);
    //extractor.compute(img2, keypoint2, descriptor2);

    //使用flann匹配
    FlannBasedMatcher matcher;
    vector<DMatch>matches;
    matcher.match(image1, image2, matches);//匹配结束

    sort(matches.begin(), matches.end());//将matches进行排序

    vector<DMatch>good_matches;
    int ptsPairs = std::min(50, (int)(matches.size() * 0.15));
    for (int i = 0; i < ptsPairs; i++)//保存50个匹配结果
    {
      good_matches.push_back(matches[i]); 
    }

下一步还需要做的是对匹配结果进行筛选,由于匹配结果是<DMatch>的C++容器类向量,如何进行筛选也是有、东西的。

参考资料

https://blog.csdn.net/zssureqh/article/details/7608024

https://docs.opencv.org/3.3.1/d3/d63/classcv_1_1Mat.html

https://blog.csdn.net/fu_shuwu/article/details/77399835

https://www.cnblogs.com/edver/p/5187190.html

https://blog.csdn.net/yang_xian521/article/details/7755101

https://www.cnblogs.com/anqiang1995/p/7442984.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

机器人视觉检测+跟踪:行人跟随过程中对目标提取特征+匹配 的相关文章

随机推荐

  • 28从零开始学Java之面向对象和面向过程到底有哪些区别?

    作者 xff1a 孙玉昌 xff0c 昵称 一一哥 xff0c 另外 壹壹哥 也是我哦 千锋教育高级教研员 CSDN博客专家 万粉博主 阿里云专家博主 掘金优质作者 前言 壹哥相信 xff0c 经过你对前面文章中技术点的学习 xff0c 现
  • 29从零开始学Java之如何正确创建Java里的类?

    作者 xff1a 孙玉昌 xff0c 昵称 一一哥 xff0c 另外 壹壹哥 也是我哦 千锋教育高级教研员 CSDN博客专家 万粉博主 阿里云专家博主 掘金优质作者 前言 在上一篇文章中 xff0c 壹哥给大家介绍了面向对象和面向过程的概念
  • 全面图解路由器接口及连接(图)

    路由器所在的网络位置比较复杂 xff0c 既可是内部子网边缘 xff0c 也可位于内 外部网络边缘 同时为了实现强大的适用性 xff0c 它需要连接各种网络 xff0c 这样 xff0c 它的接口也就必须多种多样 对于这些 xff0c 不要
  • blktrace,blkparse,btt工具的制作和使用

    1 软件包交叉编译安装 1 1 blktrace源码下载路径 https git kernel dk cgit blktrace 1 2 源码安装 tar zxvf blktrace 1 2 0 tar gz cd blktrace 1 2
  • cartographer之ceres编译

    1 首先下载ceres xff1b 2 进入ceres目录 xff1b 3 mkdir build amp amp cd build 4 cmake DEIGENSPARSE 5 make 6 sudo make install
  • 一个空文件夹和空文件占多少空间?

    用于显示文件夹和文件大小的命令 span class token function du span h 显示目前在 Linux 系统上的文件系统磁盘使用情况统计 span class token function df span i 一 问
  • 虚拟地址如何访问到物理地址

    环境 xff1a 32bit CPU 一 通过二级页表映射的方式访问物理地址 1 取一级页表的基地址Abase1 2 取虚拟地址的前12bit 31 20 地址O1 3 计算得到新地址Apgd 61 Abase1 amp 0xFFFFF00
  • 添加自定义的section

    一 基本知识点 编译出来的程序 xff08 o so exe ko等等 xff09 都是以elf格式进行排列保存的 elf文件分析情况 xff1a https blog csdn net edonlii article details 87
  • 如何打印堆栈

    一 打印堆栈可以方便问题定位 xff0c 找到具体的函数调用流程 二 打印堆栈的方法 2 1 用户态 include lt stdio h gt include lt stdlib h gt include lt stddef h gt i
  • 内存飞踩问题的几点思考

    1 程序编译 xff0c 链接后生成二进制可执行程序 二进制可执行文件以elf格式实现排列 可以通过readelf S xxxx查看具体section的划分 xff0c 粗略划分如下图所示 在这些section中 xff0c 代码段是只读的
  • CFS调度算法

    1 CFS调度算法 xff0c 顾名思义就是完全公平调度策略 比方说 xff0c 调度延迟时间是10ms xff0c 存在两个进程A和B xff0c 那么两个进程分别占用CPU的时间是5ms 然而 xff0c 阶级总是存在的 xff0c 毕
  • ARM处理器的异常模式

    1 ARM处理器有各种异常模式 xff0c 用于应对ARM出现的不同状态 出现异常时 xff0c 会随即进入相关的异常向量 xff0c 同时CPSR的寄存器也会设置成具体的模式 例 xff1a 当出现中断时 xff0c 不管是哪种中断 xf
  • 内核态和用户态相关的内存泄漏

    应用程序通过系统调用进入内核态代码 假如内核态代码存在内存泄漏 xff0c 此内存泄漏属于内核态还是用户态 xff1f 查看内核态和用户态的统计信息
  • 为什么在telnet登入界面下没有日志输出?

    1 每个进程的输入输出导向目标都可以在进程号下的fd软链接上查看 如 569号进程的输出目标是 dev console xff0c 即串口 其中0是标准输入 xff0c 1是标准输出 xff0c 2是标准错误输出 2 因此我们只需要查看te
  • 【无标题】

    1 将虚拟地址传入到内核态 xff0c 借助内核态中mm struct结构体的pgd页表基地址成员 xff0c 经过查页表的方式最终获取到物理地址 这种方法虽然很直观 xff0c 但是一会内核态 xff0c 一会用户态 xff0c 操作起来
  • C#串口=>发送和接收

    作用 xff1a 串口发送命令后 xff0c 等待下位机应答帧 代码 xff1a 一旦读取到数据就立即返回给上层 public string TXandRX byte buffer string data 发送 RS485专用 start
  • kprobe功能的代码实现

    1 可以借助 sys kernel debug tracing目录下的文件 xff0c linux提供了kprobes功能 xff0c 抓取内核函数中的入参和返回值 kprobes xff0c 强大的调试工具 sydyh43的博客 CSDN
  • 上位机使用C++通过ADS协议与倍福PLC通信例程-通过变量名方式读写浮点数

    前言 建议初学者先看这一章节内容 xff0c 里面包括一些基础的环境配置和项目建立流程 xff0c 以后开发项目这些流程是通用的 xff0c 务必掌握并熟练 链接 上位机使用C 43 43 通过ADS协议与倍福PLC通信例程 布尔变量的读取
  • 弄清USART串口的使能位(UE、TCIE、RXNEIE)和标志位(TC、RXNE)

    下面通过485半双工的通信过程 xff0c 记录USART串口的几个使能位 标志位 说明 xff1a USART IT TC 和 USART IT RXNE是一个常量 xff0c 并不代表 xff08 TC RXNE 这两位 define
  • 机器人视觉检测+跟踪:行人跟随过程中对目标提取特征+匹配

    今天上午也是没有很大的成效 xff0c 一直到下午睡醒 xff08 论好的睡眠的重要性 xff09 xff0c 在一篇帖子中看到一种新的写法 xff0c opencv3将IplImage转换为Mat格式的写法 xff0c 在我们的代码中采用