Skip to content

Latest commit

 

History

History
282 lines (193 loc) · 12.1 KB

知识积累.md

File metadata and controls

282 lines (193 loc) · 12.1 KB

1、cv::FileStorage: 处理 XML/YAML/JSON 的文件的类(读写)

2、

#include <unistd.h>
usleep();// 将当前进程指定挂起一段时间单位为 us

3、 fixedsetprecision 使用:

ofstream f;
f << fixed;
f << setprecision(6) << 2.125; // 此时 f 中保留的数据是 2.125000 保留 6 位小数。

如果单独使用 setprecision(6),则表示保留 6 位数字,即 2.12500,通过 fixed 转变为保留小数的个数

参考:https://blog.csdn.net/u011321546/article/details/9293547

4、cv::Mat 选取矩阵内部元素

cv::Mat::rowRange(0,3); // 表示选取0 1 2 行数据
cv::Mat::col(3); // 表示选取标号 3 的列数据
cv::Mat::clone(); // 表示复制当前矩阵元素并返回

参考:https://blog.csdn.net/sinat_29089097/article/details/75533538

5、cv::Mat 返回矩阵类型,float,对角阵

 cv::Mat K = cv::Mat::eye(3,3,CV_32F);

cv::Mat 普通赋值函数其实内部操作是引用(相当于 shared_ptr),只有调用 copyTo() 或者 clone() 才会真正的拷贝,所以在使用时需要注意写入矩阵时,对其他引用这个矩阵的操作有没有影响。

需要注意一点,cv::Mat::copyTo(dst) 函数,会自动调节 dst 矩阵大小。

pTracker->mImGray.copyTo(mIm); // 会自动调节 mIm 的大小。根据 mImGray 的矩阵大小。

6、cv::cvColor(src, dst, CV_RGB2GRAY) 将 src 图像转换为 dst 图像,以 RGB-Gray 的转换为例,前提是,src 图像是以 RGB 形式读取的!

 cvtColor(mImGray, mImGray, CV_RGB2GRAY);  // 此时转换成的 8 位灰度图为单通道!

7、std::copy 拷贝输入序列元素到指定容器中 ,下面有两种方式使用 copy。

  • vector 元素内容大小已知。即 vector<>::resize() 指定大小。然后直接用已知序列拷贝例如:

    vector<int>vec;
    vec.resize(3);
    int a[3] = {1, 2, 3};
    std::copy(a, a+3, vec.begin());

    需要注意的是 vec size 必须要大于序列 a 元素大小。否则复制出错。

  • vector 元素个数未知,即仅仅定义个 vector 元素,std::vector<int> vec;,然后通过 std::back_inserter() 模板函数提供一个末尾元素的迭代器。在利用 std::copy 进行拷贝。这里不需要知道 vector 容器的大小。例如:

        vector<int> vec;
        //vec.resize(3);	// 此时不需要 vec 大小!
        int a[3] = { 1, 2, 3};
        //std::copy(a,a+3,vec.begin());    
        std::copy(a,a+3,std::back_inserter(vec));	// 使得将 a,a+3 元素不断的插入 vec 末尾
        for (vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++) {
            cout << *iter << endl;
        }

8、普通数组可以强制转换为类的指针。

    // 因为 cv::Point 类型非继承别的类,内部仅仅存储 _x, _y 二维平面坐标。
    const Point* pattern0 = (const Point*)bit_pattern_31_;  // ??

但是需要强调的是: Point 类内部元素与 bit_pattern_31_ 内部元素数据类型必须一致。这样在物理内存上,每个元素所占物理单元大小一致!

9、std::fill(first, end, value)在 [vector::first, end] 里面拷贝 value。用法:

 fill(mvIniMatches.begin(),mvIniMatches.end(),-1);

10、c++ 中 usleep(微秒单位) 睡眠多少微秒,让当前线程挂起,释放 cpu,进而去执行其他线程。

11、vector 中 reserve 和 resize 方法。参考

vector::reserve() 不会影响 size () 大小

vector::reserve() 方法用来重新分配 vector 容量的大小

只有当申请的容量大小 n ,大于 vector 的当前容量时,才会重新为 vector 分配存储空间

reserve 方法对于 vector 的 size 没有任何影响

当 Push_back() 元素时,超过容量大小,那么此时 vector 会增加 当前容量/2 那么多空间。

reserve() 只能把容量增大,不能减小

vector::resize() 大小,改变 vector 的 size 大小,即改变内部有效值。

