国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像

這篇具有很好參考價(jià)值的文章主要介紹了《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。


《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

空間點(diǎn) 投影到 相機(jī)成像平面

前面內(nèi)容總結(jié):
1、機(jī)器人如何表示自身位姿

視覺SLAM: 觀測主要是指 相機(jī)成像 的過程

投影過程描述: 針孔 + 畸變

相機(jī) 內(nèi)參 && 外參

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

像素坐標(biāo)系 與 成像平面之間,相差了一個(gè)縮放 和一個(gè)原點(diǎn)的平移。

像素坐標(biāo)系:
原點(diǎn) o ′ o^{\prime} o 位于 圖像 左上角
u u u 軸 向右 與 x x x 軸 平行
v v v 軸 向下 與 y y y 軸 平行

設(shè)像素坐標(biāo)在 u u u 軸 上縮放了 α \alpha α 倍 , 在 v v v 軸 上縮放了 β \beta β 倍。同時(shí)原點(diǎn) 平移了 [ c x , c y ] T [c_x, c_y]^T [cx?,cy?]T
則 點(diǎn) p ′ p^{\prime} p 的坐標(biāo) 與像素坐標(biāo) [ u , v ] T [u, v]^T [u,v]T 之間的關(guān)系
{ u = α X ′ + c x = 由式 5.2 α ? f X Z + c x = 令 f x = α f f x X Z + c x v = β Y ′ + c y = 由式 5.2 β ? f Y Z + c x = 令 f y = β f f y Y Z + c y \begin{equation*} \begin{cases} u = \alpha X^{\prime} + c_x \overset{由式5.2}{=} \alpha ·f\frac{X}{Z} + c_x \overset{令f_x = \alpha f}{=} f_x\frac{X}{Z} + c_x \\ v = \beta Y^{\prime} + c_y \overset{由式5.2}{=} \beta·f\frac{Y}{Z} + c_x \overset{令f_y = \beta f}{=} f_y\frac{Y}{Z} + c_y \end{cases} \end{equation*} {u=αX+cx?=由式5.2α?fZX?+cx?=fx?=αffx?ZX?+cx?v=βY+cy?=由式5.2β?fZY?+cx?=fy?=βffy?ZY?+cy???

其中 f x = α f , f y = β f f_x = \alpha f, f_y=\beta f fx?=αf,fy?=βf
f f f 的單位 為
α , β \alpha, \beta α,β 的單位為 像素/米
f x , f y f_x, f_y fx?,fy? c x , c y c_x, c_y cx?,cy? 的單位為 像素。

[ u v 1 ] = [ f x 0 c x 0 f y c y 0 0 1 ] [ X Z Y Z 1 ] = 1 Z [ f x 0 c x 0 f y c y 0 0 1 ] [ X Y Z ] = d e f 1 Z K P \begin{align*}\begin{bmatrix}u\\ v\\ 1\end{bmatrix} &=\begin{bmatrix}f_x & 0 & c_x\\ 0 & f_y & c_y\\ 0 & 0 &1\end{bmatrix}\begin{bmatrix}\frac{X}{Z}\\ \frac{Y}{Z}\\ 1\end{bmatrix}\\ &=\frac{1}{Z}\begin{bmatrix}f_x & 0 & c_x\\ 0 & f_y & c_y\\ 0 & 0 &1\end{bmatrix}\begin{bmatrix}X\\ Y\\ Z\end{bmatrix}\\ &\overset{\mathrm{def}}{=} \frac{1}{Z}\bm{KP} \end{align*} ?uv1? ??= ?fx?00?0fy?0?cx?cy?1? ? ?ZX?ZY?1? ?=Z1? ?fx?00?0fy?0?cx?cy?1? ? ?XYZ? ?=defZ1?KP?

相機(jī)的內(nèi)參數(shù)(Camera Intrinsics) 矩陣 K \bm{K} K

K = [ f x 0 c x 0 f y c y 0 0 1 ] \bm{K} = \begin{bmatrix}f_x & 0 & c_x\\ 0 & f_y & c_y\\ 0 & 0 &1\end{bmatrix} K= ?fx?00?0fy?0?cx?cy?1? ?

標(biāo)定:自己確定相機(jī)的內(nèi)參【相機(jī)生產(chǎn)廠商未告知相機(jī)內(nèi)參的情形】

  • 標(biāo)定算法: 單目棋盤格張正友標(biāo)定法

相機(jī)在運(yùn)動(dòng) ——> P P P 的相機(jī)坐標(biāo) = 其世界坐標(biāo) P w \bm{P_\mathrm{w}} Pw? 根據(jù)相機(jī)位姿轉(zhuǎn)換到 相機(jī)坐標(biāo)系下。

Z P u v = Z [ u v 1 ] = K ( R P w + t ) = K T P w Z\bm{P}_{uv}=Z\begin{bmatrix} u \\v \\1\end{bmatrix}=\bm{K(RP_{\mathrm{w}}+t)=KTP_\mathrm{w}} ZPuv?=Z ?uv1? ?=K(RPw?+t)=KTPw?

相機(jī)的外參數(shù)(Camera Extrinsics):相機(jī)的位姿 R \bm{R} R , t \bm{t} t

機(jī)器人 或 自動(dòng)駕駛: 外參 = 相機(jī)坐標(biāo)系 到機(jī)器人本體坐標(biāo)系 之間的 變換。

  • 描述 相機(jī)安裝在什么地方

5.1.2 畸變模型

徑向畸變透鏡形狀引起的畸變(失真)。坐標(biāo)點(diǎn) 距離原點(diǎn)的長度發(fā)生了變化。
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

桶形畸變:圖像放大率 隨著 與光軸之間的距離 增加 而減小。
枕型畸變:圖像放大率 隨著 與光軸之間的距離 增加 而增加。

  • 穿過圖像中心和光軸有交點(diǎn)的直線還能保持形狀不變。

切向畸變:相機(jī)在在組裝過程中能使 透鏡和成像面 嚴(yán)格平行。水平夾角發(fā)行了變化。

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

通過5個(gè)畸變系數(shù)( k 1 , k 2 , k 3 , p 1 , p 2 k_1,k_2,k_3,p_1,p_2 k1?,k2?,k3?,p1?,p2?)找到某個(gè)點(diǎn)在像素平面的正確位置:
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

單目相機(jī)的成像過程

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

5.1.3 雙目相機(jī)模型

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
z ? f z = b ? u L + u R b \frac{z-f}{z}=\frac{b-u_L+u_R} zz?f?=bb?uL?+uR??
令 d = u L ? u R 令d = u_L-u_R d=uL??uR? 視差

z ? f z = b ? d b \frac{z-f}{z}=\frac{b-d} zz?f?=bb?d?

1 ? f z = 1 ? d b 1-\frac{f}{z}=1-\fracn5n3t3z 1?zf?=1?bd?

f z = d b \frac{f}{z}=\fracn5n3t3z zf?=bd?

z = f b d z=\frac{fb}n5n3t3z z=dfb?

由于計(jì)算量的原因,雙目深度估計(jì)需要使用 GPU 或 FPGA 來實(shí)時(shí)計(jì)算。

5.1.4 RGB-D 相機(jī)模型

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
RGB-D 相機(jī): 向探測目標(biāo) 發(fā)射一束 光線(通常是紅外光)。

RGB-D 不足:
1、用紅外光進(jìn)行深度測量,容易受到 日光或其他傳感器發(fā)射的紅外光干擾。不能在室外使用。
2、多個(gè)RGB-D相機(jī)之間也會(huì)相互干擾。
3、透射材質(zhì)因?yàn)榻邮詹坏椒瓷涔?,無法測量。

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
h h h 對(duì)應(yīng) 行數(shù)
w w w 對(duì)應(yīng) 列數(shù)

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
OpenCV: 通道順序?yàn)?BGR

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

