<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          圖像的點(diǎn)云拼接-原理講解與代碼實(shí)現(xiàn)

          共 8441字,需瀏覽 17分鐘

           ·

          2021-07-04 01:20

          理解好圖像的點(diǎn)云拼接,需要從相機(jī)的模型說(shuō)起。理解相機(jī)的成像原理之后,便可更為深刻的理解圖像的點(diǎn)云如何拼接在一起。


          首先說(shuō)下相機(jī)的概念與原理。



          相機(jī)概念與原理

          相機(jī)的作用:將三維世界中的坐標(biāo)點(diǎn)(單位為米)映射到二維圖像平面(單位為像素)。


          通常我們見(jiàn)到的相機(jī)都是針孔相機(jī),但是不是簡(jiǎn)單的 針孔,還有透鏡的畸變存在,所以在做圖像處理時(shí)要進(jìn)行畸變校正。


          由于畸變的存在,我們?cè)谑褂孟鄼C(jī)之前都要進(jìn)行相機(jī)標(biāo)定。


          目的就是求出內(nèi)參對(duì)于簡(jiǎn)單的應(yīng)用求出徑向畸變切向畸變就夠了。


          所謂的外參就是相機(jī)的位姿。


          有了外參、內(nèi)參、圖像、深度信息 便可以把圖像中的點(diǎn),轉(zhuǎn)到世界坐標(biāo)系下,并帶有RGB的顏色。就形成了所謂的點(diǎn)云。


          相關(guān)的公式也很好理解 ,就是通過(guò)相似三角形的原理。

          注意其中fx 、fy、 cx 、cy也就是相機(jī)的內(nèi)參了。在相機(jī)出廠時(shí)會(huì)給出。


          理解了相機(jī)的概念與原理,來(lái)編輯代碼實(shí)現(xiàn)下。



          Code實(shí)現(xiàn)

          全部代碼

          先放上全部代碼,再進(jìn)行分段講解


          #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;//彩色圖和深度圖    vector<Eigen::Isometry3d> poses;//相機(jī)位姿     ifstream fin("../pose.txt");//文件讀入 相機(jī)位置 文件     if(!fin)//相機(jī)位姿讀入失敗    {        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 讀取原始圖像           //讀取相機(jī)位姿        double data[7]={0};        for(auto& d:data)               fin>>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 );    }      //相機(jī)內(nèi)參    double cx=325.5;    double cy=253.5;    double fx=518.0;    double fy=519.0;    double depthScale = 1000.0;      cout<<"正在將圖像轉(zhuǎn)換為點(diǎn)云..."<<endl;     //定義點(diǎn)云使用的格式  用XYZRGB    typedef pcl::PointXYZRGB PointT;    typedef pcl::PointCloud<PointT> PointCloud;     //新建一個(gè)點(diǎn)云    PointCloud::Ptr pointCloud( new PointCloud );     for(int i=0;i<5;i++)    {        cout<<"轉(zhuǎn)換圖像中:"<<i+1<<endl;        cv::Mat color = colorImgs[i];//獲得 要處理的彩色圖像        cv::Mat depth = depthImgs[i];//獲得 要處理的深度圖像        Eigen::Isometry3d T = poses[i];//獲得 對(duì)應(yīng)的pose        for(int v=0 ; v<color.rows;v++)//處理每個(gè)像素        {            for(int u=0 ; u<color.cols;u++)            {                unsigned int d = depth.ptr<unsigned short>(v)[u];//深度值                if(d==0) continue;//為0 表示沒(méi)有測(cè)量到                 Eigen::Vector3d point;//相機(jī)坐標(biāo)系下的點(diǎn)                //計(jì)算相機(jī)坐標(biāo)系下的點(diǎn)的坐標(biāo)                point[2] = double(d)/depthScale;                point[0] = (u-cx)*point[2]/fx;                point[1] = (v-cy)*point[2]/fy;                  Eigen::Vector3d pointWorld = T*point;//轉(zhuǎn)換到世界坐標(biāo)系下                  PointT p;//聲明點(diǎn)云                p.x = pointWorld[0];//賦值點(diǎn)云位置                p.y = pointWorld[1];                 p.z = pointWorld[2];                 p.b = color.data[ v*color.step+u*color.channels() ];//賦值點(diǎn)云對(duì)應(yīng)RGB顏色                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<<"點(diǎn)云共有"<<pointCloud->size()<<"個(gè)點(diǎn)."<<endl;         pcl::io::savePCDFileBinary("map.pcd", *pointCloud );//保存點(diǎn)云文件      return 0;}


          代碼講解


              vector<cv::Mat> colorImgs,depthImgs;//彩色圖和深度圖    vector<Eigen::Isometry3d> poses;//相機(jī)位姿     ifstream fin("../pose.txt");//文件讀入 相機(jī)位置 文件     if(!fin)//相機(jī)位姿讀入失敗    {        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 讀取原始圖像           //讀取相機(jī)位姿        double data[7]={0};        for(auto& d:data)               fin>>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 );    }


          讀取對(duì)應(yīng)路徑下的彩色圖像、深度圖像、相機(jī)的位姿。


          上面說(shuō)了,有了這三個(gè)量再加上相機(jī)內(nèi)參,就可以得到點(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;


          傳說(shuō)中的相機(jī)內(nèi)參


              //定義點(diǎn)云使用的格式  用XYZRGB    typedef pcl::PointXYZRGB PointT;    typedef pcl::PointCloud<PointT> PointCloud;     //新建一個(gè)點(diǎn)云    PointCloud::Ptr pointCloud( new PointCloud );


          聲明pcl的格式創(chuàng)建一個(gè)點(diǎn)云,然后開(kāi)始for循環(huán)處理每一張圖片和對(duì)應(yīng)的深度圖片與相機(jī)位姿。


                  cv::Mat color = colorImgs[i];//獲得 要處理的彩色圖像        cv::Mat depth = depthImgs[i];//獲得 要處理的深度圖像        Eigen::Isometry3d T = poses[i];//獲得 對(duì)應(yīng)的pose


          得到要處理的彩色圖像深度圖像對(duì)應(yīng)的pose,然后for循環(huán)處理每一個(gè)像素。


          unsigned int d = depth.ptr<unsigned short>(v)[u];//深度值


          得到深度信息


                          Eigen::Vector3d point;//相機(jī)坐標(biāo)系下的點(diǎn)                //計(jì)算相機(jī)坐標(biāo)系下的點(diǎn)的坐標(biāo)                point[2] = double(d)/depthScale;                point[0] = (u-cx)*point[2]/fx;                point[1] = (v-cy)*point[2]/fy;


          通過(guò):

          這個(gè)公式得到相機(jī)坐標(biāo)系下的 x,y,z


            Eigen::Vector3d pointWorld = T*point;//轉(zhuǎn)換到世界坐標(biāo)系下


          相機(jī)坐標(biāo)系下的點(diǎn)通過(guò)坐標(biāo)變換轉(zhuǎn)到世界坐標(biāo)系下。


                          PointT p;//聲明點(diǎn)云                p.x = pointWorld[0];//賦值點(diǎn)云位置                p.y = pointWorld[1];                 p.z = pointWorld[2];                 p.b = color.data[ v*color.step+u*color.channels() ];//賦值點(diǎn)云對(duì)應(yīng)RGB顏色                p.g = color.data[ v*color.step+u*color.channels()+1 ];                p.r = color.data[ v*color.step+u*color.channels()+2 ];


          賦值點(diǎn)云的坐標(biāo)與顏色。


           pcl::io::savePCDFileBinary("map.pcd", *pointCloud );//保存點(diǎn)云文件


          保存成點(diǎn)云文件。

          —版權(quán)聲明—

          來(lái)源:古月居

          僅用于學(xué)術(shù)分享,版權(quán)屬于原作者。

          若有侵權(quán),請(qǐng)聯(lián)系微信號(hào):yiyang-sy 刪除或修改!


          —THE END—
          瀏覽 65
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美在线三级 | 先锋影音精品三级 | 人人爱人人摸人人曹 | 成人片777 | www国产夜插内射视频网站 |