1. 程式人生 > >從零開始學習SLAM:openCV

從零開始學習SLAM:openCV

繼續跟隨《視覺SLAM十四講》學習SLAM問題,由於理論方面已經有一些研究,主要缺乏的是在LINUX下的實戰開發能力,因而從程式碼開始分析入手,同時對C++11進行回顧。

1. openCV 中的Mat類

  1. 類的結構 Mat是由兩個資料部分,包含資訊有矩陣的大小,用於儲存的方法,矩陣儲存的地址等的矩陣頭和一個指標,指向包含了畫素值的矩陣(可根據選擇用於儲存的方法採用任何維度儲存資料)。矩陣頭部的大小是恆定的。然而,矩陣本身的大小因影象的不同而不同,通常是較大的數量級。
  2. 建構函式 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)
  1. 成員函式 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. 兩種常用的訪問影象畫素的方法

  1. 視覺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個通道的值
            }
        }
    }
  1. 使用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;
		} 
	}