Eigen對(duì)于固定大小的矩陣使用起來效率更高。

實(shí)踐

5.3.1 OpenCV 基礎(chǔ)操作 【Code】

OpenCV版本查看
python3 -c "import cv2; print(cv2.__version__)"

可能報(bào)錯(cuò)

/home/xixi/Downloads/slambook2-master/ch5/basicuse/basicuse.cpp:6:9: fatal error: opencv2/core/core.cpp: No such file or directory
    6 | #include<opencv2/core/core.cpp>

OpenCV沒安裝好
gtk/gtk.h報(bào)錯(cuò)鏈接
到 OpenCV 安裝包

mkdir build && cd build
cmake ..
make -j4  # 之前 -j8有誤,改4試試
sudo make install

——————————————————

mkdir build && cd build 
cmake ..
make 
./basicuse ubuntu.png   ## ubuntu.png 要放在 build文件夾里; 或者提供該圖片的絕對(duì)路徑;或相對(duì)于build文件夾的相對(duì)路徑

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(basicuse)

# 添加C++ 11 標(biāo)準(zhǔn)支持  nullptr  chrono
set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )


# 尋找 OpenCV 庫
find_package(OpenCV 4.2.0 REQUIRED)
#添加頭文件
include_directories(${OpenCV_INCLUDE_DIRS})