如果 resize(n) 中 n 小于 vector 中元素数量,则会删除多的元素,使得 vector 大小为n

如果 n > vector 元素数量且小于容量,那么就会在尾部插入那么多数据。可以通过 resize(n,val) 通过 val 传递值。否则默认值初始化。

如果 n > 容量,那么则会自动重新分配存储空间并值初始化

使用例子:

std::vector<cv::Mat> vDesc;
vDesc.reserve(Descriptors.rows);    // reserve() 是将容器容量扩充到当前指定的大小。恰好不浪费内存

12、cv::InputArraycv::OutputArray 对象都可以通过 对象.getMat() 将其变为 cv::Mat()类型。

13、几个近似函数

cv::cvRound() 四舍五入

cv::cvFloor() 不大于自变量的最大整数

cv::cvCeil() 不小于自变量的最小整数

14、cv::resize(src, dst, dsize, fx, fy, interpolation);将 src 图像上采样或者降采样为 dst。

采样因子根据 fx,fy 或者dsize来定。下面分别列出两种方法的调用:

// 假设图像降采样 1/2,下面两种方式获得采样后的图像
// 根据 fx,fy
cv::resize(imag_in, imag_out, cv::Size(), 0.5, 0.5); // 最后一个参数默认双线性差值
// 根据 dsize
Size sz(cvRound((float)imag_in.cols*0.5), cvRound((float)imag_in.rows*0.5)); 
cv::resize(imag_in, imag_out, sz, 0, 0);

复制原始图像 src 到目的图像 dst 中,并扩充边界。有两种情况,

一、 具体过程可以参考 ORBextractor.cc 中 1121 行开始的 ComputePyramid 函数

src 与 dst 没有关系。此时只是将 src 复制到 dst 中,然后在 dst 中,以 src 大小开始推断拓展边界值。(推断根据 BORDER_REFLECT_101 )。此时 temp 的大小实际上要比 image 大 EDGE_THRESHOLD 边界值。

cv::copyMakeBorder(image, temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, BORDER_REFLECT_101);
其中 image 图像复制到 temp 中,其中 ima

二、src 是 dst 的一部分。此时只是在此基础上以 src 边界(+EDGE_THRESHOLD)处的值直接作为结果。如果 dst 那些除了 src 部分的值是垃圾值,此时就不是我们想要的结果。我们为了使用推断方法,就是跟第一种方式一样。我们需要添加 BORDER_ISOLATED 参数

cv::copyMakeBorder(mvImagePyramid[level], temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
                           BORDER_REFLECT_101+BORDER_ISOLATED);  

15、lit = lNodes.erase(lit); ,节点擦除后自动指向下一个节点。

16、pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair。

(1)STL中的map就是将key和value放在一起来保存。

(2)另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。

17、cv::fastAtan(y,x);// 表示返回的是角度 [0-360]

18、创建指定大小的矩阵

cv::OutputArray::create(row,col,cv_8U)

19、高斯模糊方法。

// 此时是自己根据 Size(7,7) 2,2自己计算高斯核,然后进行图像的高斯模糊,具体如何进行自定义计算高斯核:
// 可以参考:https://www.cnblogs.com/tornadomeet/archive/2012/03/10/2389617.html
cv::GaussianBlur(workingMat, workingMat, Size(7, 7), 2, 2, BORDER_REFLECT_101);

20、下面是用来调用 cv::undistortPoints() 的去除关键点畸变。第一个参数要求 NX1 的 2通道

 cv::Mat mat(N,2,CV_32F);    // 单通道 N X 2矩阵内部元素是 32 float
  mat = mat.reshape(2);   // 表示将 mat 修改为 双通道,即变为了 N x 1 维的矩阵,每一维内部是两个通道,一个通道一个值

21、mGrid 是一个二维数组,内部元素是 vector 类型

 std::vector<std::size_t> mGrid[FRAME_GRID_COLS][FRAME_GRID_ROWS];

22、cv::Mat 另一种方式:

const int *pa = a.ptr<int32_t>();

这里因为 a 是 cv::Mat 1xN 的矩阵。所以这里就是直接获取元素指针!

23、std::vector::clear() 表示清理内部资源,使得 size() = 0;

24、rowRange(0,3) 去除 0 1 2 行

R.copyTo(P2.rowRange(0,3).colRange(0,3));

25、std::set 不会插入相同的元素。

26、学习一下 orb-slam2 中。从一个带有重复元素的vector 中。把所有的不重复的元素拿出来。可以利用一个 set<>,vector<> 两个集合即可。通过 set 的 count() 方法对于没有存储的元素。添加到 vector<>。可以看 KeyFrameDatabase.cc 中倒数 10 行左右的代码!

