《點(diǎn)云庫(kù)PCL學(xué)習(xí)教程》第4章-輸入、輸出(IO)_第1頁(yè)
《點(diǎn)云庫(kù)PCL學(xué)習(xí)教程》第4章-輸入、輸出(IO)_第2頁(yè)
《點(diǎn)云庫(kù)PCL學(xué)習(xí)教程》第4章-輸入、輸出(IO)_第3頁(yè)
《點(diǎn)云庫(kù)PCL學(xué)習(xí)教程》第4章-輸入、輸出(IO)_第4頁(yè)
《點(diǎn)云庫(kù)PCL學(xué)習(xí)教程》第4章-輸入、輸出(IO)_第5頁(yè)
已閱讀5頁(yè),還剩77頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第4章輸入、輸出(IO)12021/8/17PCL中所有的處理都是基于點(diǎn)云展開的,利用不同的設(shè)備獲取點(diǎn)云、存儲(chǔ)點(diǎn)云等都是點(diǎn)云處理前后必須做的流程,PCL中有自己設(shè)計(jì)的內(nèi)部PCD文件格式,為此,設(shè)計(jì)讀寫該格式以及與其他3D文件格式之間進(jìn)行轉(zhuǎn)化的接口類都是很必要的,目前PCL內(nèi)部支持對(duì)常用的3D格式文件的打開和存儲(chǔ)操作,以及與PCD內(nèi)部格式之間的互相轉(zhuǎn)化。本章首先對(duì)PCL中支持的點(diǎn)云獲取設(shè)備(如kinect)以及OpenNI開源框架作一個(gè)基本介紹,其次對(duì)PCL中的I/O模塊及相關(guān)類進(jìn)行簡(jiǎn)單說(shuō)明,最后通過(guò)應(yīng)用實(shí)例來(lái)展示如何對(duì)PCL中I/O模塊進(jìn)行靈活運(yùn)用。22021/8/17本章各小節(jié)目錄4.1I/O涉及的設(shè)備及相關(guān)概念簡(jiǎn)介4.2PCL中I/O模塊及類介紹4.3應(yīng)用實(shí)例解析32021/8/174.1I/O涉及的設(shè)備及相關(guān)概念簡(jiǎn)介42021/8/174.1.1OpenNI開源框架OpenNI(開放式自然交互)來(lái)源于由業(yè)界領(lǐng)導(dǎo)的一個(gè)非營(yíng)利性組織,創(chuàng)建于2010年11月,專注于提高和改善自然交互設(shè)備與應(yīng)用軟件的互操作能力。其官方網(wǎng)站于12月8號(hào)正式公開,主要成員之一是PrimeSense公司(Kinect的核心芯片正是由這家公司提供),其他成員還包括開發(fā)ROS的機(jī)器人公司W(wǎng)illowGarage,以及游戲公司Side-Kick等。OpenNI是一個(gè)多語(yǔ)言、跨平臺(tái)的框架,它定義了一套用于編寫通用自然交互應(yīng)用的API。OpenNI的主要目的就是形成標(biāo)準(zhǔn)的API,便于下面兩個(gè)接口之間進(jìn)行通信:(1)視覺(jué)和音頻傳感器(用來(lái)感知周圍環(huán)境信息)。52021/8/17(2)視覺(jué)和音頻感知中間件(用來(lái)對(duì)應(yīng)用場(chǎng)景中所記錄的音頻和視覺(jué)數(shù)據(jù)進(jìn)行分析與理解,例如能夠接收一份可見(jiàn)的圖像數(shù)據(jù)并返回從中檢測(cè)到的手掌位置信息)。OpenNI提供了一組基于傳感器設(shè)備實(shí)現(xiàn)的API和另外一組由中間件組件實(shí)現(xiàn)的API,打破了傳感器和中間件之間的依賴關(guān)系。這樣,使用OpenNIAPI開發(fā)應(yīng)用程序時(shí)就不需要在各種中間件模塊的上層操作上浪費(fèi)時(shí)間,可以做到一次編寫、隨處部署。OpenNI的這種分層設(shè)計(jì)機(jī)制允許中間件開發(fā)者可以直接基于最原始的數(shù)據(jù)格式編寫算法,而不管這些數(shù)據(jù)是由何種傳感器設(shè)備產(chǎn)生,同時(shí)也讓傳感器生產(chǎn)商制造的設(shè)備能用于任何OpenNI兼容的應(yīng)用程序。OpenNI的這套標(biāo)準(zhǔn)化API使得自然交互應(yīng)用開發(fā)人員62021/8/17可以利用由傳感器輸入并計(jì)算過(guò)的數(shù)據(jù)類型,很方便地跟蹤處理現(xiàn)實(shí)生活中的場(chǎng)景(例如,可以是表示人體全身的數(shù)據(jù),也可以是表示手的位置數(shù)據(jù),或者僅僅是深度圖里面的一組像素等)。這樣可以保證編寫應(yīng)用程序的時(shí)候,不用考慮傳感器或中間件供應(yīng)商相關(guān)的細(xì)節(jié)。圖4-1展示了OpenNI框架的應(yīng)用概念,分為三層:(1)應(yīng)用層:基于OpenNI實(shí)現(xiàn)的自然交互應(yīng)用軟件。(2)中間件接口層:代表OpenNI本身,提供了傳感器和中間件之間的交互接口。(3)硬件設(shè)備層:列出了捕捉視覺(jué)和音頻數(shù)據(jù)的多種硬件設(shè)備。72021/8/174.1.2OpenNI兼容設(shè)備OpenNI目前已成為PCL集成進(jìn)來(lái)的第一個(gè)設(shè)備相關(guān)的第三方庫(kù),用來(lái)抓取OpenNI兼容設(shè)備中的點(diǎn)云數(shù)據(jù)。上節(jié)描述的OpenNI應(yīng)用框架說(shuō)明,只要底層的設(shè)備傳感器設(shè)備與OpenNI兼容,都可以作為點(diǎn)云數(shù)據(jù)輸入源,圖4-2則展示了目前流行的OpenNI兼容設(shè)備。其中,PrimesenseReferenceDesign、MicrosoftKinect和AsusXtionPro這3種攝像頭設(shè)備均進(jìn)行了OpenNI兼容性測(cè)試。選擇其中任何一個(gè)設(shè)備進(jìn)行點(diǎn)云數(shù)據(jù)采集,都可以經(jīng)OpenNI處理后轉(zhuǎn)化為標(biāo)準(zhǔn)數(shù)據(jù)供上層應(yīng)用使用。如今,OpenNI已成為微軟xbox360配件kinect在PC上的開源驅(qū)動(dòng)中必須安裝的一個(gè)API。82021/8/174.2PCL中I/O模塊及類介紹PCL中I/O庫(kù)提供了點(diǎn)云文件輸入輸出相關(guān)的操作類,并封裝了OpenNI兼容的設(shè)備源數(shù)據(jù)獲取接口,可直接從眾多感知設(shè)備獲取點(diǎn)云圖像等數(shù)據(jù)。I/O模塊利用21個(gè)類與28個(gè)函數(shù)實(shí)現(xiàn)了對(duì)點(diǎn)云的獲取、讀入、存儲(chǔ)等相關(guān)操作,其依賴于pcl_common和pcl_octree模塊以及OpenNI外部開發(fā)包。92021/8/174.2.1I/O模塊中類以及全局函數(shù)說(shuō)明I/O模塊中目前共有21個(gè)類,隨著RGDB設(shè)備的流行必將引入更多的設(shè)備相關(guān)的I/O擴(kuò)展,以后有可能增加以下幾類。1.classpcl::FileReader類FileReader定義了PCD文件的讀取接口,主要用做其他讀取類的父類。從它繼承的子類必須實(shí)現(xiàn)自己的讀取函數(shù),即該類中的純虛函數(shù)其繼承關(guān)系如圖4-3所示。但為了保持向后兼容,提供了FILE_V6版本文件讀取的實(shí)現(xiàn)函數(shù)。102021/8/17類FileReader關(guān)鍵成員函數(shù):virtualintreadHeader(conststd::string&file_name,sensor_msgs::PointCloud2&cloud,Eigen::Vector4f&origin,Eigen::Quaternionf&orientation,int&file_version,int&data_type,unsignedint&data_idx,constintoffset=0)=0純虛函數(shù),定義讀取點(diǎn)云文件頭的接口函數(shù),其參數(shù)意義:file_name讀取文件的文件名。cloud存儲(chǔ)讀取后的點(diǎn)云數(shù)據(jù),但只填充文件頭(關(guān)于PCD文件格式詳見(jiàn)本章后面實(shí)例分析)。origin點(diǎn)云獲取原點(diǎn),該參數(shù)只有在文件版本大于FILE_V7才存在,否則為NULL。orientation點(diǎn)云獲取方向,該參數(shù)只有在文件版本大于FILE_V7才存在,否則為NULL。file_version文件版本(FILE_V7或者FILE_V6)。112021/8/17data_type數(shù)據(jù)類型(二進(jìn)制置為1,ASCII碼置為0)。data_idx數(shù)據(jù)偏移文件頭末尾的偏移量。offset文件頭偏移文件開始的偏移量。virtualintread(conststd::string&file_name,sensor_msgs::PointCloud2&cloud,Eigen::Vector4f&origin,Eigen::Quaternionf&orientation,int&file_version,constintoffset=0)=0為純虛函數(shù),定義讀取文件數(shù)據(jù)的接口函數(shù),讀取文件中的點(diǎn)云數(shù)據(jù)存儲(chǔ)到cloud對(duì)象中,其他參數(shù)同上函數(shù)。intread(conststd::string&file_name,sensor_msgs::PointCloud2&cloud,constintoffset=0)功能同上函數(shù)(僅適用于FILE_V6版本文件獲取,因?yàn)閟ensor_msgs::PointCloud2不包含傳感器原點(diǎn)和方向數(shù)據(jù),若讀取高版本數(shù)據(jù)會(huì)產(chǎn)生警告信息)。122021/8/17template<typenamePointT>intread(conststd::string&file_name,pcl::PointCloud<PointT>&cloud,constintoffset=0)功能同上函數(shù),只是帶有模板參數(shù)的成員函數(shù)。2.classpcl::FileWriter類FileWriter與FileReader對(duì)應(yīng),是寫入PCD文件的類接口定義,可以作為其他寫入類的父類。從它繼承的子類必須實(shí)現(xiàn)自己的寫入函數(shù),即該類中的純虛函數(shù),其繼承關(guān)系如圖4-4所示。132021/8/17類FileWriter關(guān)鍵成員函數(shù):virtualintwrite(conststd::string&file_name,constsensor_msgs::PointCloud2&cloud,constEigen::Vector4f&origin=Eigen::Vector4f::Zero(),constEigen::Quaternionf&orientation=Eigen::Quaternionf::Identity(),constboolbinary=false)=0;點(diǎn)云寫入到對(duì)應(yīng)文件的純虛函數(shù)接口定義,其參數(shù)意義:file_name寫入文件的文件名。cloud需要寫入的點(diǎn)云對(duì)象。origin寫入文件頭的點(diǎn)云獲取原點(diǎn),默認(rèn)為(0,0,0,0)。orientation寫入文件頭的點(diǎn)云獲取方向。binary設(shè)置寫入時(shí)的類型(true為二進(jìn)制,false為ASCII碼,默認(rèn)為ASCII碼)。142021/8/17template<typenamePointT>intwrite(conststd::string&file_name,constpcl::PointCloud<PointT>&cloud,constboolbinary=false)功能同上函數(shù),只是添加了模板參數(shù)的模板成員函數(shù)。3.classpcl::Grabber類Grabber為PCL1.X對(duì)應(yīng)的設(shè)備驅(qū)動(dòng)接口的基類定義,繼承關(guān)系如圖4-5所示。152021/8/17類Grabber關(guān)鍵成員函數(shù):template<typenameT>boost::signals2::connectionregisterCallback(constboost::function<T>&callback)提供回調(diào)函數(shù)指針,當(dāng)獲取每幀圖像或點(diǎn)云數(shù)據(jù)時(shí)都會(huì)啟動(dòng)回調(diào)函數(shù):template<typenameT>boolprovidesCallback()const判斷是否提供回調(diào)函數(shù):virtualvoidstart()=0啟動(dòng)設(shè)備,開始傳輸數(shù)據(jù)流:virtualvoidstop()=0停止設(shè)備上的數(shù)據(jù)流傳輸:virtualstd::stringgetName()const=0162021/8/17返回明確的子類名字:virtualboolisRunning()const=0判斷是否在傳輸數(shù)據(jù)流:virtualfloatgetFramesPerSecond()const=0獲取FPS幀率,即每秒多少幀數(shù)據(jù)。4.classopenni_wrapper::OpenNIDevice類OpenNIDevice定義OpenNI設(shè)備的基類,繼承該基類可以實(shí)現(xiàn)不同的OpenNI設(shè)備子類,用于獲取包括紅外數(shù)據(jù)、RGB數(shù)據(jù)、深度圖像數(shù)據(jù)等。繼承關(guān)系如圖4-6所示,目前包括如下設(shè)備PrimesensePSDK,MicrosoftKinect,AsusXtionPro/Live。172021/8/17類OpenNIDevice關(guān)鍵成員函數(shù):boolfindCompatibleImageMode(constXnMapOutputMode&output_mode,XnMapOutputMode&mode)constthrow()查詢是否有與output_mode對(duì)應(yīng)的圖像模式匹配的輸出模式,如果有則返回true并且存儲(chǔ)兼容模式在mode中,否返回值為false。例如設(shè)備支持30Hz的VGA模式,而請(qǐng)求輸出為30Hz的QVGA模式則通過(guò)下采樣是可以兼容的,但是設(shè)備支持25Hz的VGA而請(qǐng)求為30Hz的SXGA就不兼容。boolfindCompatibleDepthMode(constXnMapOutputMode&output_mode,XnMapOutputMode&mode)constthrow()功能和參數(shù)同上,只是針對(duì)深度圖像的模式,并非上述彩色圖像的模式。boolisImageModeSupported(constXnMapOutputMode&output_mode)constthrow()182021/8/17只判斷是否支持該output_mode所給定的圖像模式,支持返回true,否則返回false。boolisDepthModeSupported(constXnMapOutputMode&output_mode)constthrow()只判斷是否支持該output_mode所給定的深度圖像模式,支持返回true,否則返回false。constXnMapOutputMode&getDefaultImageMode()constthrow()constXnMapOutputMode&getDefaultDepthMode()constthrow()constXnMapOutputMode&getDefaultIRMode()constthrow()以上三個(gè)函數(shù)分別是獲取默認(rèn)的RGB、深度、紅外圖像的輸出模式。voidsetImageOutputMode(constXnMapOutputMode&output_mode)192021/8/17voidsetDepthOutputMode(constXnMapOutputMode&output_mode)voidsetIROutputMode(constXnMapOutputMode&output_mode)以上三個(gè)函數(shù)分別是設(shè)置RGB、深度、紅外圖像的輸出模式。XnMapOutputModegetImageOutputMode()constXnMapOutputModegetDepthOutputMode()constXnMapOutputModegetIROutputMode()const以上三個(gè)函數(shù)分別是獲取當(dāng)前的RGB、深度、紅外圖像的輸出模式。voidsetDepthRegistration(boolon_off)設(shè)置深度圖像是否與RGB圖像對(duì)齊。boolisDepthRegistrationSupported()constthrow()判斷設(shè)備是否支持深度圖像與RGB圖像對(duì)齊voidsetSynchronization(boolon_off)202021/8/17設(shè)置設(shè)備是否同步輸出RGB和深度圖像。boolisSynchronized()constthrow()判斷設(shè)備是否同步輸出RGB和深度圖像,如果是返回true,否則返回false。boolisSynchronizationSupported()constthrow()判斷設(shè)備是否支持同步輸出RGB和深度圖像。boolisDepthCropped()const返回深度圖像是否被裁剪過(guò),是為true,否則為false。voidsetDepthCropping(unsignedx,unsignedy,unsignedwidth,unsignedheight)打開深度圖像的裁剪,x、y分別為兩個(gè)方向上的起始裁剪位置,width和height分別為保留的x與y方向上的尺寸。floatgetImageFocalLength(intoutput_x_resolution=0)constthrow()212021/8/17獲取RGB圖像的焦距長(zhǎng)度(像素)。floatgetDepthFocalLength(intoutput_x_resolution=0)constthrow()獲取深度圖像的焦距長(zhǎng)度(像素)。floatgetBaseline()constthrow()獲取基線長(zhǎng)度。virtualvoidstartImageStream()virtualvoidstopImageStream()上面一對(duì)函數(shù)為啟動(dòng)和停止RGB數(shù)據(jù)流的采集。virtualvoidstartDepthStream()virtualvoidstopDepthStream()上面一對(duì)函數(shù)為啟動(dòng)和停止深度數(shù)據(jù)流的采集。virtualvoidstartIRStream()virtualvoidstopIRStream()222021/8/17上面一對(duì)函數(shù)為啟動(dòng)和停止紅外數(shù)據(jù)流的采集。boolhasImageStream()constthrow()boolhasDepthStream()constthrow()boolhasIRStream()constthrow()以上三個(gè)函數(shù)分別判斷設(shè)備是否支持RGB、深度、紅外圖像數(shù)據(jù)采集,如果是返回true,否則返回false。virtualboolisImageStreamRunning()constthrow()virtualboolisDepthStreamRunning()constthrow()virtualboolisIRStreamRunning()constthrow()以上三個(gè)函數(shù)分別判斷設(shè)備是否正在進(jìn)行RGB、深度、紅外圖像數(shù)據(jù)采集。CallbackHandleregisterImageCallback(constImageCallbackFunction&callback,void*cookie=NULL)throw()boolunregisterImageCallback(constCallbackHandle&callbackHandle)throw()232021/8/17上面一對(duì)函數(shù)分別為RGB圖像數(shù)據(jù)流的回調(diào)函數(shù)注冊(cè)與注銷。CallbackHandleregisterDepthCallback(constDepthImageCallbackFunction&callback,void*cookie=NULL)throw()boolunregisterDepthCallback(constCallbackHandle&callbackHandle)throw()上面一對(duì)函數(shù)分別為深度圖像數(shù)據(jù)流的回調(diào)函數(shù)注冊(cè)與注銷。CallbackHandleregisterIRCallback(constIRImageCallbackFunction&callback,void*cookie=NULL)throw()boolunregisterIRCallback(constCallbackHandle&callbackHandle)throw()上面一對(duì)函數(shù)分別為紅外圖像數(shù)據(jù)流的回調(diào)函數(shù)注冊(cè)與注銷。242021/8/17constchar*getSerialNumber()constthrow()獲取設(shè)備對(duì)應(yīng)的序列號(hào),注意該返回值有可能為空字符串。constchar*getConnectionString()constthrow()獲取設(shè)備連接字符串,一般格式為vendorID/productID@BusID/DeviceID。constchar*getVendorName()constthrow()constchar*getProductName()constthrow()unsignedshortgetVendorID()constthrow()unsignedshortgetProductID()constthrow()以上4個(gè)函數(shù)分別獲取廠商和產(chǎn)品的名字字符串及ID編號(hào)。unsignedchargetBus()constthrow()獲取設(shè)備所在的USB總線。252021/8/17unsignedchargetAddress()constthrow()獲取設(shè)備所在USB地址。voidsetRGBFocalLength(floatfocal_length)voidsetDepthFocalLength(floatfocal_length)以上兩個(gè)函數(shù)分別設(shè)定RGB與深度圖像獲取時(shí)的焦距大小。5.classopenni_wrapper::DeviceKinect6.classopenni_wrapper::DevicePrimesense7.classopenni_wrapper::DeviceXtionPro以上3個(gè)類分別封裝了Kinect、Primesense、XtionPro相關(guān)設(shè)備操作和數(shù)據(jù)獲取操作實(shí)現(xiàn),其詳細(xì)接口參考其父類OpenNIDevice的關(guān)鍵函數(shù)說(shuō)明。8.Classopenni_wrapper::DeviceONI262021/8/17封裝了利用ONI文件回放虛擬類kinect設(shè)備的操作和數(shù)據(jù)獲取操作實(shí)現(xiàn),其詳細(xì)接口參考其父類OpenNIDevice的關(guān)鍵函數(shù)說(shuō)明。9.Classopenni_wrapper::OpenNIDriver類OpenNIDriver采用單例模式實(shí)現(xiàn)對(duì)底層驅(qū)動(dòng)的封裝,里面包含一xn::Context對(duì)象,提供給所有設(shè)備使用。該類提供了枚舉和訪問(wèn)所有設(shè)備的方法實(shí)現(xiàn)。類OpenNIDevice關(guān)鍵成員函數(shù):unsignedupdateDeviceList()枚舉所有系統(tǒng)可以獲取的設(shè)備列表,返回獲取設(shè)備的數(shù)目。unsignedgetNumberDevices()constthrow()獲取系統(tǒng)可用設(shè)備的數(shù)目。272021/8/17boost::shared_ptr<OpenNIDevice>createVirtualDevice(conststd::string&path,boolrepeat,boolstream)const從ONI文件創(chuàng)建一虛擬設(shè)備,其中path為ONI文件的路徑,repeat設(shè)置是否虛擬設(shè)備支持無(wú)限循環(huán)從ONI文件獲取數(shù)據(jù),stream設(shè)置虛擬設(shè)備是支持?jǐn)?shù)據(jù)流形式的數(shù)據(jù)獲取還是引發(fā)式的數(shù)據(jù)獲取。boost::shared_ptr<OpenNIDevice>getDeviceByIndex(unsignedindex)const返回一設(shè)備,index為給定的設(shè)備索引。boost::shared_ptr<OpenNIDevice>getDeviceBySerialNumber(conststd::string&serial_number)const返回一設(shè)備,serial_number為給定的設(shè)備的序列號(hào)。boost::shared_ptr<OpenNIDevice>getDeviceByAddress(unsignedcharbus,unsignedcharaddress)const282021/8/17返回一設(shè)備,bus為USB設(shè)備總線號(hào),address為USB設(shè)備地址。constchar*getSerialNumber(unsignedindex)constthrow()獲取索引為index的設(shè)備序列號(hào),但該設(shè)備未被創(chuàng)建。constchar*getConnectionString(unsignedindex)constthrow()獲取索引為index的設(shè)備連接字符串,但該設(shè)備未被創(chuàng)建。voidstopAll()停止所有設(shè)備。staticOpenNIDriver&getInstance()為靜態(tài)成員函數(shù),獲取唯一的設(shè)備實(shí)例。staticvoidgetDeviceType(conststd::string&connection_string,unsignedshort&vendorId,unsignedshort&productId);為靜態(tài)成員函數(shù),獲取設(shè)備連接字符串存儲(chǔ)在connection_string,設(shè)備廠商及產(chǎn)品ID,存儲(chǔ)在292021/8/17為靜態(tài)成員函數(shù),獲取設(shè)備連接字符串存儲(chǔ)在connection_string,設(shè)備廠商及產(chǎn)品ID,存儲(chǔ)在vendorId、productId中。10.Classopenni_wrapper::OpenNIException類OpenNIException封裝一般的異常處理實(shí)現(xiàn),其關(guān)鍵成員函數(shù)如下:virtualconstchar*what()constthrow()返回異常消息字符串。conststd::string&getFunctionName()constthrow()返回發(fā)生異常的函數(shù)名。conststd::string&getFileName()constthrow()返回發(fā)生異常的文件名。unsignedgetLineNumber()constthrow()返回發(fā)生異常的行號(hào)。302021/8/1711.Classopenni_wrapper::Image類Image是簡(jiǎn)單的圖像數(shù)據(jù)封裝基類,其繼承關(guān)系如圖4-7所示。virtualboolisResizingSupported(unsignedinput_width,unsignedinput_height,unsignedoutput_width,unsignedoutput_height)const=0純虛函數(shù),具體實(shí)現(xiàn)見(jiàn)子類,判斷圖像是否支持尺寸變換,input_width、input_height為設(shè)定的寬度和高度,output_width、output_height變換后的寬度和高度。312021/8/17virtualvoidfillRGB(unsignedwidth,unsignedheight,unsignedchar*rgb_buffer,unsignedrgb_line_step=0)const=0用RGB數(shù)據(jù)填充用戶給定的rgb_buffer,返回圖像的寬度和高度為width、height,隔rgb_line_step行輸出到輸出緩存中。virtualEncodinggetEncoding()const=0返回原始編碼的方式。voidfillRaw(unsignedchar*rgb_buffer)constthrow()用原始數(shù)據(jù)填充用戶給定的rgb_buffer。virtualvoidfillGrayscale(unsignedwidth,unsignedheight,unsignedchar*gray_buffer,unsignedgray_line_step=0)const=0用灰度數(shù)據(jù)填充給定的gray_buffer,其他參數(shù)參考函數(shù)322021/8/17fillRGB。unsignedgetWidth()constthrow()unsignedgetHeight()constthrow()以上兩個(gè)函數(shù)分別獲取圖像寬度和高度。unsignedgetFrameID()constthrow()獲取幀的ID號(hào)。UnsignedlonggetTimeStamp()constthrow()獲取圖像的時(shí)間戳。constxn::ImageMetaData&getMetaData()constthrow()獲取圖像原始OpenNI格式數(shù)據(jù)。12.Classopenni_wrapper::ImageBayerGRBG13.Classopenni_wrapper::ImageRGB24332021/8/1714.Classopenni_wrapper::ImageYUV422以上3個(gè)類分別實(shí)現(xiàn)了對(duì)原始數(shù)據(jù)BayerGRBG、RGB24、YUV422到圖像轉(zhuǎn)化接口,詳細(xì)參考其父類關(guān)鍵函數(shù)說(shuō)明。15.Classpcl::OpenNIGrabber類OpenNIGrabber實(shí)現(xiàn)對(duì)OpenNI設(shè)備(例如PrimesensePSDK,MicrosoftKinect,AsusXTionPro/Live)數(shù)據(jù)的采集接口,詳細(xì)參考其父類Grabber關(guān)鍵函數(shù)說(shuō)明。16.classpcl::PCDReader17.classpcl::PLYReader以上兩個(gè)類分別是PCD、PLY文件格式讀入接口的實(shí)現(xiàn),詳細(xì)參考其父類pcl::FileReader。18.classpcl::PLYWriter19.Classpcl::PCDWriter以上兩個(gè)類分別是PCD、PLY文件格式寫出接口的實(shí)現(xiàn),342021/8/17詳細(xì)參考其父類pcl::FileWriter。20.Classpcl::PCLIOException類PCLIOException是I/O相關(guān)的異常處理接口實(shí)現(xiàn),詳細(xì)參考其父類PCLException。352021/8/174.2.2I/O模塊其他關(guān)鍵成員說(shuō)明PCL_EXPORTSintpcl::io::saveOBJFile(conststd::string&file_name,constpcl::TextureMesh&tex_mesh,unsignedprecision=5)該函數(shù)實(shí)現(xiàn)對(duì)TextureMesh保存到OBJ文件,file_name為OBJ文件名,tex_mesh為網(wǎng)格模型數(shù)據(jù),precision為保存時(shí)的精度(默認(rèn)為5)。PCL_EXPORTSintpcl::io::saveOBJFile(conststd::string&file_name,constpcl::PolygonMesh&mesh,unsignedprecision=5)功能同上,存儲(chǔ)對(duì)象為PolygonMesh。intpcl::io::loadPCDFile(conststd::string&file_name,sensor_msgs::PointCloud2&cloud)362021/8/17打開一版本V6.0的PCD文件,file_name為文件名,cloud存儲(chǔ)讀入的點(diǎn)云數(shù)據(jù)。template<typenamePointT>intpcl::io::loadPCDFile(conststd::string&file_name,pcl::PointCloud<PointT>&cloud)打開任何類型的PCD點(diǎn)云文件,file_name為文件名,cloud存儲(chǔ)讀入的點(diǎn)云數(shù)據(jù)。intpcl::io::savePCDFile(conststd::string&file_name,constsensor_msgs::PointCloud2&cloud,constEigen::Vector4f&origin=Eigen::Vector4f::Zero(),constEigen::Quaternionf&orientation=Eigen::Quaternionf::Identity(),constboolbinary_mode=false)保存點(diǎn)云到PCD文件,file_name文件名,cloud需要保存的點(diǎn)云數(shù)據(jù),origin為獲取點(diǎn)云的原點(diǎn),orientation為獲取點(diǎn)云的方向,binary_mode設(shè)置是否保存為二進(jìn)372021/8/17制格式,默認(rèn)為false。template<typenamePointT>intpcl::io::savePCDFile(conststd::string&file_name,constpcl::PointCloud<PointT>&cloud,boolbinary_mode=false)保存點(diǎn)云到PCD文件,file_name文件名,cloud需要保存的點(diǎn)云數(shù)據(jù),binary_mode設(shè)置是否保存為二進(jìn)制格式,默認(rèn)為false。template<typenamePointT>intpcl::io::savePCDFileASCII(conststd::string&file_name,constpcl::PointCloud<PointT>&cloud)以ASCII方式保存點(diǎn)云到PCD文件,file_name文件名,cloud需要保存的點(diǎn)云數(shù)據(jù)。template<typenamePointT>intpcl::io::savePCDFileBinary(conststd::string&file_name,const382021/8/17pcl::PointCloud<PointT>&cloud)以二進(jìn)制方式保存點(diǎn)云到PCD文件,file_name文件名,cloud需要保存的點(diǎn)云數(shù)據(jù)。voidpcl::throwPCLIOException(constcharfunction_name,constcharfile_name,unsignedline_number,constcharformat,…)異常處理函數(shù),function_name發(fā)生異常的函數(shù)名,file_name發(fā)生異常的文件名,發(fā)生異常的行號(hào)line_number,發(fā)生異常的拋出消息format。template<typenamePointT>intpcl::io::loadPLYFile(conststd::string&file_name,pcl::PointCloud<PointT>&cloud)打開ply文件,file_name文件名,cloud保存打開的點(diǎn)云數(shù)據(jù)。template<typenamePointT>392021/8/17intpcl::io::savePLYFile(conststd::string&file_name,constpcl::PointCloud<PointT>&cloud,boolbinary_mode=false)保存點(diǎn)云到PLY文件,file_name文件名,cloud需要保存的點(diǎn)云數(shù)據(jù),binary_mode設(shè)置是否保存為二進(jìn)制格式,默認(rèn)為false。template<typenamePointT>intpcl::io::savePLYFileASCII(conststd::string&file_name,constpcl::PointCloud<PointT>&cloud)template<typenamePointT>intpcl::io::savePLYFileBinary(conststd::string&file_name,constpcl::PointCloud<PointT>&cloud)以上兩個(gè)函數(shù)分別以為ASCII和二進(jìn)制方式保存點(diǎn)云到ply文件,file_name文件名,cloud需要保存的點(diǎn)云數(shù)據(jù)。PCL_EXPORTSintpcl::io::savePLYFile(conststd::string&402021/8/17file_name,constpcl::PolygonMesh&mesh,unsignedprecision=5)保存PolygonMesh對(duì)象到PLY文件,file_name為PLY文件名,mesh為需要保存的對(duì)象數(shù)據(jù),precision為保存精度(默認(rèn)為5)。CL_EXPORTSvoidpcl::io::saveRgbPNGFile(conststd::string&file_name,constunsignedcharrgb_image,intwidth,intheight)保存RGB數(shù)據(jù)為PNG文件,file_name為PNG文件名,rgb_image為RGB數(shù)據(jù),width、height為圖像數(shù)據(jù)的寬度和高度。PCL_EXPORTSvoidpcl::io::saveMonoPNGFile(conststd::string&file_name,constunsignedcharmono_image,intwidth,intheight)功能同上,只是保存的數(shù)據(jù)為灰度圖像格式。PCL_EXPORTSvoidpcl::io::saveShortPNGFile(conststd::string&file_name,constunsignedshortshort_image,intwidth,int412021/8/17height)功能同上,只是保存的數(shù)據(jù)為16位灰度圖像格式。template<typenameT>voidpcl::io::savePNGFile(conststd::string&file_name,constpcl::PointCloud<T>&cloud)保存點(diǎn)云中RGB域?yàn)閜ng文件,cloud為包含RGB域的點(diǎn)云對(duì)象,file_name為png文件名。PCL_EXPORTSintpcl::io::saveVTKFile(conststd::string&file_name,constpcl::PolygonMesh&triangles,unsignedprecision=5)保存PolygonMesh對(duì)象數(shù)據(jù)為VTK文件,file_name為VTK文件名,triangles為需要保存的數(shù)據(jù),precision為保存精度(默認(rèn)為5)。422021/8/174.3應(yīng)用實(shí)例解析432021/8/174.3.1PCD(點(diǎn)云數(shù)據(jù))文件格式本小節(jié)描述PCD(點(diǎn)云數(shù)據(jù))文件格式,及其他在點(diǎn)云庫(kù)(PCL)中應(yīng)用的方法。1.為什么用一種新的文件格式?PCD文件格式并非白費(fèi)力氣地做重復(fù)工作,現(xiàn)有的文件結(jié)構(gòu)因本身組成的原因不支持由PCL庫(kù)引進(jìn)n維點(diǎn)類型機(jī)制處理過(guò)程中的某些擴(kuò)展,而PCD文件格式能夠很好地補(bǔ)足這一點(diǎn)。PCD不是第一個(gè)支持3D點(diǎn)云數(shù)據(jù)的文件類型,尤其是計(jì)算機(jī)圖形學(xué)和計(jì)算幾何學(xué)領(lǐng)域,已經(jīng)創(chuàng)建了很多格式來(lái)描述任意多邊形和激光掃描儀獲取的點(diǎn)云。包括下面幾種格式:(1)PLY是一種多邊形文件格式,由Stanford大學(xué)的Turk等人設(shè)計(jì)開發(fā)。(2)STL是3DSystems公司創(chuàng)建的模型文件格式,主要應(yīng)用于CAD、CAM領(lǐng)域;442021/8/17(3)OBJ是從幾何學(xué)上定義的文件格式,首先由WavefrontTechnologies開發(fā);(4)X3D是符合ISO標(biāo)準(zhǔn)的基于XML的文件格式,表示3D計(jì)算機(jī)圖形數(shù)據(jù);(5)其他許多種格式。以上所有的文件格式都有缺點(diǎn),在下一節(jié)會(huì)講到。這是很自然的,因?yàn)樗鼈兪窃诓煌瑫r(shí)間為了不同的使用目的所創(chuàng)建的,那時(shí)今天的新的傳感器技術(shù)和算法都還沒(méi)有發(fā)明出來(lái)。2.PCD版本在點(diǎn)云庫(kù)(PCL)1.0版本發(fā)布之前,PCD文件格式有不同的修訂號(hào)。這些修訂號(hào)用PCV_Vx來(lái)編號(hào)(例如,PCD_V5、PCD_V6、PCD_V7等等),代表PCD文件的0.x版本號(hào)。然而PCL中PCD文件格式的正式發(fā)布是0.7452021/8/17版本(PCD_V7)。3.文件頭格式每一個(gè)PCD文件包含一個(gè)文件頭,它確定和聲明文件中存儲(chǔ)的點(diǎn)云數(shù)據(jù)的某種特性。PCD文件頭必須用ASCII碼來(lái)編碼。PCD文件中指定的每一個(gè)文件頭字段以及ascii點(diǎn)數(shù)據(jù)都用一個(gè)新行(\n)分開了,從0.7版本開始,PCD文件頭包含下面的字段:(1)VERSION——指定PCD文件版本。(2)FIELDS——指定一個(gè)點(diǎn)可以有的每一個(gè)維度和字段的名字。例如:FIELDSxyz#XYZdataFIELDSxyzrgb#XYZ+colorsFIELDSxyznormal_xnormal_ynormal_z#XYZ+surfacenormalsFIELDSj1j2j3462021/8/17…(3)SIZE——用字節(jié)數(shù)指定每一個(gè)維度的大小。例如:unsignedchar/char?has1byteunsignedshort/short?has2bytesunsignedint/int/float?Has4bytesdouble?has8bytes(4)TYPE——用一個(gè)字符指定每一個(gè)維度的類型。現(xiàn)在被接受的類型有:I——表示有符號(hào)類型int8(char)、int16(short)和int32(int);U——表示無(wú)符號(hào)類型uint8(unsignedchar)、uint16(unsignedshort)和uint32(unsignedint);F——表示浮點(diǎn)類型。(5)COUNT——指定每一個(gè)維度包含的元素?cái)?shù)目。例如,472021/8/17X這個(gè)數(shù)據(jù)通常有一個(gè)元素,但是像VFH這樣的特征描述子就有308個(gè)。實(shí)際上這是在給每一點(diǎn)引入n維直方圖描述符的方法,把它們當(dāng)做單個(gè)的連續(xù)存儲(chǔ)塊。默認(rèn)情況下,如果沒(méi)有COUNT,所有維度的數(shù)目被設(shè)置成1。(6)WIDTH——用點(diǎn)的數(shù)量表示點(diǎn)云數(shù)據(jù)集的寬度。數(shù)據(jù)是有序點(diǎn)云還是無(wú)序點(diǎn)云,WIDTH有兩層解釋:①它能確定無(wú)序數(shù)據(jù)集的點(diǎn)云中點(diǎn)的個(gè)數(shù)(和下面的POINTS一樣)。②它能確定有序點(diǎn)云數(shù)據(jù)集的數(shù)據(jù)(一行中點(diǎn)的數(shù)目)。注意:有序點(diǎn)云數(shù)據(jù)集,意味著點(diǎn)云是類似于圖像(或者矩陣)的結(jié)構(gòu),數(shù)據(jù)分為行和列。這種點(diǎn)云的實(shí)例包括立體攝像機(jī)和時(shí)間飛行攝像機(jī)生成的數(shù)據(jù)。有序數(shù)據(jù)集的優(yōu)勢(shì)在于,預(yù)先了解相鄰點(diǎn)(和像素點(diǎn))的482021/8/17關(guān)系,鄰域操作更加高效,這樣就加速了計(jì)算并降低了PCL中某些算法的成本。例如:WIDTH640#每行有640個(gè)點(diǎn)(7)HEIGHT——用點(diǎn)的數(shù)目表示點(diǎn)云數(shù)據(jù)集的高度。類似于WIDTH,HEIGHT也有兩層解釋:①它表示有序點(diǎn)云數(shù)據(jù)集的高度(行的總數(shù));②對(duì)于無(wú)序數(shù)據(jù)集它被設(shè)置成1(被用來(lái)檢查一個(gè)數(shù)據(jù)集是有序還是無(wú)序)。有序點(diǎn)云例子:WIDTH640#像圖像一樣的有序結(jié)構(gòu),有640行和480列HEIGHT480#這樣該數(shù)據(jù)集中共有640×480=307200個(gè)點(diǎn)無(wú)序點(diǎn)云例子:492021/8/17WIDTH307200HEIGHT1#有307200個(gè)點(diǎn)的無(wú)序點(diǎn)云數(shù)據(jù)集(8)VIEWPOINT——指定數(shù)據(jù)集中點(diǎn)云的獲取視點(diǎn)。VIEWPOINT有可能在不同坐標(biāo)系之間轉(zhuǎn)換的時(shí)候應(yīng)用,在輔助獲取其他特征時(shí)也比較有用,例如曲面法線,在判斷方向一致性時(shí),需要知道視點(diǎn)的方位,視點(diǎn)信息被指定為平移(txtytz)+四元數(shù)(qwqxqyqz)。默認(rèn)值是:VIEWPOINT0001000(9)POITNS——指定點(diǎn)云中點(diǎn)的總數(shù)。從0.7版本開始該字段就有點(diǎn)多余了,因此有可能在將來(lái)的版本中將它移除。例子:POINTS307200#點(diǎn)云中點(diǎn)的總數(shù)為307200502021/8/17(10)DATA——指定存儲(chǔ)點(diǎn)云數(shù)據(jù)的數(shù)據(jù)類型。從0.7版本開始支持兩種數(shù)據(jù)類型:ASCII碼和二進(jìn)制。查看下一節(jié)可以獲得更多細(xì)節(jié)。注意:文件頭最后一行(DATA)的下一個(gè)字節(jié)就被看成是點(diǎn)云的數(shù)據(jù)部分了,它會(huì)被解釋為點(diǎn)云數(shù)據(jù)。警告:PCD文件的文件頭部分必須以上面的順序精確指定,也就是如下順序:VERSION、FIELDS、SIZE、TYPE、COUNT、WIDTH、HEIGHT、VIEWPOINT、POINTS、DATA之間用換行隔開。4.數(shù)據(jù)存儲(chǔ)類型在0.7版本中,PCD文件格式用兩種模式存儲(chǔ)數(shù)據(jù):如果以ASCII形式,每一點(diǎn)占據(jù)一個(gè)新行:p_1p_2512021/8/17…p_n注意:從PCL1.0.1版本開始,用字符串“nan”表示NaN,此字符表示該點(diǎn)的值不存在或非法等。如果以二進(jìn)制形式,這里數(shù)據(jù)是數(shù)組(向量)pcl::PointCloud.points的一份完整拷貝,在Linux系統(tǒng)上,我們用mmap/munmap操作來(lái)盡可能快地讀寫數(shù)據(jù),存儲(chǔ)點(diǎn)云數(shù)據(jù)可以用簡(jiǎn)單的ASCII形式,每點(diǎn)占據(jù)一行,用空格鍵或Tab鍵分開,沒(méi)有其他任何字符。也可以用二進(jìn)制存儲(chǔ)格式,它既簡(jiǎn)單又快速,當(dāng)然這依賴于用戶應(yīng)用。ASCII格式允許用戶打開點(diǎn)云文件,使用例如gunplot這樣的標(biāo)準(zhǔn)軟件工具更改點(diǎn)云文件數(shù)據(jù),或者用sed、awk等工具來(lái)對(duì)它們進(jìn)行操作。5.相對(duì)其他文件格式的優(yōu)勢(shì)提高適用性和速度。522021/8/17(1)存儲(chǔ)和處理有序點(diǎn)云數(shù)據(jù)集的能力(2)二進(jìn)制mmap/munmap數(shù)據(jù)類型是把數(shù)據(jù)下載和存儲(chǔ)到磁盤上最快的方法;(3)存儲(chǔ)不同的數(shù)據(jù)類型(4)特征描述子的n維直方圖另一個(gè)優(yōu)勢(shì)是通過(guò)控制文件格式,我們能夠使其最大程度上適應(yīng)PCL,這樣能獲得PCL應(yīng)用程序的最好性能,而不用把一種不同的文件格式改變成PCL的內(nèi)部格式,這樣的話通過(guò)轉(zhuǎn)換函數(shù)會(huì)引起額外的延時(shí)。注意:盡管PCD(點(diǎn)云數(shù)據(jù))是PCL中的內(nèi)部文件格式,pcl_I/O庫(kù)也提供在前面提到的所有其他文件格式中保存和加載數(shù)據(jù)。6.例子532021/8/17下面是PCD文件的一個(gè)片段。把它留給讀者以解析這些數(shù)據(jù),看看它的組成。#.PCDv.7–PointCloudDatafileformatVERSION.7FIELDSxyzrgbSIZE4444TYPEFFFFCOUNT1111WIDTH213HEIGHT1VIEWPORT0001000POINTS213DATAascii0.937730.3376304.2108e+060.908050.3564104.2108e+06542021/8/174.3.2從PCD文件中讀取點(diǎn)云數(shù)據(jù)在本小節(jié)我們學(xué)習(xí)如何從PCD文件中讀取點(diǎn)云數(shù)據(jù)。在本書提供光盤的第4章例1文件夾中,打開名為pcd_read.cpp的代碼文件。同目錄下可找到測(cè)試點(diǎn)云文件test_pcd.pcd。1.代碼解釋說(shuō)明現(xiàn)在解析上面打開的代碼。#include<iostream>//標(biāo)準(zhǔn)C++庫(kù)中的輸入輸出類相關(guān)頭文件#include<pcl/io/pcd_io.h>//pcd讀寫類相關(guān)的頭文件#include<pcl/point_types.h>//PCL中支持的點(diǎn)類型頭文件與本程序相關(guān)的頭文件聲明。pcl::PointCloud<pcl::PointXYZ>::Ptrcloud(newpcl::PointCloud<pcl::PointXYZ>);552021/8/17創(chuàng)建一個(gè)PointCloud<PointXYZ>boost共享指針并進(jìn)行實(shí)例化。if(pcl::io::loadPCDFile<pcl::PointXYZ>(“test_pcd.pcd”,*cloud)==-1)//打開點(diǎn)云文件{PCL_ERROR(“Couldn’treadfiletest_pcd.pcd\n”);return(-1);}從磁盤上加載PointCloud數(shù)據(jù)(假設(shè)test_pcd.pcd文件已經(jīng)被創(chuàng)建了)到二進(jìn)制存儲(chǔ)塊中?;蛘呖梢宰x取PointCloud2存儲(chǔ)塊(僅僅在PCL1.x中可用)。由于點(diǎn)云的動(dòng)態(tài)性質(zhì),我們更愿意以二進(jìn)制塊來(lái)讀取,然后轉(zhuǎn)換成要使用的表示方式。sensor_msgs::PointCloud2cloud_blob;//PointCloud2適合版本低的點(diǎn)云文件562021/8/17pcl::io::loadPCDFile(“test_pcd.pcd”,cloud_blob);pcl::fromROSMsg(cloud_blob,*cloud);//*sensor_msgs/PointCloud2轉(zhuǎn)換為pcl::PointCloud<T>把二進(jìn)制塊讀取并轉(zhuǎn)換到模板化的PointCloud格式里,這里用pcl::PointXYZ作為點(diǎn)類型。for(size_ti=0;i<cloud->points.size();++i)std::cout<<“”<<cloud->points[i].x<<“”<<cloud->points[i].y<<““<<cloud->points[i].z<<std::endl;最后在標(biāo)準(zhǔn)輸出上打印出從文件中加載的數(shù)據(jù)。2.編譯并運(yùn)行該程序利用光盤提供的CMakeLists.txt文件,在CMake中建立工程文件,并生成相應(yīng)的可執(zhí)行文件,生成可執(zhí)行程序之后就可以運(yùn)行了。在CMD中輸入以下命令:…>pcd_read.exe572021/8/17運(yùn)行之后,可看見(jiàn)圖4-8所示的輸出結(jié)果,在本例中提供的是點(diǎn)云文件版本0.7,所以在代碼中沒(méi)有涉及PointCloud2,如果用戶需要讀取版本較低的PCD文件,需要替換點(diǎn)云讀取代碼為上面描述的PointCloud2讀取方式。注意,如果test_pcd.pcd文件不存在(沒(méi)有創(chuàng)建或者被刪除了),將會(huì)提示如下錯(cuò)誤信息:Couldn’treadfiletest_pcd.pcd582021/8/174.3.3向PCD文件寫入點(diǎn)云數(shù)據(jù)本小節(jié)我們學(xué)習(xí)如何向PCD文件寫入點(diǎn)云數(shù)據(jù)。首先,在本書提供光盤的第4章例2文件夾中,打開名為pcd_write.cpp的代碼文件。1.代碼解釋說(shuō)明現(xiàn)在,我們解析上面代碼:#include<pcl/io/pcd_io.h>#include<pcl/point_types.h>pcl/io/pcd_io.h頭文件中包含了PCD輸入輸出操作的聲明,pcl/point_types.h頭文件則包含一些PointT類型結(jié)構(gòu)體的聲明(本例中是pcl::PointXYZ)。pcl::PointCloud<pcl::PointXYZ>cloud;592021/8/17描述我們將要實(shí)例化的模板類PointCloud,每一個(gè)點(diǎn)的類型都被設(shè)置成pcl::PointXYZ,作為模板類實(shí)例化的參數(shù),其他類型請(qǐng)參考第3章點(diǎn)類型介紹一節(jié),pcl::PointXYZ具體定義如下下面://點(diǎn)PointXYZ類型對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)StructPointXYZ{floatx;floaty;floatz;};下面這幾行://創(chuàng)建點(diǎn)云cloud.width=5;cloud.height=1;602021/8/17cloud.is_dense=false;cloud.points.resize(cloud.width*cloud.height);for(size_ti=0;i<cloud.points.size();++i){cloud.points[i].x=1024*rand()/(RAND_MAX+1.0f);cloud.points[i].y=1024*rand()/(RAND_MAX+1.0f);cloud.points[i].z=1024*rand()/(RAND_MAX+1.0f);}用隨機(jī)點(diǎn)的值填充PointCloud點(diǎn)云對(duì)象,并設(shè)置適當(dāng)?shù)膮?shù)(width、height、is_dense)。然后:pcl::io::savePCDFileASCII(“test_pcd.pcd”,cloud);把PointCloud對(duì)象數(shù)據(jù)存儲(chǔ)在test_pcd.pcd文件中。最后:std::cerr<<“Saved“<<cloud.points.size()<<“datapointstotest_pcd.pcd.”<<std::endl;for(size_ti=0;i<cloud.points.size();++i)612021/8/17std::cerr<<““<<cloud.points[i].x<<“”<<cloud.points[i].y<<““<<cloud.points[i].z<<std::endl;上面幾行代碼用來(lái)打印輸出存儲(chǔ)的點(diǎn)云數(shù)據(jù)。2.編譯并運(yùn)行該程序利用光盤提供的CMakeLists.txt文件,在CMake中建立工程文件,并生成相應(yīng)的可執(zhí)行文件,生成可執(zhí)行文件之后就可以運(yùn)行了,在CMD中使用以下命令:…>pcd_write.exe將在CMD界面看到類似圖4-9所示的內(nèi)容。622021/8/17Linux下用戶可以方便的用下面的命令檢查test_pcd.pcd文件的內(nèi)容,在Window上的用戶直接用一般的word等就可以對(duì)PCD文件進(jìn)行打開(只限于0.7版本的,低版本的打開顯示不完整)。632021/8/174.3.4連接兩個(gè)點(diǎn)云中的字段或數(shù)據(jù)形成新點(diǎn)云本小節(jié)我們學(xué)習(xí)如何連接兩個(gè)不同點(diǎn)云為一個(gè)點(diǎn)云,進(jìn)行連接操作前要確保兩個(gè)數(shù)據(jù)集中字段的類型相同和維度相等。同時(shí)也學(xué)習(xí)如何連接兩個(gè)不同點(diǎn)云的字段(例如,顏色、法線),這種操作的強(qiáng)制約束條件是兩個(gè)數(shù)據(jù)集中點(diǎn)的數(shù)目必須一樣,例如,點(diǎn)云A是N個(gè)點(diǎn)的XYZ點(diǎn),點(diǎn)云B是N個(gè)點(diǎn)的RGB點(diǎn),則連接兩個(gè)字段形成點(diǎn)云C是N個(gè)點(diǎn)xyzrgb類型。在本書提供光盤的第4章例3文件夾中,打開名為concatenate_clouds.cpp的代碼文件。1.代碼解釋說(shuō)明現(xiàn)在解析上面的打開的源代碼,在下面幾行中:pcl::PointCloud<pcl::PointXYZ>cloud_a,cloud_b,cloud_c;642021/8/17pcl::PointCloud<pcl::Normal>n_cloud_b;//存儲(chǔ)進(jìn)行連接時(shí)需要的normal點(diǎn)云pcl::PointCloud<pcl::PointNormal>p_n_cloud_c;//存儲(chǔ)連接X(jué)YZ與normal后的點(diǎn)云//創(chuàng)建點(diǎn)云數(shù)據(jù)cloud_a.width=3;//設(shè)置cloud_a點(diǎn)個(gè)數(shù)為3,cloud_a.height=cloud_b.height=n_cloud_b.height=1;//設(shè)置都為無(wú)序點(diǎn)云cloud_a.points.resize(cloud_a.width*cloud_a.height);if(strcmp(argv[1],“-p”)==0)//判斷進(jìn)行是否為連接a+b=c{cloud_b.width=2;cloud_b.points.resize(cloud_b.width*cloud_b.height);}else{n_cloud_b.width=3;//如果是連接X(jué)YZ與normal則生成3個(gè)法線n_cloud_b.points.resize(n_cloud_b.width*n_cloud_b.height);}652021/8/17//以下循環(huán)生成無(wú)序點(diǎn)云,填充上面定義的兩種類型點(diǎn)云對(duì)象for(size_ti=0;i<cloud_a.points.size();++i){//cloud_a始終產(chǎn)生3個(gè)點(diǎn)cloud_a.points[i].x=1024*rand()/(RAND_MAX+1.0f);cloud_a.points[i].y=1024*rand()/(RAND_MAX+1.0f);cloud_a.points[i].z=1024*rand()/(RAND_MAX+1.0f);}if(strcmp(argv[1],“-p”)==0)for(size_ti=0;i<cloud_b.points.size();++i){//如果連接a+b=c則cloud_b用2個(gè)點(diǎn)作為xyz數(shù)據(jù)cloud_b.points[i].x=1024*rand()/(RAND_MAX+1.0f);cloud_b.points[i].y=1024*rand()/(RAND_MAX+1.0f);cloud_b.points[i].z=1024*rand()/(RAND_MAX+1.0f);}662021/8/17elsefor(size_ti=0;i<n_cloud_b.points.size();++i){//如果連接xyz+normal=xyznormal則n_cloud_b用3個(gè)點(diǎn)作為normal數(shù)據(jù)n_cloud_b.points[i].normal[0]=1024*rand()/(RAND_MAX+1.0f);n_cloud_b.points[i].normal[1]=1024*rand()/(RAND_MAX+1.0f);n_cloud_b.points[i].normal[2]=1024*rand()/(RAND_MAX+1.0f);}我們定義了連接點(diǎn)云會(huì)用到的5個(gè)點(diǎn)云對(duì)象:3個(gè)輸入(cloud_a、cloud_b和n_cloud_b),兩個(gè)輸出(cloud_c和p_n_cloud_c)。然后我們?yōu)閮蓚€(gè)輸入點(diǎn)云(cloud_a和cloud_b或者cloud_a和n_cloud_b)填充數(shù)據(jù)。然后下面幾行:672021/8/17std::cerr<<“CloudA:”<<std::endl;for(size_ti=0;i<cloud_a.points.size();++i)std::cerr<<““<<cloud_a.points[i].x<<““<<cloud_a.points[i].y<<““<<cloud_a.points[i].z<<std::endl:std::cerr<<“CloudB:”<<std::endl;if(strcmp(argv[1],“-p”)==0)for(size_ti=0;i<cloud_b.points.size();++i)std::cerr<<““<<cloud_b.points[i].x<<““<<cloud_b.points[i].y<<““<<cloud_b.points[i].z<<std::endl;elsefor(size_ti=0;i<n_cloud_b.points.size();++i)std::cerr<<““<<n_cloud_b.points[i].normal[0]<<““<<n_cloud_b.points[i].normal[1]<<““<<n_cloud_b.points[i].normal[2]<<std::endl;把cloud_a和cloud_b或n_cloud_b(取決于命令行參數(shù))的數(shù)據(jù)打印在標(biāo)準(zhǔn)輸出上。如果我們需要連接點(diǎn)云,那么682021/8/17下面的代碼:cloud_c=cloud_a;cloud_c+=cloud_b;把cloud_a和cloud_b連接在一起創(chuàng)建了cloud_c。另外如果要連接字段,那么下面的代碼:pcl::concatenateFields(cloud_a,n_cloud_b,p_n_cloud_c);通過(guò)把cloud_a和n_cloud_b字段連接在一起創(chuàng)建了p_n_cloud_c。最后:std::cerr<<“CloudC:”<<std::endl;for(size_ti=0;i<cloud_c.points.size();++i)std::cerr<<""<<cloud_c.points[i].x<<""<<cloud_c.points[i].y<<""<<cloud_c.points[i].z<<""<<std::endl;或者pcl::concatenateFields(cloud_a,n_cloud_b,p_n_cloud_c);692021/8/17std::cerr<<"CloudC:"<<std::endl;for(size_ti=0;i<p_n_cloud_c.points.size();++i)std::cerr<<""<<p_n_cloud_c.points[i].x<<""<<p_n_cloud_c.points[i].y<<""<<p_n_cloud_c.points[i].z<<""<<p_n_cloud_c.points[i].normal[0]<<""<<p_n_cloud_c.points[i].normal[1]<<""<<p_n_cloud_c.points[i].normal[2]<<std::endl;上面兩段代碼中的一段用來(lái)把cloud_c或者p_n_cloud_c的內(nèi)容顯示在屏幕上,這取決于我們連接是點(diǎn)云還是字段。2.編譯并運(yùn)行該程序利用光盤提供的CMakeLists.txt文件,在CMake中建立工程文件,并生成相應(yīng)的可執(zhí)行文件,生成可執(zhí)行程序之后就可以運(yùn)行了。在CMD中輸入以下命令來(lái)連接點(diǎn),702021/8/17…>concatenate_clouds.exe–p或者鍵入以下命令來(lái)連接字段?!?gt;concatenate_clouds.exe–f運(yùn)行程序結(jié)果如圖4-10所示,先是點(diǎn)云字段間連接,后面是點(diǎn)云連接。712021/8/174.3.5PCL中的OpenNI點(diǎn)云獲取框架從PCL1.0開始,PCL提供了一個(gè)通用采集接口,這樣可以方便地連接到不同的設(shè)備及其驅(qū)動(dòng)、文件格式和其他數(shù)據(jù)源。PCL集成的第一個(gè)數(shù)據(jù)獲取驅(qū)動(dòng)是新的OpenNIGrabber,它使得從OpenNI

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論