add_executable(basicuse basicuse.cpp)
# 鏈接OpenCV庫
target_link_libraries(basicuse ${OpenCV_LIBS})

basicuse.cpp

#include<iostream>
#include<chrono> // 計(jì)時(shí)

using namespace std;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>// high-level graphical user interface

using namespace cv;

int main(int argc, char **argv){
    // 讀取argv[1] 指定的圖像
    cv::Mat image;
    image = cv::imread(argv[1]);  // 從命令行的第一個(gè)參數(shù)中 讀取圖像位置

    // 判斷圖像是否 正確讀取
    if (image.data == nullptr){
        cerr << "文件" << argv[1] << "不存在。" << endl;
        return 0; 
    }

    // 輸出文件的基本信息
    cout << "圖像寬為" << image.cols << ",高為" << image.rows
    << ", 通道數(shù)為" << image.channels()  << endl;
    cv::imshow("image", image);
    cv::waitKey(0);  // 暫停程序,等待一個(gè)按鍵輸入


    cv::destroyAllWindows();
    return 0;
}

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

#include<iostream>
#include<chrono> // 計(jì)時(shí)

using namespace std;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>// high-level graphical user interface

using namespace cv;

int main(int argc, char **argv){
    // 讀取argv[1] 指定的圖像
    cv::Mat image;
    image = cv::imread(argv[1]);  // 從命令行的第一個(gè)參數(shù)中 讀取圖像位置

    // 判斷image的類型
    if (image.type() != CV_8UC1 && image.type() != CV_8UC3) {
        // 圖像類型不符合要求
        cout << "請(qǐng)輸入一張彩色圖或灰度圖." << endl;
        return 0;
    }

    // 遍歷圖像, 請(qǐng)注意以下遍歷方式亦可使用于隨機(jī)像素訪問
    // 使用 std::chrono 來給算法計(jì)時(shí)
    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 指向待訪問的像素?cái)?shù)據(jù)
        // 輸出該像素的每個(gè)通道,如果是灰度圖就只有一個(gè)通道
        for (int c = 0; c != image.channels(); c++) {
            unsigned char data = data_ptr[c]; // data為I(x,y)第c個(gè)通道的值
        }
        }
    }
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast < chrono::duration < double >> (t2 - t1);
    cout << "遍歷圖像用時(shí):" << time_used.count() << " 秒。" << endl;
    
    return 0;
}

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

#include<iostream>
#include<chrono> // 計(jì)時(shí)

using namespace std;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>// high-level graphical user interface

using namespace cv;

int main(int argc, char **argv){
    // 讀取argv[1] 指定的圖像
    cv::Mat image;
    image = cv::imread(argv[1]);  // 從命令行的第一個(gè)參數(shù)中 讀取圖像位置

    // 關(guān)于 cv::Mat 的拷貝
    // 直接賦值并不會(huì)拷貝數(shù)據(jù)   淺拷貝 會(huì) 同時(shí)修改原始數(shù)據(jù)
    cv::Mat image_another = image;
    // 修改 image_another 會(huì)導(dǎo)致 image 發(fā)生變化
    image_another(cv::Rect(0, 0, 100, 100)).setTo(0); // 將左上角100*100的塊置零
    cv::imshow("image", image);
    cv::waitKey(0);

    // 使用clone函數(shù)來拷貝數(shù)據(jù)
    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);

    // 對(duì)于圖像還有很多基本的操作,如剪切,旋轉(zhuǎn),縮放等,限于篇幅就不一一介紹了,請(qǐng)參看OpenCV官方文檔查詢每個(gè)函數(shù)的調(diào)用方法.
    cv::destroyAllWindows();

    return 0;
}

5.3.2 圖像去畸變 【Code】

cv::Undistort()

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(myOpenCV)

# 添加C++ 11 標(biāo)準(zhǔn)支持  nullptr  chrono
set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )


# 尋找 OpenCV 庫
find_package(OpenCV 4.2.0 REQUIRED)
#添加頭文件
include_directories(${OpenCV_INCLUDE_DIRS})


add_executable(myOpenCV undistortImage.cpp)
# 鏈接OpenCV庫
target_link_libraries(myOpenCV ${OpenCV_LIBS})


undistortImage.cpp

#include <opencv2/opencv.hpp>
#include <string>

using namespace std;

string image_file = "../distorted.png";   // 請(qǐng)確保路徑正確 