27、下面为什么会成立,还不太清除,但是高翔 14 讲 3 章显示那里确实这么用的!

pangolin::OpenGlMatrix M;

Eigen::Matrix<double, 4, 4> mm = M;

28、cv::WaitKey(10); 表示当前暂停 10ms。一般是在显示图像后加上这么一句话。如果用户按键,那么就会继续执行。没有按键就会等待 10ms 然后自动继续执行。cv::WaitKey(0) 表示程序会无限制的等待用户的按键事件。参考

29、在 g2o 中,我们加入节点时,标号可以不用顺序加入。只要标号唯一即可。

30、cv::reduce(P,C,1,CV_REDUCE_SUM); 这里把 3x3 矩阵 P 列对应元素全部求和,变为一个 3x1 向量 C 。这里的 cv::Mat P; // 3x3 列为点坐标 cv::Mat C ; // 3x1 列为点坐标

31、计算对称矩阵的特征值和特征向量可以调用函数 cv::eigen(N, eval, evec);

cv::Mat N;4x4 。这里的 eval 是一个向量,按照降序排列。evec 是矩阵,按照行存储,依次对应特征值。 evec[0] 其实就是最大特征值对应的特征向量。如果这里用了非对称矩阵,那么此时仅仅求出特征值。不会给出特征向量。如果要求解非对称矩阵的特征值和特征向量可以调用 cv::eigenNonSymmetric()

32、cv::Rodrigues(vec,mR12i); 给定一个轴角,计算一个旋转矩阵!或者相反输入输出

33、double nom = Pr1.dot(P3); 两个向量点乘,如果两个元素都是相同大小的矩阵,那么就把矩阵变为列向量。然后对应位置相乘

34、cv::pow(P3,2,aux_P3); 将 P3 矩阵的每个元素都平方,然后更新到新的矩阵 aux_P3

35、assert 的一个比较好的方法。即能提示错误信息,又能保证正确条件下不会出错。

// 下面这句正常执行时,不会出现后面的错误信息
assert(0 < 1 && "index out of bounds");
// 下面在 1 < 0 明显错误的情况下,就会提示后面的信息
assert(1 < 0 && "index out of bounds");

36、在使用 g2o 时,位姿---位姿 边的构建需要看 Optimizer::OptimizeEssentialGraph()闭环边设置过程。g2o::EdgeSim3 需要两个位姿节点。然后测量值是 0-->1 的变换。

37、在 PnPsolver::compute_pose() 函数中

  double mtm[12 * 12], d[12], ut[12 * 12];
  CvMat MtM = cvMat(12, 12, CV_64F, mtm);
  CvMat D   = cvMat(12,  1, CV_64F, d);
  CvMat Ut  = cvMat(12, 12, CV_64F, ut); // 直接绑定 Ut 和 ut 数组,操作 Ut 就是在操作 ut

  // 求解 Mx=0 方程,利用奇异值分解
  cvMulTransposed(M, &MtM, 1); // M^TM
  cvSVD(&MtM, &D, &Ut, 0, CV_SVD_MODIFY_A | CV_SVD_U_T); // MtM 是对称矩阵,那么后面选项是 CV_SVD_U_T 时,表示 奇异值分解的 U^T 直接给 Ut。然后 U=V ,所以这里 V 的位置直接写成 0.他们都是奇异值对应的特征向量
  cvReleaseMat(&M);

38、获取 4 个数或者更多(不超过 10 个)的数中的最小值和最大值,可以用连续的 min、max 来得到。max(arg1, max(arg2, max(arg3, arg4)))。同理 min()也适用。

39、g2o::SE3Quat::to_homogeneous_matrix() 将 SE3 变为 4x4 的矩阵。Eigen::Matrix<double, 4, 4> 类型。

40、cv::Mat 和 Eigen::Matrix 之间元素的转变需要一个个元素间赋值

41、cv::Mat 通道的变换

cv::Mat mat(N,2,CV_32F);    // 单通道 N X 2矩阵内部元素是 32 float
mat = mat.reshape(2);   // 表示将 mat 修改为 双通道,即变为了 N x 1 维的矩阵,每一维内部是两个通道,一个通道一个值
cv::undistortPoints(mat,mat,mK,mDistCoef,cv::Mat(),mK); // 利用 opencv 去除失真???带细看!
    mat=mat.reshape(1); // 从新变为单通道 NX2矩阵

42、