继续跟随《视觉SLAM十四讲》学习SLAM问题,由于理论方面已经有一些研究,主要缺乏的是在LINUX下的实战开发能力,因而从代码开始分析入手,同时对C++11进行回顾。
1. openCV 中的Mat类
Mat类用于存储图像信息,详细信息见 https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html ,这里我们主要针对几个常用的点展开来记录。
- 类的结构
Mat是由两个数据部分,包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。矩阵头部的大小是恒定的。然而,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。 - 构造函数
Mat类的默认构造函数为cv::Mat::Mat(),生成一个矩阵并由OpenCV提供的函数(一般是Mat::create() 和 cv::imread() )来分配储存空间。OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针,例如:
/ 关于 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 );
也就是说直接拷贝拷贝的只是指向数据矩阵的指针,对任意一个指针指向内容的修改会影响其他所有的,销毁时则是每销毁一个引用计数会-1(每copy一次同样会+1),直到计数为0,矩阵数据会被清理。
常用的构造函数还包括
Mat (int rows, int cols, int type)
Mat (Size size, int type)
Mat (int rows, int cols, int type, const Scalar &s)
Mat (Size size, int type, const Scalar &s)
Mat (int ndims, const int *sizes, int type)
Mat (int ndims, const int *sizes, int type, const Scalar &s)
Mat (const Mat &m)
Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)
Mat (Size size, int type, void *data, size_t step=AUTO_STEP)
Mat (int ndims, const int *sizes, int type, void *data, const size_t *steps=0)
Mat (const Mat &m, const Range &rowRange, const Range&colRange = Range::all())
Mat (const Mat &m, const Rect &roi)
Mat (const Mat &m, const Range *ranges)
- 成员函数
Mat成员函数较常用的包括at(获取某位置的元素值),convertTo(将源文件转化为目标数据格式),clone(复制图像矩阵数据),create(分配矩阵的存储单元),type(获取数据类型),channels(获取通道数)(rows和cols属于Member Data调用不需要加括号),详细的说明可见 https://blog.csdn.net/guyuealian/article/details/70159660
2. 一个方便的读取矩阵txt文件的方式
ifstream fin("文件名.txt");
for ( int i=0; i<矩阵行数; i++ )
{
double data[矩阵列数] = {0};
for ( auto& d:data )
fin>>d;
}
3. 两种常用的访问图像像素的方法
- 视觉SLAM十四讲中的方法(使用指针)
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个通道的值
}
}
}
- 使用at
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j<image.cols; j++)
{
image.at<Vec3b>(i,j)[0]=image.at<Vec3b>(i,j)[0]/div*div+div/2;
image.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[1]/div*div+div/2;
image.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[2]/div*div+div/2;
}
}
其他方法可以参考 https://blog.csdn.net/xiaowei_cqu/article/details/19839019
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)