int main(int argc, char **argv) {

  // 本程序?qū)崿F(xiàn)去畸變部分的代碼。盡管我們可以調(diào)用OpenCV的去畸變,但自己實(shí)現(xiàn)一遍有助于理解。
  // 畸變參數(shù)
  double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
  // 內(nèi)參
  double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;

  cv::Mat image = cv::imread(image_file, 0);   // 圖像是灰度圖,CV_8UC1
  int rows = image.rows, cols = image.cols;
  cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1);   // 去畸變以后的圖

  // 計(jì)算去畸變后圖像的內(nèi)容
  for (int v = 0; v < rows; v++) {
    for (int u = 0; u < cols; u++) {
      // 按照公式,計(jì)算點(diǎn)(u,v)對(duì)應(yīng)到畸變圖像中的坐標(biāo)(u_distorted, v_distorted)
      double x = (u - cx) / fx, y = (v - cy) / fy;
      double r = sqrt(x * x + y * y);
      double x_distorted = x * (1 + k1 * r * r + k2 * r * r * r * r) + 2 * p1 * x * y + p2 * (r * r + 2 * x * x);
      double y_distorted = y * (1 + k1 * r * r + k2 * r * r * r * r) + p1 * (r * r + 2 * y * y) + 2 * p2 * x * y;
      double u_distorted = fx * x_distorted + cx;
      double v_distorted = fy * y_distorted + cy;

      // 賦值 (最近鄰插值)
      if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) {
        image_undistort.at<uchar>(v, u) = image.at<uchar>((int) v_distorted, (int) u_distorted);
      } else {
        image_undistort.at<uchar>(v, u) = 0;
      }
    }
  }

  // 畫圖去畸變后圖像
  cv::imshow("distorted", image);
  cv::imshow("undistorted", image_undistort);
  cv::waitKey();
  return 0;
}

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

5.4.1 雙目視覺 視差圖 點(diǎn)云 【Code】

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(stereoVision)

# 添加C++ 11 標(biāo)準(zhǔn)支持  nullptr  chrono
set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )


# 尋找 OpenCV 庫
find_package(OpenCV 4.2.0 REQUIRED)
#添加頭文件
include_directories(${OpenCV_INCLUDE_DIRS})

find_package(Pangolin REQUIRED)

add_executable(stereoVision stereoVision.cpp)
target_link_libraries(stereoVision ${OpenCV_LIBS} ${Pangolin_LIBRARIES})

stereoVision.cpp

#include <opencv2/opencv.hpp>
#include <vector>
#include <string>
#include <Eigen/Core>
#include <pangolin/pangolin.h>
#include <unistd.h>

using namespace std;
using namespace Eigen;

// 文件路徑
string left_file = "../left.png";
string right_file = "../right.png";

// 在pangolin中畫圖,已寫好,無需調(diào)整
void showPointCloud(
    const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud);

int main(int argc, char **argv) {

    // 內(nèi)參
    double fx = 718.856, fy = 718.856, cx = 607.1928, cy = 185.2157;
    // 基線
    double b = 0.573;

    // 讀取圖像
    cv::Mat left = cv::imread(left_file, 0);
    cv::Mat right = cv::imread(right_file, 0);
    cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(
        0, 96, 9, 8 * 9 * 9, 32 * 9 * 9, 1, 63, 10, 100, 32);    // 神奇的參數(shù)
    cv::Mat disparity_sgbm, disparity;
    sgbm->compute(left, right, disparity_sgbm);
    disparity_sgbm.convertTo(disparity, CV_32F, 1.0 / 16.0f);

    // 生成點(diǎn)云
    vector<Vector4d, Eigen::aligned_allocator<Vector4d>> pointcloud;

    // 如果你的機(jī)器慢,請(qǐng)把后面的v++和u++改成v+=2, u+=2
    for (int v = 0; v < left.rows; v++)
        for (int u = 0; u < left.cols; u++) {
            if (disparity.at<float>(v, u) <= 0.0 || disparity.at<float>(v, u) >= 96.0) continue;

            Vector4d point(0, 0, 0, left.at<uchar>(v, u) / 255.0); // 前三維為xyz,第四維為顏色

            // 根據(jù)雙目模型計(jì)算 point 的位置
            double x = (u - cx) / fx;
            double y = (v - cy) / fy;
            double depth = fx * b / (disparity.at<float>(v, u));
            point[0] = x * depth;
            point[1] = y * depth;
            point[2] = depth;

            pointcloud.push_back(point);
        }

    cv::imshow("disparity", disparity / 96.0);
    cv::waitKey(0);
    // 畫出點(diǎn)云
    showPointCloud(pointcloud);
    return 0;
}

