:數(shù)據(jù)集選型與evo工具詳解)
1. 項目概述這套組合到底解決什么問題做視覺SLAM的人無論是剛?cè)腴T的研究生還是在公司調(diào)算法的工程師大概率都會遇到同一個問題算法寫出來了跑起來了但怎么證明它“行”你自己在數(shù)據(jù)集上跑一遍看著畫面里特征點穩(wěn)定跟蹤覺得效果不錯可老板、審稿人或者客戶一句“精度多少”你拿不出數(shù)字就尷尬了。ORB-SLAM作為基于特征點法的代表性開源系統(tǒng)大家都很熟悉但真正要把它的性能量化、可復(fù)現(xiàn)、可比較就繞不開兩樣?xùn)|西公開數(shù)據(jù)集和評估工具。這個項目就是圍繞“ORB-SLAM 數(shù)據(jù)集 evo評估”這一整套評測鏈路展開的。先說數(shù)據(jù)集。做SLAM評測不能拿自己錄的數(shù)據(jù)自說自話因為場景、傳感器標定、運動軌跡都不透明別人也沒法復(fù)現(xiàn)。主流的公開數(shù)據(jù)集比如TUM RGB-D、KITTI、EuRoC MAV都提供了傳感器數(shù)據(jù)圖像、IMU等和高精度的真值軌跡Ground Truth你在同一份數(shù)據(jù)上跑結(jié)果才有橫向?qū)Ρ鹊恼f服力。再說評估工具。evo是當(dāng)前用得最順手的軌跡評估工具之一它能把你SLAM輸出的軌跡和數(shù)據(jù)集提供的真值軌跡加載進來做時間戳對齊、軌跡對齊然后算出ATE絕對軌跡誤差、RPE相對位姿誤差等核心指標還能直接畫圖省去自己寫腳本的麻煩。這篇內(nèi)容適合誰我認為有三類人最需要一是剛接觸SLAM、想把ORB-SLAM在公開數(shù)據(jù)集上跑通并量化結(jié)果的新手二是準備發(fā)論文、需要給方法做對比實驗的研究生三是在實際項目中想快速評估自己改動效果的工程師。下面我會從數(shù)據(jù)集選型、evo工具原理、完整實操流程到常見坑位把這條評測鏈路一次性講清楚。整套流程我實測過多次照著走基本不會有卡殼的地方。2. 常用SLAM公開數(shù)據(jù)集選型與特點2.1 TUM RGB-D室內(nèi)視覺SLAM的入門標配TUM RGB-D數(shù)據(jù)集是慕尼黑工業(yè)大學(xué)TU Munich發(fā)布的全稱是TUM RGB-D Benchmark。它用微軟Kinect一代傳感器在室內(nèi)場景下錄制了幾十個序列覆蓋桌面、辦公室、客廳等不同環(huán)境。這個數(shù)據(jù)集最核心的價值在于提供了非常豐富的傳感器軌跡和真值除了RGB圖像和深度圖像還有用運動捕捉系統(tǒng)Vicon或高精度運動追蹤系統(tǒng)測得的相機軌跡頻率達到100Hz以上精度在毫米級別。為什么說它是入門標配因為TUM數(shù)據(jù)集的序列劃分非常細每個序列都有明確的場景特征和運動特性例如fr1/desk是桌面場景相機在桌面上方緩慢移動適合驗證基本跟蹤穩(wěn)定性fr2/xyz是純平移運動適合驗證尺度一致性fr3/structure_texture_far則是有大量無紋理墻面的場景專門用來考驗特征點法在弱紋理環(huán)境下的表現(xiàn)。對于ORB-SLAM這種基于ORB特征點的系統(tǒng)TUM數(shù)據(jù)能非常直觀地暴露算法在不同場景下的弱點。TUM還支持RGB-D和單目兩種評測模式你既可以輸入RGB-D序列驗證稠密或半稠密建圖也可以只用RGB圖像走單目SLAM流程。它提供的groundtruth.txt是標準TUM格式每行內(nèi)容包括時間戳、平移量以及四元數(shù)表示的旋轉(zhuǎn)這個格式同時也是evo工具默認支持的格式之一所以拿來就能直接評估不需要額外轉(zhuǎn)換。2.2 KITTI自動駕駛場景的里程計基準KITTI數(shù)據(jù)集是德國卡爾斯魯厄理工學(xué)院KIT和豐田美國技術(shù)研究院聯(lián)合發(fā)布的自動駕駛場景數(shù)據(jù)集涵蓋雙目圖像、激光雷達點云、GPS/IMU數(shù)據(jù)以及高精度真值。它的視覺里程計基準KITTI Odometry提供了從城市道路到鄉(xiāng)村公路的22個序列00到21前11個序列公開了真值軌跡用于評估單目、雙目以及激光SLAM/里程計系統(tǒng)的定位精度。KITTI和TUM最大的區(qū)別在于場景尺度和載體特性。TUM是室內(nèi)手持相機運動范圍小、視場受限KITTI是車載攝像頭場景是開闊的室外道路光照變化大、動態(tài)物體多車輛、行人運動方式以車輛前進和轉(zhuǎn)向為主。這些特性決定了KITTI更適合評估SLAM系統(tǒng)在真實自動駕駛場景下的長距離定位能力尤其是累積漂移的控制情況。ORB-SLAM在KITTI上跑tracking線程對車輛快速轉(zhuǎn)向和遮擋的魯棒性會得到充分考驗。KITTI數(shù)據(jù)格式上需要注意它沒有直接提供單目的TUM格式軌跡文件而是以位姿矩陣序列的形式存儲。每幀的位姿是一個3x4的變換矩陣展平后占一行12個數(shù)字6自由度位姿。這個格式evo同樣原生支持KITTI格式但如果你用的是KITTI的單目序列因為沒有尺度信息輸出軌跡要和真值對齊時需要做Sim(3)變換稍后我會在evo原理部分詳細說明。2.3 EuRoC MAV無人機視覺慣性里程計的經(jīng)典測試EuRoC MAV數(shù)據(jù)集是蘇黎世聯(lián)邦理工學(xué)院ETH發(fā)布的微型無人機MAV數(shù)據(jù)集用雙目相機加IMU錄制包含機器大廳Machine Hall和普通房間Vicon Room兩種室內(nèi)環(huán)境共11個序列。它的獨到之處在于把場景難度按“光照條件、紋理豐富度、運動速度、IMU激勵程度”分成了Easy、Medium、Difficult三個等級評測時可以直接用難度梯度來衡量算法魯棒性。EuRoC提供了100Hz的雙目圖像全局快門、200Hz的IMU數(shù)據(jù)以及Vicon運動捕捉系統(tǒng)得到的6自由度真值。如果你在調(diào)ORB-SLAM3這種帶IMU融合的版本EuRoC幾乎是必測的數(shù)據(jù)集。因為它的運動包含快速旋轉(zhuǎn)、急加速、劇烈振動可以充分驗證視覺慣性融合是否能有效抑制純視覺在快速運動下容易丟失的問題。EuRoC的真值文件格式是timestamp、position的三軸坐標加四元數(shù)與TUM格式略有差別數(shù)據(jù)順序是qw qx qy qzevo同樣支持直接讀取。需要注意EuRoC數(shù)據(jù)集官方還提供了帶時間戳的軌跡真值并區(qū)分了全局坐標系和機體坐標系用的時候要確認你評估時載入的是哪一套坐標避免因為坐標系選錯而得出錯誤結(jié)論。2.4 其他常用數(shù)據(jù)集一覽除了上述三大主流數(shù)據(jù)集根據(jù)應(yīng)用場景不同你還會遇到一些特定方向的數(shù)據(jù)集我在這里簡單列一下方便大家根據(jù)需求選型數(shù)據(jù)集場景傳感器典型用途ICL-NUIM室內(nèi)合成場景RGB-D無真實傳感器噪聲方便做算法消融實驗ETH3D室內(nèi)外混合雙目、多視角高分辨率圖像適合魯棒視覺定位和重建TUM VI室內(nèi)手持/無人機雙目IMU視覺慣性里程計評估時間戳標定嚴格NCLT校園室外長時雙目、激光、IMU長時SLAM、光照季節(jié)變化魯棒性O(shè)penLORIS室內(nèi)生活場景RGB-D、IMU生活機器人長期自定位主打動態(tài)環(huán)境選數(shù)據(jù)集沒有絕對的對錯核心原則是你的算法目標場景和數(shù)據(jù)集采集場景要盡量匹配。比如你做室內(nèi)服務(wù)機器人硬要在KITTI上刷精度意義就不大反過來你做自動駕駛定位非要在TUM這種桌面數(shù)據(jù)上評估也難以說明在真實道路場景的適用性。3. evo評估工具安裝、核心命令與原理3.1 evo能做什么為什么大家都用evo是一個用Python寫的SLAM軌跡評估工具作者是Michael Grupp目前在GitHub上開源維護社區(qū)非?;钴S。它支持多種輸入格式TUM、KITTI、EuRoC、ROS bag等能夠計算兩個軌跡之間的絕對誤差A(yù)TE和相對誤差RPE并且自帶可視化功能可以直接輸出誤差曲線和軌跡對比圖。在evo出現(xiàn)之前大家評估SLAM基本是拿到數(shù)據(jù)集官方提供的Matlab評估腳本或者自己寫Python代碼處理軌跡對齊和誤差計算。自己寫的問題在于軌跡對齊算法容易出錯、時間戳對齊要處理插值、誤差統(tǒng)計口徑不統(tǒng)一最后跑出來的結(jié)果跟別人對不上。evo把這些問題都封裝好了命令行一條指令就能得到規(guī)范化的指標這也讓它成了當(dāng)前SLAM領(lǐng)域事實上的標準評估工具。另一個關(guān)鍵點是evo“可復(fù)現(xiàn)”。它會把評估過程中的關(guān)鍵參數(shù)如對齊方式、誤差類型、時間戳偏移量全部打印出來你寫論文時直接引用即可評審和讀者可以照著你的參數(shù)重新跑一遍保證結(jié)果一致性。這一點在學(xué)術(shù)交流中非常加分。3.2 安裝與環(huán)境配置evo的安裝很簡單因為它是純Python項目直接用pip安裝即可。不過你在裝之前最好先確認Python環(huán)境。官方推薦Python3.8以上版本我是直接用Anaconda建了一個單獨的環(huán)境避免跟系統(tǒng)Python打架。conda create -n evo_env python3.8 conda activate evo_env pip install evo --upgrade --no-binary evo這里的--no-binary evo參數(shù)建議保留因為evo的二進制wheel包有時候會缺依賴從源碼編譯安裝更穩(wěn)妥。安裝完成后驗證一下evo --version正常情況下會輸出evo的版本號同時還會列出evo_ape、evo_rpe、evo_traj等子命令。如果提示找不到命令檢查一下Anaconda環(huán)境的bin目錄是否在PATH里或者直接運行python -m evo來調(diào)用。安裝過程中最容易踩的坑是numpy版本沖突。evo底層依賴numpy和matplotlib如果你環(huán)境里numpy版本過新比如1.24以上的某些版本evo在繪制誤差圖時可能報錯此時可以指定降級安裝pip install numpy1.23.5這個版本組合我實測下來穩(wěn)定不報錯。3.3 核心命令evo_ape、evo_rpe、evo_trajevo最常用的三個命令是evo_ape、evo_rpe和evo_traj我逐個說明它們的用途。evo_ape是計算絕對軌跡誤差A(yù)bsolute Trajectory Error的命令。ATE衡量的是整條軌跡的全局一致性即估計軌跡和真值軌跡在整體上相差多少。對于回環(huán)檢測是否有效、長時間運行是否漂移這類問題ATE是最直接的指標。基本用法如下evo_ape tum groundtruth.txt estimated.txt -a這里的-a參數(shù)讓evo在計算誤差前自動進行軌跡對齊。對于單目SLAM因為沒有尺度信息還需要加上-s進行尺度校正此時對應(yīng)的是Sim(3)變換對齊命令為evo_ape tum groundtruth.txt estimated.txt -a -sevo_rpe則是計算相對位姿誤差Relative Pose Error它衡量的是固定時間間隔比如每1米或者每1秒內(nèi)位姿增量的誤差。相對誤差在評估里程計局部精度時更有意義因為它剔除了全局累計漂移的影響?;居梅╡vo_rpe tum groundtruth.txt estimated.txt -r trans_part -d 1其中-r指定計算誤差的部位常用選項包括trans_part平移部分、rot_part旋轉(zhuǎn)部分、full全部-d指定相對誤差的時間間隔單位是秒。如果你需要評估平移、旋轉(zhuǎn)分別的表現(xiàn)可以組合這些參數(shù)分別出指標。evo_traj用于加載一個或多個軌跡文件進行可視化或者將不同格式的數(shù)據(jù)轉(zhuǎn)換成你需要的格式。例如查看軌跡evo_traj tum estimated.txt -p把KITTI格式的位姿文件轉(zhuǎn)成TUM格式evo_traj kitti kitti_poses.txt --save_as_tum-p參數(shù)會彈出matplotlib窗口把軌跡畫在平面上配合--ref參數(shù)還可以同時畫出真值軌跡做對比據(jù)說這個功能在調(diào)試時很實用一眼就能看出軌跡整體是否偏離。每次評估完evo會輸出一組統(tǒng)計量通常包括RMSE均方根誤差、MAE平均絕對誤差、Median中位數(shù)、Std標準差和Max最大誤差。不同論文里常用RMSE作為最終匯報指標但實際寫報告時建議把中位數(shù)和最大誤差也一并給出因為RMSE對異常值比較敏感最大誤差能反映算法最壞情況下的表現(xiàn)。3.4 軌跡對齊與誤差計算原理很多人第一次用evo時會困惑為什么我的軌跡明明和真值畫出來差得很遠加了-a之后指標立刻變得很好原因在于SLAM系統(tǒng)輸出的軌跡坐標系和數(shù)據(jù)集真值軌跡坐標系通常不是同一個兩者之間存在一個剛體變換旋轉(zhuǎn)平移單目SLAM還額外存在尺度因子。如果不先對齊坐標系就直接算誤差數(shù)值會大得離譜也沒有實際意義。evo默認用的是Umeyama算法它可以在已知兩個軌跡對應(yīng)點的情況下求解出最優(yōu)的相似變換Sim(3)使估計軌跡在最小二乘意義下最接近真值軌跡。這個變換包含旋轉(zhuǎn)、平移和縮放三個分量。雙目或RGB-D SLAM的輸出一般不存在尺度問題用剛體變換SE(3)對齊就夠了單目SLAM則必須用Sim(3)對齊把尺度因子也求解出來。這也是你為什么會在很多論文里看到“monocular results are aligned with 7-DoF similarity transformation”的原因。對齊完成之后ATE的計算過程是把兩軌跡對應(yīng)位姿的平移向量之差取范數(shù)然后統(tǒng)計RMSE等誤差指標。RPE則是對相鄰位姿增量做類似計算得到的是局部誤差的時間序列。理解了這個原理你就能明白為什么同一個算法在不同數(shù)據(jù)集上的指標必須注明對齊方式否則數(shù)值之間根本不具備可比性。4. 實操ORB-SLAM2跑通TUM數(shù)據(jù)并用evo評估4.1 下載數(shù)據(jù)集與ORB-SLAM2編譯準備這里我以O(shè)RB-SLAM2在TUM RGB-D數(shù)據(jù)集上的評測為例走一遍完整流程。這套流程是室內(nèi)RGB-D SLAM最經(jīng)典的驗證路徑跑通之后再遷移到KITTI、EuRoC就順手很多。先下載TUM數(shù)據(jù)集的fr1/desk序列。在TUM官網(wǎng)找到下載鏈接文件是一個壓縮包包含RGB圖像、深度圖像和groundtruth.txt。解壓后建議把目錄名改簡單一點比如fr1_desk方便后續(xù)命令行操作。同時還需要TUM官方提供的一個RGB-D數(shù)據(jù)對齊腳本associate.py因為RGB圖像、深度圖像和真值軌跡的時間戳不是一一對應(yīng)的需要根據(jù)時間差做匹配。ORB-SLAM2的編譯依賴項有Pangolin、OpenCV、Eigen、DBoW2和g2o。Pangolin用于可視化窗口OpenCV做圖像處理Eigen做矩陣運算DBoW2和g2o是ORB-SLAM內(nèi)部集成的詞袋和優(yōu)化庫。如果你在Ubuntu 18.04或20.04上操作官方README里的命令基本能一路順暢編譯過。編譯時容易出問題的是OpenCV版本ORB-SLAM2的代碼比較早對OpenCV3兼容最好如果你裝的是OpenCV4.2以上版本大概率會遇到一些函數(shù)接口變動導(dǎo)致的編譯錯誤需要手動改幾處源代碼比如ORBextractor.cc里的CV_LOAD_IMAGE_GRAYSCALE改成cv::IMREAD_GRAYSCALE。建議先用opencv_version確認你機器上的OpenCV版本若裝的是4系就提前做好改代碼的準備。4.2 運行ORB-SLAM2生成軌跡編譯完成后運行ORB-SLAM2調(diào)用RGB-D模式需要三個參數(shù)詞袋文件路徑、相機參數(shù)文件路徑和數(shù)據(jù)集序列路徑。以fr1/desk為例./Examples/RGB-D/rgbd_tum \ Vocabulary/ORBvoc.txt \ Examples/RGB-D/TUM1.yaml \ /path/to/fr1_desk執(zhí)行后程序會加載數(shù)據(jù)集圖像并進行實時跟蹤和建圖同時可視化窗口會顯示當(dāng)前相機位姿和地圖點。當(dāng)所有圖像處理完畢后ORB-SLAM2會在當(dāng)前目錄下生成一個CameraTrajectory.txt文件每行是時間戳、平移三軸和四元數(shù)這個文件就是我們要拿來評估的估計軌跡。還有一個可選參數(shù)associate.py生成的匹配文件。如果你的數(shù)據(jù)集圖像和真值時間戳偏差較大直接運行時系統(tǒng)可能因時間戳錯配找不到對應(yīng)幀。此時要先跑一遍時間戳匹配生成一個associations.txt文件然后把它作為第三個參數(shù)傳給程序例如python associate.py rgb.txt depth.txt associations.txt ./Examples/RGB-D/rgbd_tum \ Vocabulary/ORBvoc.txt \ Examples/RGB-D/TUM1.yaml \ /path/to/fr1_desk \ /path/to/associations.txt跑完后再看一眼CameraTrajectory.txt的文件大小如果只有幾行說明跟蹤出現(xiàn)大面積丟失需要檢查關(guān)聯(lián)文件和相機參數(shù)是否正確配置。4.3 evo評估與結(jié)果解讀得到估計軌跡文件后先用evo_traj可視化對比估計軌跡和真值軌跡的整體形狀evo_traj tum CameraTrajectory.txt --ref groundtruth.txt -a -p這里--ref指定真值軌跡-a做對齊-p可視化。如果估計軌跡和真值軌跡在整體形態(tài)上高度重合說明算法運行正常。如果兩條軌跡在起點一致但后續(xù)逐漸發(fā)散一般就是累積漂移導(dǎo)致屬于SLAM的固有特性重點看后面ATE的具體數(shù)值來定量判斷。接下來正式計算ATE和RPEevo_ape tum groundtruth.txt CameraTrajectory.txt -a -va evo_rpe tum groundtruth.txt CameraTrajectory.txt -r trans_part -d 1 -a -va-va參數(shù)會輸出詳細的對齊參數(shù)和每個時間點的誤差細節(jié)并把誤差曲線圖保存下來。運行完成后終端會打印RMSE、MAE、Median、Std、Max等統(tǒng)計結(jié)果。以fr1/desk為例一個調(diào)試正常的ORB-SBAM2系統(tǒng)ATE的RMSE通常在幾厘米以內(nèi)如果結(jié)果達到十幾厘米甚至更高就要檢查是不是有跟蹤丟失、參數(shù)標定不準確或者時間戳關(guān)聯(lián)出了問題。最后還可以用evo_res合并多次評估結(jié)果比如你在調(diào)參過程中記錄了多次運行結(jié)果可以用evo_res把多份誤差文件合并統(tǒng)計生成對比表這在做參數(shù)消融實驗時比較有用。5. 常見問題與排查技巧實錄5.1 evo安裝和依賴的坑安裝evo看似簡單實際上依賴問題最容易讓人卡住。我?guī)屯卵b的時候經(jīng)常遇到pip在安裝numpy或matplotlib過程中報編譯錯誤或者安裝完成后一運行evo_ape就提示找不到某個模塊。這里提供幾個經(jīng)過驗證的排查方向Python版本不要太高3.8到3.10之間最穩(wěn)3.11以上evo部分依賴可能有兼容問題。優(yōu)先在conda全新環(huán)境里裝evo避免系統(tǒng)Python里其他包版本干擾。如果運行evo時報ImportError: libGL.so.1: cannot open shared object file說明系統(tǒng)缺少OpenGL庫在Ubuntu上執(zhí)行sudo apt update sudo apt install libgl1 libglib2.0-0即可解決。evo的繪圖依賴tkinter如果你用的是headless服務(wù)器跑評估沒有GUI環(huán)境可以在腳本里用--save_plot參數(shù)保存圖片而不是彈出窗口或安裝python3-tk解決。5.2 軌跡格式不對導(dǎo)致解析失敗evo加載軌跡文件時報格式錯誤是最常見的問題之一。TUM格式要求每一行是timestamp tx ty tz qx qy qz qw注意四元數(shù)順序是x y z wKITTI格式每一行是3x4變換矩陣的12個數(shù)字EuRoC格式每一行是timestamp tx ty tz qw qx qy qz旋轉(zhuǎn)部分和TUM的順序不一樣。很多人在網(wǎng)上找到的軌跡文件或者從ROS的話題里導(dǎo)出的數(shù)據(jù)格式往往不標準直接喂給evo很容易報錯。建議拿到軌跡文件后先用head命令看一眼內(nèi)容結(jié)構(gòu)確認列數(shù)是否匹配。另外ROS用戶導(dǎo)出的geometry_msgs/PoseStamped話題需要先用evo_traj bag直接加載rosbag再轉(zhuǎn)成TUM或KITTI格式不要手動拼接文本容易出錯。5.3 時間戳對齊與插值的選擇評估時估計軌跡和真值軌跡的時間戳通常不是一一對應(yīng)的。evo在加載兩個軌跡后會默認做時間戳對齊把真值軌跡插值到估計軌跡的時間點上。這個插值邏輯本身很成熟但如果你在命令行加了--t_offset或--sync參數(shù)就要格外小心比如TUM數(shù)據(jù)集的時間戳單位是秒而KITTI的某些文件時間是微秒如果混用單位對齊結(jié)果會完全錯誤。還有一個常見誤區(qū)在計算ATE之前不做時間對齊就加-a此時對齊和誤差計算會變得混亂。建議先不加-a單純用evo_traj看一下兩條軌跡的時間范圍確認時間戳單位、起始時間差再決定是否需要調(diào)節(jié)時間偏移量。5.4 實操中的幾個實用小技巧最后分享幾個我在實際評測時總結(jié)的小技巧能幫你節(jié)省不少時間批量評估如果你在一個數(shù)據(jù)集上跑了很多參數(shù)組合別一個個手敲命令寫個shell腳本循環(huán)調(diào)用evo_ape把結(jié)果重定向到CSV文件最后用Excel或Python匯總。在ORB-SLAM運行過程中同步保存軌跡ORB-SLAM2默認只在程序結(jié)束后寫軌跡但長數(shù)據(jù)集跑到一半崩潰彈窗軌跡就丟了??梢栽诖a里加一個回調(diào)函數(shù)或定期寫文件的邏輯保證崩潰前的最新軌跡能保存下來這在調(diào)試階段很救命。用--plot_mode調(diào)整繪圖視角evo默認的繪圖是俯視圖xy平面但你如果關(guān)心高度方向的漂移可以把--plot_mode改成xyz或者xz多視角看誤差明顯程度不同往往俯視圖看起來貼合得很好換到側(cè)視圖就露餡了。同時評估多個軌跡evo_traj支持一次加載多個估計軌跡配合--ref真值軌跡可以在同一張圖上對比不同參數(shù)下算法表現(xiàn)的差異比跑完一次截圖一次直觀得多。我個人的體會是數(shù)據(jù)集、算法、評估工具這三者是一套組合拳缺哪一個都不完整。很多人在調(diào)SLAM參數(shù)時只盯著可視化窗口看“感覺還挺穩(wěn)定”缺少量化數(shù)據(jù)的反饋這樣優(yōu)化起來效率很低。而當(dāng)你把evo接入日常工作流每次跑完數(shù)據(jù)都自動計算ATE和RPE算法改進的效果是好是壞就一目了然了。后續(xù)如果你想做更嚴謹?shù)脑u測還可以把evo集成到你的訓(xùn)練或調(diào)參腳本里實現(xiàn)每次實驗結(jié)束自動出報告效率會提升非常明顯。