当前位置: 首页 > news >正文

自学SLAM(6)相机与图像实践:OpenCV处理图像与图像拼接(点云)

前言

如果写过SLAM14讲第一次的作业,或者看过我之前的运行ORB_SLAM2教程应该都安装过OpenCV了,如果没有安装,没关系,可以看我之前的博客,里面有如何安装OpenCV。
链接: 运行ORB-SLAM2(含OpenCV的安装)

文章目录

  • 前言
  • 1.OpenCV的图像操作
  • 2.使用OpenCV进行RGB-D图像拼接(点云)


1.OpenCV的图像操作

让我们先来看一段代码,学习一下OpenCV的函数调用。
改代码中,演示了如下几个操作:图像读取,显示,像素遍历,复制,赋值等。大部分的注解已经写在代码中。编译该程序时,需要在CMakeLists.txt中添加OpenCV的头文件,然后将程序链接到库文件上。

imageBasics.cpp:

#include <iostream>
#include <chrono>
using namespace std;#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>int main ( int argc, char** argv )
{// 读取argv[1]指定的图像cv::Mat image;image = cv::imread ( argv[1] ); //cv::imread函数读取指定路径下的图像// 判断图像文件是否正确读取if ( image.data == nullptr ) //数据不存在,可能是文件不存在{cerr<<"文件"<<argv[1]<<"不存在."<<endl;return 0;}// 文件顺利读取, 首先输出一些基本信息cout<<"图像宽为"<<image.cols<<",高为"<<image.rows<<",通道数为"<<image.channels()<<endl;cv::imshow ( "image", image );      // 用cv::imshow显示图像cv::waitKey ( 0 );                  // 暂停程序,等待一个按键输入// 判断image的类型if ( image.type() != CV_8UC1 && image.type() != CV_8UC3 ){// 图像类型不符合要求cout<<"请输入一张彩色图或灰度图."<<endl;return 0;}// 遍历图像, 请注意以下遍历方式亦可使用于随机像素访问// 使用 std::chrono 来给算法计时chrono::steady_clock::time_point t1 = chrono::steady_clock::now();for ( size_t y=0; y<image.rows; y++ ){// 用cv::Mat::ptr获得图像的行指针unsigned char* row_ptr = image.ptr<unsigned char> ( y );  // row_ptr是第y行的头指针for ( size_t x=0; x<image.cols; x++ ){// 访问位于 x,y 处的像素unsigned char* data_ptr = &row_ptr[ x*image.channels() ]; // data_ptr 指向待访问的像素数据// 输出该像素的每个通道,如果是灰度图就只有一个通道for ( int c = 0; c != image.channels(); c++ ){unsigned char data = data_ptr[c]; // data为I(x,y)第c个通道的值}}}chrono::steady_clock::time_point t2 = chrono::steady_clock::now();chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>( t2-t1 );cout<<"遍历图像用时:"<<time_used.count()<<" 秒。"<<endl;// 关于 cv::Mat 的拷贝// 直接赋值并不会拷贝数据cv::Mat image_another = image;// 修改 image_another 会导致 image 发生变化image_another ( cv::Rect ( 0,0,100,100 ) ).setTo ( 0 ); // 将左上角100*100的块置零cv::imshow ( "image", image );cv::waitKey ( 0 );// 使用clone函数来拷贝数据cv::Mat image_clone = image.clone();image_clone ( cv::Rect ( 0,0,100,100 ) ).setTo ( 255 );cv::imshow ( "image", image );cv::imshow ( "image_clone", image_clone );cv::waitKey ( 0 );// 对于图像还有很多基本的操作,如剪切,旋转,缩放等,限于篇幅就不一一介绍了,请参看OpenCV官方文档查询每个函数的调用方法.cv::destroyAllWindows();return 0;
}

CMakeLists.txt:

cmake_minimum_required( VERSION 2.8 )
project( imageBasics )# 添加c++ 11标准支持
set( CMAKE_CXX_FLAGS "-std=c++11" )# 寻找OpenCV库
find_package( OpenCV 3 REQUIRED )
# 添加头文件
include_directories( ${OpenCV_INCLUDE_DIRS} )add_executable( imageBasics imageBasics.cpp )
# 链接OpenCV库
target_link_libraries( imageBasics ${OpenCV_LIBS} )