void showPointCloud(const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud) {

    if (pointcloud.empty()) {
        cerr << "Point cloud is empty!" << endl;
        return;
    }

    pangolin::CreateWindowAndBind("Point Cloud Viewer", 1024, 768);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    pangolin::OpenGlRenderState s_cam(
        pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
        pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
    );

    pangolin::View &d_cam = pangolin::CreateDisplay()
        .SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f / 768.0f)
        .SetHandler(new pangolin::Handler3D(s_cam));

    while (pangolin::ShouldQuit() == false) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        d_cam.Activate(s_cam);
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        glPointSize(2);
        glBegin(GL_POINTS);
        for (auto &p: pointcloud) {
            glColor3f(p[3], p[3], p[3]);
            glVertex3d(p[0], p[1], p[2]);
        }
        glEnd();
        pangolin::FinishFrame();
        usleep(5000);   // sleep 5 ms
    }
    return;
}

視差圖:
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

byzanz-record -x 147 -y 76 -w 1386 -h 768  -d 15 --delay=5 -c  /home/xixi/myGIF/test.gif

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

5.4.2 RGB-D 點(diǎn)云 拼合成 地圖【Code】

通過物理方法 獲得 像素深度信息
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

mkdir build && cd build
cmake ..
make 
./joinMap

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(joinMap)

# 添加C++ 11 標(biāo)準(zhǔn)支持  nullptr  chrono
set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )

# 尋找 OpenCV 庫
find_package(OpenCV 4.2.0 REQUIRED)
#添加頭文件
include_directories(${OpenCV_INCLUDE_DIRS})

# Sophus 庫
find_package(Sophus REQUIRED)
include_directories(${Sophus_INCLUDE_DIRS})

#  Pangolin 庫
find_package(Pangolin REQUIRED)
include_directories(${Pangolin_INCLUDE_DIRS})

add_executable(joinMap joinMap.cpp)
target_link_libraries(joinMap ${OpenCV_LIBS} ${Pangolin_LIBRARIES} ${Sophus_LIBRARIES}) 
# 上面這句 一定要 鏈接到  Sophus

joinMap.cpp

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <boost/format.hpp>  // for formating strings
#include <pangolin/pangolin.h>
#include <sophus/se3.h>

using namespace Sophus;  // 原代碼少了 這句
using namespace std;
typedef vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> TrajectoryType;
typedef Eigen::Matrix<double, 6, 1> Vector6d;

// 在pangolin中畫圖,已寫好,無需調(diào)整
void showPointCloud(
    const vector<Vector6d, Eigen::aligned_allocator<Vector6d>> &pointcloud);

int main(int argc, char **argv) {
    vector<cv::Mat> colorImgs, depthImgs;    // 彩色圖和深度圖
    TrajectoryType poses;         // 相機(jī)位姿

    ifstream fin("../pose.txt");
    if (!fin) {
        cerr << "請(qǐng)?jiān)谟衟ose.txt的目錄下運(yùn)行此程序" << 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()));
        depthImgs.push_back(cv::imread((fmt % "depth" % (i + 1) % "pgm").str(), -1)); // 使用-1讀取原始圖像

        double data[7] = {0};
        for (auto &d:data)
            fin >> d;
        Sophus::SE3 pose(Eigen::Quaterniond(data[6], data[3], data[4], data[5]),
                          Eigen::Vector3d(data[0], data[1], data[2]));
        poses.push_back(pose);
    }

    // 計(jì)算點(diǎn)云并拼接
    // 相機(jī)內(nèi)參 
    double cx = 325.5;
    double cy = 253.5;
    double fx = 518.0;
    double fy = 519.0;
    double depthScale = 1000.0;
    vector<Vector6d, Eigen::aligned_allocator<Vector6d>> pointcloud;
    pointcloud.reserve(1000000);

    for (int i = 0; i < 5; i++) {
        cout << "轉(zhuǎn)換圖像中: " << i + 1 << endl;
        cv::Mat color = colorImgs[i];
        cv::Mat depth = depthImgs[i];
        Sophus::SE3 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]; // 深度值
                if (d == 0) continue; // 為0表示沒有測量到
                Eigen::Vector3d point;
                point[2] = double(d) / depthScale;
                point[0] = (u - cx) * point[2] / fx;
                point[1] = (v - cy) * point[2] / fy;
                Eigen::Vector3d pointWorld = T * point;

                Vector6d p;
                p.head<3>() = pointWorld;
                p[5] = color.data[v * color.step + u * color.channels()];   // blue
                p[4] = color.data[v * color.step + u * color.channels() + 1]; // green
                p[3] = color.data[v * color.step + u * color.channels() + 2]; // red
                pointcloud.push_back(p);
            }
    }

    cout << "點(diǎn)云共有" << pointcloud.size() << "個(gè)點(diǎn)." << endl;
    showPointCloud(pointcloud);
    return 0;
}

void showPointCloud(const vector<Vector6d, Eigen::aligned_allocator<Vector6d>> &pointcloud) {

    if (pointcloud.empty()) {
        cerr << "Point cloud is empty!" << endl;
        return;
    }

    pangolin::CreateWindowAndBind("Point Cloud Viewer", 1024, 768);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    pangolin::OpenGlRenderState s_cam(
        pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
        pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
    );

    pangolin::View &d_cam = pangolin::CreateDisplay()
        .SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f / 768.0f)
        .SetHandler(new pangolin::Handler3D(s_cam));

    while (pangolin::ShouldQuit() == false) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        d_cam.Activate(s_cam);
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        glPointSize(2);
        glBegin(GL_POINTS);
        for (auto &p: pointcloud) {
            glColor3d(p[3] / 255.0, p[4] / 255.0, p[5] / 255.0);
            glVertex3d(p[0], p[1], p[2]);
        }
        glEnd();
        pangolin::FinishFrame();
        usleep(5000);   // sleep 5 ms
    }
    return;
}

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

byzanz-record -x 72 -y 64 -w 998 -h 605  -d 15 --delay=5 -c  /home/xixi/myGIF/test.gif

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

習(xí)題

待做:

  • 找OpenCV里的標(biāo)定 方法
  • 整理鏈接里的內(nèi)容

《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

題1

相機(jī)內(nèi)參標(biāo)定

√ 題2

相機(jī)內(nèi)參 K \bm{K} K 的物理意義:可將世界坐標(biāo)系某點(diǎn) P P P歸一化坐標(biāo) 轉(zhuǎn)成 像素坐標(biāo) P u v = K [ X / Z , Y / Z , 1 ] T \bm{P_{uv}=K}[X/Z,Y/Z, 1]^T Puv?=K[X/Z,Y/Z,1]T

圖像分辨率指圖像中存儲(chǔ)的信息量,是每英寸圖像內(nèi)有多少個(gè)像素點(diǎn),分辨率的單位為PPI(Pixels Per Inch),通常叫做像素每英寸。
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM
當(dāng)分辨率變?yōu)樵瓉淼膬杀稌r(shí), 顯然對(duì)于同一位置,以像素為單位的 c x c_x cx? c y c_y cy? 均變?yōu)樵瓉淼?倍。而以 像素/每米 為單位的 α \alpha α β \beta β 變成原來的 2 倍。 f f f 不變,則 f x = α f f_x = \alpha f fx?=αf f y = β f f_y = \beta f fy?=βf 也變?yōu)樵瓉淼?2 倍。
綜上:當(dāng)相機(jī)的分辨率變?yōu)樵瓉淼?倍時(shí), c x c_x cx? , c y c_y cy? f x f_x fx? , f y f_y fy? 均變?yōu)樵瓉淼?2 倍。

題3

魚眼或全景相機(jī) 標(biāo)定
鏈接1
鏈接2
————————————

√ 題4

異同:
工業(yè)相機(jī)常見的曝光方式:
1、全局曝光(Global shutter,也稱全局快門、幀曝光

  • 當(dāng)光圈打開時(shí),工業(yè)相機(jī)中的圖像傳感器上所有像素點(diǎn)可以在同一時(shí)刻曝光,當(dāng)光圈關(guān)閉后,所有像素同時(shí)結(jié)束曝光,然后輸出像素?cái)?shù)據(jù)。全局曝光的工業(yè)相機(jī)可以一次拍攝物體的整體圖像后再輸出,因此在拍攝高速運(yùn)動(dòng)物體時(shí)圖像不會(huì)偏移,能夠達(dá)到無失真的效果。
  • CCD(電荷耦合)元件 為這種曝光 方式

2、卷簾曝光(Rolling shutter,也稱卷簾快門、行曝光

  • 采用的是逐行掃描逐行曝光的方式,當(dāng)上一行的所有像素同時(shí)曝光后,下一行的所有像素再同時(shí)曝光,直至所有行曝光完成。
  • 當(dāng)曝光不當(dāng)或物體移動(dòng)較快時(shí),會(huì)出現(xiàn)部分曝光(partial exposure)、斜坡圖形(skew)、晃動(dòng)(wobble) 等現(xiàn)象。這種Rolling shutter方式拍攝出現(xiàn)的現(xiàn)象,稱為“果凍效應(yīng)”。
  • 大部分CMOS相機(jī)使用卷簾快門(rolling shutter)

3、基于卷簾曝光并結(jié)合全局曝光優(yōu)勢(shì)的全局復(fù)位釋放曝光(Global Reset Release Shutter,GRR)

優(yōu)缺點(diǎn):
Global shutter適用于拍攝高速運(yùn)動(dòng)物體;且在光線有明暗變化的時(shí)候,Global shutter sensor不會(huì)有明暗瑕疵。
Global shutter需要對(duì)每個(gè)像素都要增加一個(gè)存儲(chǔ)單元,這樣增加了sensor的生產(chǎn)難度以及成本。
Rolling Shutter sensor適用于拍攝運(yùn)動(dòng)速度相對(duì)較的物體或場景,可獲得更高的成像信噪比。 Rolling Shutter 在低噪、像素?fù)p失、高感、動(dòng)態(tài)范圍等有優(yōu)勢(shì)。