然后我们尝试使用OpenCV打开一张图片:
在这里插入图片描述
在这里插入图片描述

2.使用OpenCV进行RGB-D图像拼接(点云)

在这里插入图片描述
joinMap.cpp:

#include <iostream>
#include <fstream>
using namespace std;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <Eigen/Geometry> 
#include <boost/format.hpp>  // for formating strings
#include <pcl/point_types.h> 
#include <pcl/io/pcd_io.h> 
#include <pcl/visualization/pcl_visualizer.h>int main( int argc, char** argv )
{vector<cv::Mat> colorImgs, depthImgs;    // colorImgs:彩色图;depthImgs:深度图vector<Eigen::Isometry3d, Eigen::aligned_allocator<Eigen::Isometry3d>> poses;   // 相机位姿//iftream的对象假设为fin,fin在读取数据的时候会根据你的输出对象来选择输出的方式。ifstream fin("./pose.txt");if (!fin){cerr<<"请在有pose.txt的目录下运行此程序"<<endl;return 1;}for ( int i=0; i<5; i++ ){boost::format fmt( "./%s/%d.%s" ); //图像文件格式colorImgs.push_back( cv::imread( (fmt%"color"%(i+1)%"png").str() ));/*cv::Mat img =cv::imread(argv[1],-1)函数原型Mat imread( const String& filename, int flags = IMREAD_COLOR );第一个参数是图片的绝对地址;第二个参数表示图片读入的方式(flags可以缺省,缺省时flags=1,表示以彩色图片方式读入图片);flags>0时表示以彩色方式读入图片;flags=0时表示以灰度图方式读入图片;flags<0时表示以图片的本来的格式读入图片;*/depthImgs.push_back( cv::imread( (fmt%"depth"%(i+1)%"pgm").str(), -1 )); // 使用-1读取原始图像double data[7] = {0};for ( auto& d:data )fin>>d; //将深度值文件一行一行读进d中Eigen::Quaterniond q( data[6], data[3], data[4], data[5] ); //旋转四元数Eigen::Isometry3d T(q);T.pretranslate( Eigen::Vector3d( data[0], data[1], data[2] )); //平移向量poses.push_back( T );}// 计算点云并拼接// 相机内参 double cx = 325.5;double cy = 253.5;double fx = 518.0;double fy = 519.0;double depthScale = 1000.0;cout<<"正在将图像转换为点云..."<<endl;// 定义点云使用的格式:这里用的是XYZRGBtypedef pcl::PointXYZRGB PointT; typedef pcl::PointCloud<PointT> PointCloud;// 新建一个点云PointCloud::Ptr pointCloud( new PointCloud ); for ( int i=0; i<5; i++ ){cout<<"转换图像中: "<<i+1<<endl; cv::Mat color = colorImgs[i]; //像素值 cv::Mat depth = depthImgs[i]; //每个像素值对应的深度值Eigen::Isometry3d T = poses[i]; //每张图片对应的位姿for ( int v=0; v<color.rows; v++ )for ( int u=0; u<color.cols; u++ ){unsigned int d = depth.ptr<unsigned short> ( v )[u]; // 深度值/*d==0:表示该像素点没有深度值(不可能),所以就抛弃该点,不再计算相机坐标系下的坐标值(X,Y,Z)*/if ( d==0 ) continue; // 为0表示没有测量到//point:相机坐标系下的坐标值(X,Y,Z)Eigen::Vector3d point; point[2] = double(d)/depthScale; point[0] = (u-cx)*point[2]/fx;point[1] = (v-cy)*point[2]/fy; // pointWorld:世界坐标Eigen::Vector3d pointWorld = T*point;// p:点云(每个点云按照[XYZRGB]的格式表示)PointT p ;p.x = pointWorld[0];p.y = pointWorld[1];p.z = pointWorld[2];p.b = color.data[ v*color.step+u*color.channels() ];p.g = color.data[ v*color.step+u*color.channels()+1 ];p.r = color.data[ v*color.step+u*color.channels()+2 ];pointCloud->points.push_back( p );}}pointCloud->is_dense = false;cout<<"点云共有"<<pointCloud->size()<<"个点."<<endl;pcl::io::savePCDFileBinary("map.pcd", *pointCloud );return 0;
}

CMakeLists.txt:

cmake_minimum_required( VERSION 2.8 )
project( joinMap )set( CMAKE_BUILD_TYPE Release )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )# opencv 
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )# eigen 
include_directories( "/usr/include/eigen3/" )# pcl 
find_package( PCL REQUIRED COMPONENT common io )
include_directories( ${PCL_INCLUDE_DIRS} )
add_definitions( ${PCL_DEFINITIONS} )add_executable( joinMap joinMap.cpp )
target_link_libraries( joinMap ${OpenCV_LIBS} ${PCL_LIBRARIES} )

这里点云我们用的是pcl的库,所以需要安装一些pcl的库

安装命令如下:

sudo apt-get install libpcl-dev
sudo apt-get install pcl-tools

然后就可以进行编译,进入我们创建的build文件夹

cmake ..
make
cd ..
build/joinMap 
pcl_viewer map.pcd 

点云图就出来了:

在这里插入图片描述
放大点云图:
在这里插入图片描述

相关文章:

自学SLAM(6)相机与图像实践:OpenCV处理图像与图像拼接(点云)

前言 如果写过SLAM14讲第一次的作业&#xff0c;或者看过我之前的运行ORB_SLAM2教程应该都安装过OpenCV了&#xff0c;如果没有安装&#xff0c;没关系&#xff0c;可以看我之前的博客&#xff0c;里面有如何安装OpenCV。 链接: 运行ORB-SLAM2&#xff08;含OpenCV的安装&…...

伊朗网络间谍组织针对中东金融和政府部门

导语 近日&#xff0c;以色列网络安全公司Check Point与Sygnia发现了一起针对中东金融、政府、军事和电信部门的网络间谍活动。这一活动由伊朗国家情报和安全部门&#xff08;MOIS&#xff09;支持的威胁行为者发起&#xff0c;被称为"Scarred Manticore"。该组织被认…...

基于51单片机土壤湿度检测及自动浇花系统仿真(带时间显示)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;单片机浇花 获取完整源码源文件仿真源文件原理图源文件论文报告等 单片机土壤湿度检测及自动浇花系统仿真&#xff08;带时间显示&#xff09; 具体功能&#xff1a; &#xff08;1&#xff09;液晶第一行显示实际湿度&am…...

typeScript基础使用与进阶

typeScript基础使用与进阶 一、初始typeScript1.1 js的超集1.2 编译器编译为js代码1.3 完全兼容js1.4 静态类型检查器 二、ts的安装与编译2.1 ts的安装2.2 ts编译成js2.2.1 手动编译2.2.2 自动编译 三、ts基础使用3.1 类型声明3.1.1 基础类型3.1.2 数组3.1.3 对象3.1.4 any类型…...

云智慧联合北航提出智能运维(AIOps)大语言模型及评测基准

随着各行业数字化转型需求的不断提高&#xff0c;人工智能、云计算、大数据等新技术的应用已不仅仅是一个趋势。各行业企业和组织纷纷投入大量资源&#xff0c;以满足日益挑剔的市场需求&#xff0c;追求可持续性和竞争力&#xff0c;这也让运维行业迎来了前所未有的挑战和机遇…...

高效处理异常值的算法:One-class SVM模型的自动化方案

一、引言 数据清洗和异常值处理在数据分析和机器学习任务中扮演着关键的角色。清洗数据可以提高数据质量&#xff0c;消除噪声和错误&#xff0c;从而确保后续分析和建模的准确性和可靠性。而异常值则可能对数据分析结果产生严重影响&#xff0c;导致误导性的结论和决策。因此&…...

Docker DeskTop安装与启动(Windows版本)

一、官网下载Docker安装包 Docker官网如下&#xff1a; Docker官网不同操作系统下载页面https://docs.docker.com/desktop/install/windows-install/ 二、安装Docker DeskTop 2.1 双击 Docker Installer.exe 以运行安装程序 2.2 安装操作 默认勾选&#xff0c;具体操作如下…...

数据结构:邻接矩阵与邻接表

模型图 邻接矩阵 用于反应图中任意两点之间的关联&#xff0c;用二维数组表示比较方便 以行坐标为起点&#xff0c;列坐标为终点如果两个点之间有边&#xff0c;那么标记为绿色&#xff0c;如图&#xff1a; 适合表示稠密矩阵 邻接表 用一维数组 链表的形式表示&#xff…...

python PyQt5 MySQL GUI 学生信息管理系统