————————

題5

RGB-D 相機(jī)標(biāo)定
《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像,機(jī)器人,SLAM

鏈接
鏈接2

題6

遍歷圖像的方法
鏈接
鏈接2

題7

OpenCV官方教程學(xué)習(xí)
官方文檔文章來源地址http://www.zghlxwxcb.cn/news/detail-728039.html

到了這里,關(guān)于《視覺 SLAM 十四講》V2 第 5 講 相機(jī)與圖像的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 視覺SLAM十四講——ch10實(shí)踐(后端2)

    視覺SLAM十四講——ch10實(shí)踐(后端2)

    視覺SLAM(Simultaneous Localization and Mapping)后端是一種用于處理視覺SLAM問題的算法。視覺SLAM是指機(jī)器在未知環(huán)境中同時(shí)實(shí)現(xiàn)自身的定位和地圖構(gòu)建的技術(shù)。 視覺SLAM后端的任務(wù)是在視覺SLAM中負(fù)責(zé)維護(hù)一個(gè)優(yōu)化后的地圖和機(jī)器人的軌跡。常見的視覺SLAM后端算法包括基于圖優(yōu)化的

    2024年02月09日
    瀏覽(20)
  • 視覺SLAM十四講——ch9實(shí)踐(后端1)

    視覺SLAM十四講——ch9實(shí)踐(后端1)

    Ceres BA使用的是BAL數(shù)據(jù)集。在本例中,使用problem-16-22106-pre.txt文件。 BAL的數(shù)據(jù)集自身存在的特殊 BAL的相機(jī)內(nèi)參模型由焦距f和畸變參數(shù)k1,k2給出。 因?yàn)锽AL數(shù)據(jù)在投影時(shí)假設(shè)投影平面在相機(jī)光心之后,所以按照我們之前用的模型計(jì)算,需要在投影之后乘以系數(shù)-1。 安裝meshlab,

    2024年02月09日
    瀏覽(21)
  • 《視覺SLAM十四講》報(bào)錯(cuò)信息和解決方案

    ch4-Sophus 編譯報(bào)錯(cuò) 報(bào)錯(cuò)信息: 解決方法:修改Sophus下的so2.cpp文件 將下面這個(gè)修改一下: 修改為: ch5/imageBasics 安裝opencv4.x報(bào)錯(cuò) 環(huán)境:Unbuntu22.04,安裝opencv4.x 報(bào)錯(cuò)信息: 解決方案:參照https://blog.csdn.net/qq_51022848/article/details/128095476 ch5/joinMap/CMakeLists.txt 編譯報(bào)錯(cuò) 報(bào)錯(cuò)信息:

    2024年02月14日
    瀏覽(45)
  • 踩坑 Sophus 模板庫安裝及編譯(視覺SLAM 十四講第二版 ch4 )

    踩坑 Sophus 模板庫安裝及編譯(視覺SLAM 十四講第二版 ch4 )

    在《視覺slam十四講》第二版中,第4、7、8、9、10講都需要Sophus庫,因此我們需要安裝Sophus庫,并且需要的是Sophus模板庫,因此很多人因?yàn)榘惭b了非模板版本導(dǎo)致報(bào)錯(cuò),下面提供Sophus模板版本安裝方式,以及對(duì)應(yīng)不報(bào)錯(cuò)版本。 只要是?3.3以上的版本即可 官網(wǎng)進(jìn)入,然后下載T

    2024年01月22日
    瀏覽(17)
  • slam十四講~環(huán)境安裝以及問題記錄

    slam十四講~環(huán)境安裝以及問題記錄

    參考資料: https://zhuanlan.zhihu.com/p/452256687 https://blog.csdn.net/qq_38629044/article/details/95355859 https://blog.csdn.net/Bonaventure/article/details/122835996 https://blog.csdn.net/weixin_44986556/article/details/108962861 https://blog.csdn.net/qq_38364548/article/details/122055690 https://blog.csdn.net/rong11417/article/details/103905794 http

    2023年04月15日
    瀏覽(34)
  • (視覺人機(jī)器視覺培訓(xùn))康耐視3DA5000標(biāo)定詳細(xì)流程(相機(jī)安裝于機(jī)器人上)

    (視覺人機(jī)器視覺培訓(xùn))康耐視3DA5000標(biāo)定詳細(xì)流程(相機(jī)安裝于機(jī)器人上)

    (Q有答疑)visionman基本腳本培訓(xùn)-康耐視Visionpro之Visual Studio -調(diào)試快速方法 1、打開,運(yùn)行A5000Viewer 2、修改相應(yīng)參數(shù),確認(rèn)圖像效果,并在Fifo取像工具自定義屬性中添加。 1、本次應(yīng)用為相機(jī)安裝在機(jī)器人六軸前段,標(biāo)定塊位于相機(jī)視野內(nèi)靜止不動(dòng),對(duì)于相機(jī)固定安裝稍有差異。

    2023年04月26日
    瀏覽(50)
  • 自學(xué)SLAM(8)《第四講:相機(jī)模型與非線性優(yōu)化》作業(yè)

    自學(xué)SLAM(8)《第四講:相機(jī)模型與非線性優(yōu)化》作業(yè)

    小編研究生的研究方向是視覺SLAM,目前在自學(xué),本篇文章為初學(xué)高翔老師課的第四次作業(yè)。 現(xiàn)實(shí)?活中的圖像總存在畸變。原則上來說,針孔透視相機(jī)應(yīng)該將三維世界中的直線投影成直線,但是當(dāng)我們使???和魚眼鏡頭時(shí),由于畸變的原因,直線在圖像?看起來是扭曲的

    2024年02月05日
    瀏覽(26)
  • 機(jī)器人學(xué)|手機(jī)玻璃加工全自動(dòng)化——AGV+機(jī)器人+視覺解決方案(含雙目三維視覺SLAM建圖、MATLAB的AGV路徑規(guī)劃導(dǎo)航避障、六軸機(jī)械手臂建模與路徑規(guī)劃仿真,附帶源代碼)

    機(jī)器人學(xué)|手機(jī)玻璃加工全自動(dòng)化——AGV+機(jī)器人+視覺解決方案(含雙目三維視覺SLAM建圖、MATLAB的AGV路徑規(guī)劃導(dǎo)航避障、六軸機(jī)械手臂建模與路徑規(guī)劃仿真,附帶源代碼)

    文章目錄 前言 一、國內(nèi)外移動(dòng)操作機(jī)器人現(xiàn)狀 二、方案概述 三、主要部件BOM清單 1.差動(dòng)輪式AGV: 2.UR5系列機(jī)械臂 3.Cognex智能相機(jī) 4.加工臺(tái) 5.控制系統(tǒng) 6.電源和電纜 四、技術(shù)點(diǎn)及工作流程 五、計(jì)算自動(dòng)化方案與人工方案成本收回時(shí)間 1.自動(dòng)化方案成本分析: 2.人工方案成本

    2024年01月22日
    瀏覽(16)
  • LabVIEW開發(fā)微控制器控制的并行機(jī)器人的實(shí)時(shí)視覺圖像處理

    LabVIEW開發(fā)微控制器控制的并行機(jī)器人的實(shí)時(shí)視覺圖像處理

    LabVIEW開發(fā)微控制器控制的并行機(jī)器人的實(shí)時(shí)視覺圖像處理 ? ? ? ? 通過相機(jī)視覺,以對(duì)目標(biāo)物體的不同顏色進(jìn)行分類,并與平行機(jī)器人一起拾取和放置物體。通過使用MATLAB?Simulink模擬合適的機(jī)器人工作空間來研究使用相機(jī)的效率和機(jī)器人的準(zhǔn)確性。機(jī)械臂以使用運(yùn)動(dòng)學(xué)計(jì)算

    2024年02月09日
    瀏覽(24)
  • 基于全景相機(jī)的視覺SLAM

    基于全景相機(jī)的視覺SLAM

    相機(jī)坐標(biāo)系中空間點(diǎn)投影到二維圖像的過程可以簡化為將空間點(diǎn)投影到單位球面上,然后將此球面展開成全景圖像。 式中:ri一空間點(diǎn)在相機(jī)坐標(biāo)系中與原點(diǎn)的距離;t0一投影函數(shù)??梢钥闯?,全景相機(jī)的投影過程是非線性的。 能看出全景圖像的畸變系數(shù)為cosp,圖2-4為全景機(jī)

    2024年02月10日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包