学生信息管理系统 本系统使用python&#xff0c;pyqt5&#xff0c;数据库使用MySQL&#xff0c;实现windowsGUI应用。 python使用pymysql模块操作数据库代码 import pymysqldef handle_db(cmd, sql):result None# print(f" sql {sql}")# 连接数据库conn pymysql…...

[SSD综述1.6] SSD固态硬盘参数图文解析_选购固态硬盘就像买衣服?

依公知及经验整理,原创保护,禁止转载。 专栏 《SSD入门到精通系列》 <<<< 返回总目录 <<<< ​ 传统的 HDD 是“马达+磁头+磁盘”的机械结构,而 SSD 则是“闪存介质+主控”的纯半导体芯片存储结构,两者在数据存储介质和读写方式上有着本质区别,这…...

【计算机网络 - 自顶向下方法】第一章习题答案

P2 Question&#xff1a;   式 (1-1) 给出了经传输速率为 R 的 N 段链路发送长度为 L 的一个分组的端到端时延。 对于经过 N 段链路一个接一个地发送 P 个这样的分组&#xff0c;一般化地表示出这个公式。 Answer&#xff1a;    N ∗ L R \frac{N*L}{R} RN∗L​时&#x…...

零基础搭建Nextcloud私有云盘并通过内网穿透实现远程访问

文章目录 摘要1. 环境搭建2. 测试局域网访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问 4 配置固定http公网地址4.1 保留一个二级子域名4.1 配置固定二级子域名4.3 测试访问公网固定二级子域名 摘要 Nextcloud,它是ownCloud的一个分支,是一个文件共享服…...

element ui多选框编辑时无法选中的解决办法

<!--v-model绑定的值必须是[]&#xff0c;不能是字符串--><el-form-item label"配布对象" prop"reptGroupArray" > <!--多选--><el-checkbox-group v-model"form.reptGroupArray" size"small" change"check…...

Android Studio布局

线性布局 水平或竖直排列子元素的布局容器 相对布局 可针对容器内每个子元素设置相对位置&#xff08;相对于父容器或同级子元素的位置&#xff09; 网格布局 找了下面这篇文章连接可以参考&#xff08;不再赘述&#xff09; GridLayout(网格布局) | 菜鸟教程 (runoob.com) …...

2.10 CSS BFC

1.简介 BFC是Block Formatting Context(块级格式上下文)&#xff0c;可以理解成元素的一个“特异功能”。该“特异功能”&#xff0c;在默认的情况下处于关闭状态;当元素满足了某些条件后&#xff0c;该"特异功能被激活。所谓激活"特异功能”&#xff0c;专业点说就…...

iSlide2024一款基于PPT的插件工具包含38个设计辅助功能

根据使用者情况表明iSlide 是一款拥有30W素材的PPT高效设计软件&#xff0c;可提高90%工作效率&#xff0c;现全球已有超过1400万使用者&#xff0c;智能排版原创高品模板可商用图形&#xff0c;真正摆脱PPT的束缚&#xff0c;把精力用在该用的地方。我们都明白islide插件功能特…...

ATE新能源汽车充电桩自动负载测试系统

随着新能源汽车的普及&#xff0c;充电桩的需求也在不断增加&#xff0c;为了确保充电桩的性能和安全性&#xff0c;对其进行负载测试是非常重要的。ATE新能源汽车充电桩自动负载测试系统是一种专门用于检测充电桩性能的设备&#xff0c;它可以模拟各种实际使用场景&#xff0c…...

机器学习笔记 - 感知器的数学表达

一、假设前提 感知机(或称感知器,Perceptron)是Frank Rosenblatt在1957年就职于Cornell航空实验室(Cornell Aeronautical Laboratory)时所发明的一种人工神经网络。 它可以被视为一种最简单形式的前馈神经网络,是一种二元线性分类模型,其输入为实例的特征向量,输出为实…...

JavaScript 自定义对象

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>JS-定义对象</title> </head><body&g…...

UNI-APP_ios自动适应底部安全区背景,修改安全区背景

自动适应&#xff08;推荐&#xff09; 将所有 iPhone X&#xff08;刘海屏) 底部安全区域背景颜色 自动适应&#xff0c;当前页面什么颜色会自动调整。 1.打开 manifest.json &#xff0c;打开源码视图 2.找到 app-plus 配置项&#xff0c;添加以下代码 "safearea&quo…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...