日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【LeGO-LOAM论文阅读(二)--特征提取(二)】

發布時間:2023/12/14 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【LeGO-LOAM论文阅读(二)--特征提取(二)】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介

上篇博客介紹了特征提取的原理以及坐標轉化和插值的源碼理解,這篇將介紹特征提取的后續算法模塊。

源碼

1、新數據進來進行坐標轉換和插補等工作

見【LeGO-LOAM論文閱讀(二)–特征提取(一)】

2、進行光滑度計算

光滑度計算公式:

S取10,代表參與計算點數,計算點左右各有5個,r表示深度距離,計算點云開始5個點后到點云結束5個點前的點云平滑度,計算方式與論文中給的并不一樣。

// 計算光滑性,這里的計算沒有完全按照公式進行,// 缺少除以總點數i和r[i]void calculateSmoothness(){int cloudSize = segmentedCloud->points.size();for (int i = 5; i < cloudSize - 5; i++) {float diffRange = segInfo.segmentedCloudRange[i-5] + segInfo.segmentedCloudRange[i-4]+ segInfo.segmentedCloudRange[i-3] + segInfo.segmentedCloudRange[i-2]+ segInfo.segmentedCloudRange[i-1] - segInfo.segmentedCloudRange[i] * 10+ segInfo.segmentedCloudRange[i+1] + segInfo.segmentedCloudRange[i+2]+ segInfo.segmentedCloudRange[i+3] + segInfo.segmentedCloudRange[i+4]+ segInfo.segmentedCloudRange[i+5]; cloudCurvature[i] = diffRange*diffRange;

初始化點云標簽,初始化為0,surfPointsFlat標記為-1,surfPointsLessFlatScan為不大于0的標簽,cornerPointsSharp標記為2,cornerPointsLessSharp標記為1。

// 在markOccludedPoints()函數中對該參數進行重新修改cloudNeighborPicked[i] = 0;// 在extractFeatures()函數中會對標簽進行修改,// 初始化為0,surfPointsFlat標記為-1,surfPointsLessFlatScan為不大于0的標簽// cornerPointsSharp標記為2,cornerPointsLessSharp標記為1cloudLabel[i] = 0;cloudSmoothness[i].value = cloudCurvature[i];cloudSmoothness[i].ind = i;}}

3、標記阻塞點。

阻塞點指點云之間相互遮擋而且距離比較近的點。將被遮擋的點云連續五個標志位cloudNeighborPicked標記為1。depth大的那個就是被遮擋的那個。具體參數設置為什么是10和0.3我也不清楚,應該是是試驗過的,各位可以考慮話說弄成別的試試

void markOccludedPoints(){int cloudSize = segmentedCloud->points.size();for (int i = 5; i < cloudSize - 6; ++i){float depth1 = segInfo.segmentedCloudRange[i];float depth2 = segInfo.segmentedCloudRange[i+1];int columnDiff = std::abs(int(segInfo.segmentedCloudColInd[i+1] - segInfo.segmentedCloudColInd[i]));if (columnDiff < 10){// 選擇距離較遠的那些點,并將他們標記為1if (depth1 - depth2 > 0.3){cloudNeighborPicked[i - 5] = 1;cloudNeighborPicked[i - 4] = 1;cloudNeighborPicked[i - 3] = 1;cloudNeighborPicked[i - 2] = 1;cloudNeighborPicked[i - 1] = 1;cloudNeighborPicked[i] = 1;}else if (depth2 - depth1 > 0.3){cloudNeighborPicked[i + 1] = 1;cloudNeighborPicked[i + 2] = 1;cloudNeighborPicked[i + 3] = 1;cloudNeighborPicked[i + 4] = 1;cloudNeighborPicked[i + 5] = 1;cloudNeighborPicked[i + 6] = 1;}}

接著排除共面的情況,舍棄距離變換比較大的點

float diff1 = std::abs(segInfo.segmentedCloudRange[i-1] - segInfo.segmentedCloudRange[i]);float diff2 = std::abs(segInfo.segmentedCloudRange[i+1] - segInfo.segmentedCloudRange[i]);// 選擇距離變化較大的點,并將他們標記為1if (diff1 > 0.02 * segInfo.segmentedCloudRange[i] && diff2 > 0.02 * segInfo.segmentedCloudRange[i])cloudNeighborPicked[i] = 1;}}

4、特征抽取。

這部分對計算好平滑度的點云將進行特征提取,提取出線特征和面特征。由于點云過于龐大,后面處理的時候對點云進行了下采樣來提高計算效率。
清空上一幀特征:

void extractFeatures(){cornerPointsSharp->clear();cornerPointsLessSharp->clear();surfPointsFlat->clear();surfPointsLessFlat->clear();

將每一幀點云數據按水平角度分為6份,每份是60°的激光數據,sp儲存的是每份數據的起點,ep儲存的是每份數據的終點。

for (int i = 0; i < N_SCAN; i++) {surfPointsLessFlatScan->clear();for (int j = 0; j < 6; j++) {// sp和ep的含義是什么???startPointer,endPointer?int sp = (segInfo.startRingIndex[i] * (6 - j) + segInfo.endRingIndex[i] * j) / 6;int ep = (segInfo.startRingIndex[i] * (5 - j) + segInfo.endRingIndex[i] * (j + 1)) / 6 - 1;if (sp >= ep)continue;

將每份點云按照平滑度進行排序(由小到大):

std::sort(cloudSmoothness.begin()+sp, cloudSmoothness.begin()+ep, by_value());

提取線特征的條件:不是被淘汰的點(cloudNeighborPicked=0)并且平滑度大于設定的閾值還有不能是地面點:

int largestPickedNum = 0;for (int k = ep; k >= sp; k--) {// 每次ind的值就是等于k??? 有什么意義?// 因為上面對cloudSmoothness進行了一次從小到大排序,所以ind不一定等于k了int ind = cloudSmoothness[k].ind;if (cloudNeighborPicked[ind] == 0 &&cloudCurvature[ind] > edgeThreshold &&segInfo.segmentedCloudGroundFlag[ind] == false) {

在滿足條件的點云中,將最大平滑度的兩個點云加入到cornerPointsSharp中,并將標志cloudLabel置為2

largestPickedNum++;if (largestPickedNum <= 2) {// 論文中nFe=2,cloudSmoothness已經按照從小到大的順序排列,// 所以這邊只要選擇最后兩個放進隊列即可// cornerPointsSharp標記為2cloudLabel[ind] = 2;cornerPointsSharp->push_back(segmentedCloud->points[ind]);cornerPointsLessSharp->push_back(segmentedCloud->points[ind]);

將平滑度前20的點云加入到cornerPointsLessSharp中,并將cloudLabel置為1

} else if (largestPickedNum <= 20) {// 塞20個點到cornerPointsLessSharp中去// cornerPointsLessSharp標記為1cloudLabel[ind] = 1;cornerPointsLessSharp->push_back(segmentedCloud->points[ind]);} else {break;}

將已經加入到cornerPointsSharp和cornerPointsLessSharp中的點淘汰,后面不再用:

cloudNeighborPicked[ind] = 1;

計算已經被選為線特征點云前后5個點之間的距離差值,若距離較近
同樣淘汰(避免兩個特征點表示的是同一個線特征):

for (int l = 1; l <= 5; l++) {// 從ind+l開始后面5個點,每個點index之間的差值,// 確保columnDiff<=10,然后標記為我們需要的點int columnDiff = std::abs(int(segInfo.segmentedCloudColInd[ind + l] - segInfo.segmentedCloudColInd[ind + l - 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind + l] = 1;}for (int l = -1; l >= -5; l--) {// 從ind+l開始前面五個點,計算差值然后標記int columnDiff = std::abs(int(segInfo.segmentedCloudColInd[ind + l] - segInfo.segmentedCloudColInd[ind + l + 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind + l] = 1;}}}

提取面特征的條件,不能是淘汰點,平滑度小于設定閾值并且只能是地面點:

int smallestPickedNum = 0;for (int k = sp; k <= ep; k++) {int ind = cloudSmoothness[k].ind;// 平面點只從地面點中進行選擇? 為什么要這樣做?if (cloudNeighborPicked[ind] == 0 &&cloudCurvature[ind] < surfThreshold &&segInfo.segmentedCloudGroundFlag[ind] == true) {

將滿足條件的點加入surfPointsFlat同時標志cloudLabel設為-1:

cloudLabel[ind] = -1;surfPointsFlat->push_back(segmentedCloud->points[ind]);

將最小平滑度的四個點放入surfPointsFlat,同時設置為淘汰點。

// 論文中nFp=4,將4個最平的平面點放入隊列中smallestPickedNum++;if (smallestPickedNum >= 4) {break;}cloudNeighborPicked[ind] = 1;

同時判斷面特征點前后5個點并標記(和線特征一樣):

for (int l = 1; l <= 5; l++) {// 從前面往后判斷是否是需要的鄰接點,是的話就進行標記int columnDiff = std::abs(int(segInfo.segmentedCloudColInd[ind + l] - segInfo.segmentedCloudColInd[ind + l - 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind + l] = 1;}for (int l = -1; l >= -5; l--) {// 從后往前開始標記int columnDiff = std::abs(int(segInfo.segmentedCloudColInd[ind + l] - segInfo.segmentedCloudColInd[ind + l + 1]));if (columnDiff > 10)break;cloudNeighborPicked[ind + l] = 1;}}}

將cloudLabe<= 0的點先都加入 surfPointsLessFlatScan中:

for (int k = sp; k <= ep; k++) {if (cloudLabel[k] <= 0) {surfPointsLessFlatScan->push_back(segmentedCloud->points[k]);}}}

surfPointsLessFlatScan中的點云會非常的多,為了提高計算效率,對點云進行下采樣:

// surfPointsLessFlatScan中有過多的點云,如果點云太多,計算量太大// 進行下采樣,可以大大減少計算量surfPointsLessFlatScanDS->clear();downSizeFilter.setInputCloud(surfPointsLessFlatScan);downSizeFilter.filter(*surfPointsLessFlatScanDS);*surfPointsLessFlat += *surfPointsLessFlatScanDS;}}

5、發布四種點云信息。

分別發布平滑度大的點云、平滑度較大的點云、平滑度小的點云、平滑度較小的點云:

void publishCloud(){sensor_msgs::PointCloud2 laserCloudOutMsg;if (pubCornerPointsSharp.getNumSubscribers() != 0){pcl::toROSMsg(*cornerPointsSharp, laserCloudOutMsg);laserCloudOutMsg.header.stamp = cloudHeader.stamp;laserCloudOutMsg.header.frame_id = "/camera";pubCornerPointsSharp.publish(laserCloudOutMsg);}if (pubCornerPointsLessSharp.getNumSubscribers() != 0){pcl::toROSMsg(*cornerPointsLessSharp, laserCloudOutMsg);laserCloudOutMsg.header.stamp = cloudHeader.stamp;laserCloudOutMsg.header.frame_id = "/camera";pubCornerPointsLessSharp.publish(laserCloudOutMsg);}if (pubSurfPointsFlat.getNumSubscribers() != 0){pcl::toROSMsg(*surfPointsFlat, laserCloudOutMsg);laserCloudOutMsg.header.stamp = cloudHeader.stamp;laserCloudOutMsg.header.frame_id = "/camera";pubSurfPointsFlat.publish(laserCloudOutMsg);}if (pubSurfPointsLessFlat.getNumSubscribers() != 0){pcl::toROSMsg(*surfPointsLessFlat, laserCloudOutMsg);laserCloudOutMsg.header.stamp = cloudHeader.stamp;laserCloudOutMsg.header.frame_id = "/camera";pubSurfPointsLessFlat.publish(laserCloudOutMsg);}}

回到runFeatureAssociation函數里,判斷有沒有初始化·,即判斷是不是第一幀數據,systemInitedLM初始為0,:

if (!systemInitedLM) {checkSystemInitialization();return;}

將第一幀的曲率較大的點保存為上一幀用于匹配的線特征:

void checkSystemInitialization(){// 交換cornerPointsLessSharp和laserCloudCornerLastpcl::PointCloud<PointType>::Ptr laserCloudTemp = cornerPointsLessSharp;cornerPointsLessSharp = laserCloudCornerLast;laserCloudCornerLast = laserCloudTemp;

將第一幀的曲率較小的點保存為上一幀用于匹配的面特征

// 交換surfPointsLessFlat和laserCloudSurfLastlaserCloudTemp = surfPointsLessFlat;surfPointsLessFlat = laserCloudSurfLast;laserCloudSurfLast = laserCloudTemp;

將特征點保存到KD樹中:

kdtreeCornerLast->setInputCloud(laserCloudCornerLast);kdtreeSurfLast->setInputCloud(laserCloudSurfLast);

記錄特征點數

laserCloudCornerLastNum = laserCloudCornerLast->points.size();laserCloudSurfLastNum = laserCloudSurfLast->points.size();

發布特征點云消息:

sensor_msgs::PointCloud2 laserCloudCornerLast2;pcl::toROSMsg(*laserCloudCornerLast, laserCloudCornerLast2);laserCloudCornerLast2.header.stamp = cloudHeader.stamp;laserCloudCornerLast2.header.frame_id = "/camera";pubLaserCloudCornerLast.publish(laserCloudCornerLast2);sensor_msgs::PointCloud2 laserCloudSurfLast2;pcl::toROSMsg(*laserCloudSurfLast, laserCloudSurfLast2);laserCloudSurfLast2.header.stamp = cloudHeader.stamp;laserCloudSurfLast2.header.frame_id = "/camera";pubLaserCloudSurfLast.publish(laserCloudSurfLast2);

保存累積旋轉量:

transformSum[0] += imuPitchStart;transformSum[2] += imuRollStart;

checkSystemInitialization判斷完第一幀數據將systemInitedLM設為1

systemInitedLM = true; }

6、更新位姿

這里主要是保存當前點云中最后一個點的旋轉角、最后一個點相對于第一個點的位移以及速度:

void updateInitialGuess(){imuPitchLast = imuPitchCur;imuYawLast = imuYawCur;imuRollLast = imuRollCur;imuShiftFromStartX = imuShiftFromStartXCur;imuShiftFromStartY = imuShiftFromStartYCur;imuShiftFromStartZ = imuShiftFromStartZCur;imuVeloFromStartX = imuVeloFromStartXCur;imuVeloFromStartY = imuVeloFromStartYCur;imuVeloFromStartZ = imuVeloFromStartZCur;

但是我發現最后一個點的位移變換函數根本沒有被調用,我覺得這個函數是要在插值和坐標轉那被調用,可以并沒有,有沒有大佬能解釋下。

void ShiftToStartIMU(float pointTime){// 下面三個量表示的是世界坐標系下,從start到cur的坐標的漂移imuShiftFromStartXCur = imuShiftXCur - imuShiftXStart - imuVeloXStart * pointTime;imuShiftFromStartYCur = imuShiftYCur - imuShiftYStart - imuVeloYStart * pointTime;imuShiftFromStartZCur = imuShiftZCur - imuShiftZStart - imuVeloZStart * pointTime;// 從世界坐標系變換到start坐標系float x1 = cosImuYawStart * imuShiftFromStartXCur - sinImuYawStart * imuShiftFromStartZCur;float y1 = imuShiftFromStartYCur;float z1 = sinImuYawStart * imuShiftFromStartXCur + cosImuYawStart * imuShiftFromStartZCur;float x2 = x1;float y2 = cosImuPitchStart * y1 + sinImuPitchStart * z1;float z2 = -sinImuPitchStart * y1 + cosImuPitchStart * z1;imuShiftFromStartXCur = cosImuRollStart * x2 + sinImuRollStart * y2;imuShiftFromStartYCur = -sinImuRollStart * x2 + cosImuRollStart * y2;imuShiftFromStartZCur = z2;}

更新旋轉量(相鄰兩幀):

// 關于下面負號的說明:// transformCur是在Cur坐標系下的 p_start=R*p_cur+t// R和t是在Cur坐標系下的// 而imuAngularFromStart是在start坐標系下的,所以需要加負號if (imuAngularFromStartX != 0 || imuAngularFromStartY != 0 || imuAngularFromStartZ != 0){transformCur[0] = - imuAngularFromStartY;transformCur[1] = - imuAngularFromStartZ;transformCur[2] = - imuAngularFromStartX;

更新位移量(兩幀之間):

// 速度乘以時間,當前變換中的位移if (imuVeloFromStartX != 0 || imuVeloFromStartY != 0 || imuVeloFromStartZ != 0){transformCur[3] -= imuVeloFromStartX * scanPeriod;transformCur[4] -= imuVeloFromStartY * scanPeriod;transformCur[5] -= imuVeloFromStartZ * scanPeriod;}}

7、更新變換矩陣。

如果線特征或者面特征太少,直接退出:

void updateTransformation(){if (laserCloudCornerLastNum < 10 || laserCloudSurfLastNum < 100)return;

尋找面特征對應點findCorrespondingSurfFeatures, iterCount迭代次數?:

for (int iterCount1 = 0; iterCount1 < 25; iterCount1++) {laserCloudOri->clear();coeffSel->clear();// 找到對應的特征平面// 然后計算協方差矩陣,保存在coeffSel隊列中// laserCloudOri中保存的是對應于coeffSel的未轉換到開始時刻的原始點云數據findCorrespondingSurfFeatures(iterCount1);

面特征點數賦值:

void findCorrespondingSurfFeatures(int iterCount){int surfPointsFlatNum = surfPointsFlat->points.size();

將特征點坐標變換到開始時刻 TransformToStart:

for (int i = 0; i < surfPointsFlatNum; i++) {// 坐標變換到開始時刻,參數0是輸入,參數1是輸出TransformToStart(&surfPointsFlat->points[i], &pointSel);

注意假設了勻速運動模型,也就是說位姿的變化是線性的,而代碼中提到的s就是隨時間線性變化的因子。回顧之前點云強度的保存的數據的計算,point.intensity = int(segmentedCloud->points[i].intensity) + scanPeriod * relTime;,再結合s的定義, float s = 10 * (pi->intensity - int(pi->intensity));,發現s就是relTime,為當前點云時間減去初始點云相對于幀點云時間差的比值。

void TransformToStart(PointType const * const pi, PointType * const po){// intensity代表的是:整數部分ring序號,小數部分是當前點在這一圈中所花的時間// 關于intensity, 參考 adjustDistortion() 函數中的定義// s代表的其實是一個比例,s的計算方法應該如下:// s=(pi->intensity - int(pi->intensity))/SCAN_PERIOD// ===> SCAN_PERIOD=0.1(雷達頻率為10hz)// 以上理解感謝github用戶StefanGlaser// https://github.com/laboshinl/loam_velodyne/issues/29float s = 10 * (pi->intensity - int(pi->intensity));

計算當前點云和開始時刻的旋轉角度以及位移,這里用了勻速運動模型:

float rx = s * transformCur[0];float ry = s * transformCur[1];float rz = s * transformCur[2];float tx = s * transformCur[3];float ty = s * transformCur[4];float tz = s * transformCur[5];

計算特征點對應于開始時刻坐標系的坐標,先平移在旋轉:

float x1 = cos(rz) * (pi->x - tx) + sin(rz) * (pi->y - ty);float y1 = -sin(rz) * (pi->x - tx) + cos(rz) * (pi->y - ty);float z1 = (pi->z - tz);float x2 = x1;float y2 = cos(rx) * y1 + sin(rx) * z1;float z2 = -sin(rx) * y1 + cos(rx) * z1;po->x = cos(ry) * x2 - sin(ry) * z2;po->y = y2;po->z = sin(ry) * x2 + cos(ry) * z2;po->intensity = pi->intensity;}

每5此迭代重新匹配特征點:

if (iterCount % 5 == 0) {

在上一幀曲率較小的點(平面特征點)組成的KD樹中尋找一個最近鄰點:

kdtreeSurfLast->nearestKSearch(pointSel, 1, pointSearchInd, pointSearchSqDis);int closestPointInd = -1, minPointInd2 = -1, minPointInd3 = -1;// sq:平方,距離的平方值// 如果nearestKSearch找到的1(k=1)個鄰近點滿足條件if (pointSearchSqDis[0] < nearestFeatureSearchSqDist) {closestPointInd = pointSearchInd[0];

找到該最近鄰點的線束(第幾行第幾列)point.intensity保存里點云的行列值:

// point.intensity 保存的是什么值? 第幾次scan?// thisPoint.intensity = (float)rowIdn + (float)columnIdn / 10000.0;// fullInfoCloud->points[index].intensity = range;// 在imageProjection.cpp文件中有上述兩行代碼,兩種類型的值,應該存的是上面一個int closestPointScan = int(laserCloudSurfLast->points[closestPointInd].intensity);

在最近鄰點i 所在線束尋找再尋找另外一個最近點,以及在最近鄰點i ii所在線束的相鄰線束中尋找第三個最近點,組成匹配平面:

// 主要功能是找到2個scan之內的最近點,并將找到的最近點及其序號保存// 之前掃描的保存到minPointSqDis2,之后的保存到minPointSqDis2float pointSqDis, minPointSqDis2 = nearestFeatureSearchSqDist, minPointSqDis3 = nearestFeatureSearchSqDist;

首先在雷達點云存儲的正方向(ScanID增大的方向和雷達旋轉正方向)尋找其他兩個點,為什么加上2.5,因為上下兩個scan相差2°:

for (int j = closestPointInd + 1; j < surfPointsFlatNum; j++) {// int類型的值加上2.5? 為什么不直接加上2?// 四舍五入if (int(laserCloudSurfLast->points[j].intensity) > closestPointScan + 2.5) {break;}

計算距離,找到最近鄰的點,將之前掃描到的點保存在minPointSqDis2中,之后掃描到的保存在minPointSqDis3中:

pointSqDis = (laserCloudSurfLast->points[j].x - pointSel.x) * (laserCloudSurfLast->points[j].x - pointSel.x) + (laserCloudSurfLast->points[j].y - pointSel.y) * (laserCloudSurfLast->points[j].y - pointSel.y) + (laserCloudSurfLast->points[j].z - pointSel.z) * (laserCloudSurfLast->points[j].z - pointSel.z);if (int(laserCloudSurfLast->points[j].intensity) <= closestPointScan) {if (pointSqDis < minPointSqDis2) {minPointSqDis2 = pointSqDis;minPointInd2 = j;}} else {if (pointSqDis < minPointSqDis3) {minPointSqDis3 = pointSqDis;minPointInd3 = j;}}

反方向(ScanID減小的方向和雷達旋轉反方向尋找點,并確定總的最近鄰點:

// 往前找for (int j = closestPointInd - 1; j >= 0; j--) {if (int(laserCloudSurfLast->points[j].intensity) < closestPointScan - 2.5) {break;}pointSqDis = (laserCloudSurfLast->points[j].x - pointSel.x) * (laserCloudSurfLast->points[j].x - pointSel.x) + (laserCloudSurfLast->points[j].y - pointSel.y) * (laserCloudSurfLast->points[j].y - pointSel.y) + (laserCloudSurfLast->points[j].z - pointSel.z) * (laserCloudSurfLast->points[j].z - pointSel.z);if (int(laserCloudSurfLast->points[j].intensity) >= closestPointScan) {if (pointSqDis < minPointSqDis2) {minPointSqDis2 = pointSqDis;minPointInd2 = j;}} else {if (pointSqDis < minPointSqDis3) {minPointSqDis3 = pointSqDis;minPointInd3 = j;}}}}

找到平面匹配的三個點:

pointSearchSurfInd1[i] = closestPointInd;pointSearchSurfInd2[i] = minPointInd2;pointSearchSurfInd3[i] = minPointInd3;}

找到特征點的對應點以后的工作就是計算距離了,在這里還計算了平面法向量(就是點到平面的直線的方向向量)在各個軸的方向分解,在雅可比的計算中使用:

// 前后都能找到對應的最近點在給定范圍之內// 那么就開始計算距離// [pa,pb,pc]是tripod1,tripod2,tripod3這3個點構成的一個平面的方向量,// ps是模長,它是三角形面積的2倍if (pointSearchSurfInd2[i] >= 0 && pointSearchSurfInd3[i] >= 0) {tripod1 = laserCloudSurfLast->points[pointSearchSurfInd1[i]];tripod2 = laserCloudSurfLast->points[pointSearchSurfInd2[i]];tripod3 = laserCloudSurfLast->points[pointSearchSurfInd3[i]];float pa = (tripod2.y - tripod1.y) * (tripod3.z - tripod1.z) - (tripod3.y - tripod1.y) * (tripod2.z - tripod1.z);float pb = (tripod2.z - tripod1.z) * (tripod3.x - tripod1.x) - (tripod3.z - tripod1.z) * (tripod2.x - tripod1.x);float pc = (tripod2.x - tripod1.x) * (tripod3.y - tripod1.y) - (tripod3.x - tripod1.x) * (tripod2.y - tripod1.y);float pd = -(pa * tripod1.x + pb * tripod1.y + pc * tripod1.z);float ps = sqrt(pa * pa + pb * pb + pc * pc);pa /= ps;pb /= ps;pc /= ps;pd /= ps;// 距離沒有取絕對值// 兩個向量的點乘,分母除以ps中已經除掉了,// 加pd原因:pointSel與tripod1構成的線段需要相減float pd2 = pa * pointSel.x + pb * pointSel.y + pc * pointSel.z + pd;float s = 1;if (iterCount >= 5) {// /加上影響因子s = 1 - 1.8 * fabs(pd2) / sqrt(sqrt(pointSel.x * pointSel.x+ pointSel.y * pointSel.y + pointSel.z * pointSel.z));}if (s > 0.1 && pd2 != 0) {// [x,y,z]是整個平面的單位法量// intensity是平面外一點到該平面的距離coeff.x = s * pa;coeff.y = s * pb;coeff.z = s * pc;coeff.intensity = s * pd2;// 未經變換的點放入laserCloudOri隊列,距離,法向量值放入coeffSellaserCloudOri->push_back(surfPointsFlat->points[i]);coeffSel->push_back(coeff);}}}}

面特征優化(這塊我看暈了,以下參考LeGO-LOAM源碼解析5: featureAssociation(三)):
定義各個矩陣,matA表示J,matAtA表示H,matAtB表示b:

int pointSelNum = laserCloudOri->points.size();cv::Mat matA(pointSelNum, 3, CV_32F, cv::Scalar::all(0));cv::Mat matAt(3, pointSelNum, CV_32F, cv::Scalar::all(0));cv::Mat matAtA(3, 3, CV_32F, cv::Scalar::all(0));cv::Mat matB(pointSelNum, 1, CV_32F, cv::Scalar::all(0));cv::Mat matAtB(3, 1, CV_32F, cv::Scalar::all(0));cv::Mat matX(3, 1, CV_32F, cv::Scalar::all(0));

對每個線特征點求關于對應三個變量的解雅可比矩陣A和損失向量B,拼裝成為一個大的求解矩陣:

float srx = sin(transformCur[0]);float crx = cos(transformCur[0]);float sry = sin(transformCur[1]);float cry = cos(transformCur[1]);float srz = sin(transformCur[2]);float crz = cos(transformCur[2]);float tx = transformCur[3];float ty = transformCur[4];float tz = transformCur[5];float a1 = crx*sry*srz; float a2 = crx*crz*sry; float a3 = srx*sry; float a4 = tx*a1 - ty*a2 - tz*a3;float a5 = srx*srz; float a6 = crz*srx; float a7 = ty*a6 - tz*crx - tx*a5;float a8 = crx*cry*srz; float a9 = crx*cry*crz; float a10 = cry*srx; float a11 = tz*a10 + ty*a9 - tx*a8;float b1 = -crz*sry - cry*srx*srz; float b2 = cry*crz*srx - sry*srz;float b5 = cry*crz - srx*sry*srz; float b6 = cry*srz + crz*srx*sry;float c1 = -b6; float c2 = b5; float c3 = tx*b6 - ty*b5; float c4 = -crx*crz; float c5 = crx*srz; float c6 = ty*c5 + tx*-c4;float c7 = b2; float c8 = -b1; float c9 = tx*-b2 - ty*-b1;// 構建雅可比矩陣,求解for (int i = 0; i < pointSelNum; i++) {pointOri = laserCloudOri->points[i];coeff = coeffSel->points[i];float arx = (-a1*pointOri.x + a2*pointOri.y + a3*pointOri.z + a4) * coeff.x+ (a5*pointOri.x - a6*pointOri.y + crx*pointOri.z + a7) * coeff.y+ (a8*pointOri.x - a9*pointOri.y - a10*pointOri.z + a11) * coeff.z;float arz = (c1*pointOri.x + c2*pointOri.y + c3) * coeff.x+ (c4*pointOri.x - c5*pointOri.y + c6) * coeff.y+ (c7*pointOri.x + c8*pointOri.y + c9) * coeff.z;float aty = -b6 * coeff.x + c4 * coeff.y + b2 * coeff.z;float d2 = coeff.intensity;matA.at<float>(i, 0) = arx;matA.at<float>(i, 1) = arz;matA.at<float>(i, 2) = aty;matB.at<float>(i, 0) = -0.05 * d2;}

使用OpenCV函數進行求解,利用QR分解加速:

cv::transpose(matA, matAt);matAtA = matAt * matA;matAtB = matAt * matB;cv::solve(matAtA, matAtB, matX, cv::DECOMP_QR);

關于退化問題的討論,與LOAM中一致,請參考loam源碼解析5 : laserOdometry(三)中的退化問題分析:

if (iterCount == 0) {cv::Mat matE(1, 3, CV_32F, cv::Scalar::all(0));cv::Mat matV(3, 3, CV_32F, cv::Scalar::all(0));cv::Mat matV2(3, 3, CV_32F, cv::Scalar::all(0));cv::eigen(matAtA, matE, matV);matV.copyTo(matV2);isDegenerate = false;float eignThre[3] = {10, 10, 10};for (int i = 2; i >= 0; i--) {if (matE.at<float>(0, i) < eignThre[i]) {for (int j = 0; j < 3; j++) {matV2.at<float>(i, j) = 0;}isDegenerate = true;} else {break;}}matP = matV.inv() * matV2;}if (isDegenerate) {cv::Mat matX2(3, 1, CV_32F, cv::Scalar::all(0));matX.copyTo(matX2);matX = matP * matX2;}

使用迭代計算的增量進行姿態更新:

transformCur[1] += matX.at<float>(0, 0);transformCur[3] += matX.at<float>(1, 0);transformCur[5] += matX.at<float>(2, 0);for(int i=0; i<6; i++){if(isnan(transformCur[i]))transformCur[i]=0;}

計算姿態是否合法,以及是否滿足迭代條件:

float deltaR = sqrt(pow(rad2deg(matX.at<float>(0, 0)), 2) +pow(rad2deg(matX.at<float>(1, 0)), 2));float deltaT = sqrt(pow(matX.at<float>(2, 0) * 100, 2));if (deltaR < 0.1 && deltaT < 0.1) {return false;}return true;}

線特征匹配與優化:

for (int iterCount2 = 0; iterCount2 < 25; iterCount2++) {laserCloudOri->clear();coeffSel->clear();// 找到對應的特征邊/角點// 尋找邊特征的方法和尋找平面特征的很類似,過程可以參照尋找平面特征的注釋findCorrespondingCornerFeatures(iterCount2);if (laserCloudOri->points.size() < 10)continue;// 通過角/邊特征的匹配,計算變換矩陣if (calculateTransformationCorner(iterCount2) == false)break;}}

這塊和面特征匹配優化的思想類似:
將曲率大的點(待匹配的特征點)的坐標全部轉換到當前幀的初始時刻:

void findCorrespondingCornerFeatures(int iterCount){int cornerPointsSharpNum = cornerPointsSharp->points.size();for (int i = 0; i < cornerPointsSharpNum; i++) {TransformToStart(&cornerPointsSharp->points[i], &pointSel);

每五次迭代重新匹配特征點:

if (iterCount % 5 == 0) {

在上一幀曲率較大的點組成的KD樹中尋找一個最近鄰點,找到該最近鄰點的線束,

kdtreeCornerLast->nearestKSearch(pointSel, 1, pointSearchInd, pointSearchSqDis);int closestPointInd = -1, minPointInd2 = -1;if (pointSearchSqDis[0] < nearestFeatureSearchSqDist) {closestPointInd = pointSearchInd[0];int closestPointScan = int(laserCloudCornerLast->points[closestPointInd].intensity);

在最近鄰點i ii所在線束的相鄰線束中尋找第二個最近點,組成匹配直線:
首先在雷達點云存儲的正方向(ScanID增大的方向和雷達旋轉正方向)尋找另外一個點:
然后在雷達點云存儲的反方向(ScanID減小的方向和雷達旋轉反方向)尋找其他兩個點:

float pointSqDis, minPointSqDis2 = nearestFeatureSearchSqDist;for (int j = closestPointInd + 1; j < cornerPointsSharpNum; j++) {if (int(laserCloudCornerLast->points[j].intensity) > closestPointScan + 2.5) {break;}pointSqDis = (laserCloudCornerLast->points[j].x - pointSel.x) * (laserCloudCornerLast->points[j].x - pointSel.x) + (laserCloudCornerLast->points[j].y - pointSel.y) * (laserCloudCornerLast->points[j].y - pointSel.y) + (laserCloudCornerLast->points[j].z - pointSel.z) * (laserCloudCornerLast->points[j].z - pointSel.z);if (int(laserCloudCornerLast->points[j].intensity) > closestPointScan) {if (pointSqDis < minPointSqDis2) {minPointSqDis2 = pointSqDis;minPointInd2 = j;}}}for (int j = closestPointInd - 1; j >= 0; j--) {if (int(laserCloudCornerLast->points[j].intensity) < closestPointScan - 2.5) {break;}pointSqDis = (laserCloudCornerLast->points[j].x - pointSel.x) * (laserCloudCornerLast->points[j].x - pointSel.x) + (laserCloudCornerLast->points[j].y - pointSel.y) * (laserCloudCornerLast->points[j].y - pointSel.y) + (laserCloudCornerLast->points[j].z - pointSel.z) * (laserCloudCornerLast->points[j].z - pointSel.z);if (int(laserCloudCornerLast->points[j].intensity) < closestPointScan) {if (pointSqDis < minPointSqDis2) {minPointSqDis2 = pointSqDis;minPointInd2 = j;}}}}

找到用于匹配的兩個點(形成邊緣線):

pointSearchCornerInd1[i] = closestPointInd;pointSearchCornerInd2[i] = minPointInd2;}

找到特征點的對應點以后的工作就是計算距離了,在這里還計算了就是點到直線的方向向量在各個軸的方向分解,在雅可比的計算中使用:

if (pointSearchCornerInd2[i] >= 0) {tripod1 = laserCloudCornerLast->points[pointSearchCornerInd1[i]];tripod2 = laserCloudCornerLast->points[pointSearchCornerInd2[i]];float x0 = pointSel.x;float y0 = pointSel.y;float z0 = pointSel.z;float x1 = tripod1.x;float y1 = tripod1.y;float z1 = tripod1.z;float x2 = tripod2.x;float y2 = tripod2.y;float z2 = tripod2.z;float m11 = ((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1));float m22 = ((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1));float m33 = ((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1));float a012 = sqrt(m11 * m11 + m22 * m22 + m33 * m33);float l12 = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2));float la = ((y1 - y2)*m11 + (z1 - z2)*m22) / a012 / l12;float lb = -((x1 - x2)*m11 - (z1 - z2)*m33) / a012 / l12;float lc = -((x1 - x2)*m22 + (y1 - y2)*m33) / a012 / l12;float ld2 = a012 / l12;float s = 1;if (iterCount >= 5) {s = 1 - 1.8 * fabs(ld2);}if (s > 0.1 && ld2 != 0) {coeff.x = s * la; coeff.y = s * lb;coeff.z = s * lc;coeff.intensity = s * ld2;laserCloudOri->push_back(cornerPointsSharp->points[i]);coeffSel->push_back(coeff);}}}}

線特征優化(我已經麻了):

bool calculateTransformationCorner(int iterCount){int pointSelNum = laserCloudOri->points.size();cv::Mat matA(pointSelNum, 3, CV_32F, cv::Scalar::all(0));cv::Mat matAt(3, pointSelNum, CV_32F, cv::Scalar::all(0));cv::Mat matAtA(3, 3, CV_32F, cv::Scalar::all(0));cv::Mat matB(pointSelNum, 1, CV_32F, cv::Scalar::all(0));cv::Mat matAtB(3, 1, CV_32F, cv::Scalar::all(0));cv::Mat matX(3, 1, CV_32F, cv::Scalar::all(0));// 以下為開始計算A,A=[J的偏導],J的偏導的計算公式是什么?float srx = sin(transformCur[0]);float crx = cos(transformCur[0]);float sry = sin(transformCur[1]);float cry = cos(transformCur[1]);float srz = sin(transformCur[2]);float crz = cos(transformCur[2]);float tx = transformCur[3];float ty = transformCur[4];float tz = transformCur[5];float b1 = -crz*sry - cry*srx*srz; float b2 = cry*crz*srx - sry*srz; float b3 = crx*cry; float b4 = tx*-b1 + ty*-b2 + tz*b3;float b5 = cry*crz - srx*sry*srz; float b6 = cry*srz + crz*srx*sry; float b7 = crx*sry; float b8 = tz*b7 - ty*b6 - tx*b5;float c5 = crx*srz;for (int i = 0; i < pointSelNum; i++) {pointOri = laserCloudOri->points[i];coeff = coeffSel->points[i];float ary = (b1*pointOri.x + b2*pointOri.y - b3*pointOri.z + b4) * coeff.x+ (b5*pointOri.x + b6*pointOri.y - b7*pointOri.z + b8) * coeff.z;float atx = -b5 * coeff.x + c5 * coeff.y + b1 * coeff.z;float atz = b7 * coeff.x - srx * coeff.y - b3 * coeff.z;float d2 = coeff.intensity;// A=[J的偏導]; B=[權重系數*(點到直線的距離)] 求解公式: AX=B// 為了讓左邊滿秩,同乘At-> At*A*X = At*BmatA.at<float>(i, 0) = ary;matA.at<float>(i, 1) = atx;matA.at<float>(i, 2) = atz;matB.at<float>(i, 0) = -0.05 * d2;}// transpose函數求得matA的轉置matAtcv::transpose(matA, matAt);matAtA = matAt * matA;matAtB = matAt * matB;// 通過QR分解的方法,求解方程AtA*X=AtB,得到Xcv::solve(matAtA, matAtB, matX, cv::DECOMP_QR);if (iterCount == 0) {cv::Mat matE(1, 3, CV_32F, cv::Scalar::all(0));cv::Mat matV(3, 3, CV_32F, cv::Scalar::all(0));cv::Mat matV2(3, 3, CV_32F, cv::Scalar::all(0));// 計算At*A的特征值和特征向量// 特征值存放在matE,特征向量matVcv::eigen(matAtA, matE, matV);matV.copyTo(matV2);// 退化的具體表現是指什么?isDegenerate = false;float eignThre[3] = {10, 10, 10};for (int i = 2; i >= 0; i--) {if (matE.at<float>(0, i) < eignThre[i]) {for (int j = 0; j < 3; j++) {matV2.at<float>(i, j) = 0;}// 存在比10小的特征值則出現退化isDegenerate = true;} else {break;}}matP = matV.inv() * matV2;}if (isDegenerate) {cv::Mat matX2(3, 1, CV_32F, cv::Scalar::all(0));matX.copyTo(matX2);matX = matP * matX2;}transformCur[1] += matX.at<float>(0, 0);transformCur[3] += matX.at<float>(1, 0);transformCur[5] += matX.at<float>(2, 0);for(int i=0; i<6; i++){if(isnan(transformCur[i]))transformCur[i]=0;}float deltaR = sqrt(pow(rad2deg(matX.at<float>(0, 0)), 2));float deltaT = sqrt(pow(matX.at<float>(1, 0) * 100, 2) +pow(matX.at<float>(2, 0) * 100, 2));if (deltaR < 0.1 && deltaT < 0.1) {return false;}return true;}

以上部分我不完全理解就不贅述了,總之經過上面的騷操作我們得到了當前幀的角度旋轉量和位移量。

8、積分總變換。

然后就算旋轉變化:

// 旋轉角的累計變化量void integrateTransformation(){float rx, ry, rz, tx, ty, tz; // AccumulateRotation作用// 將計算的兩幀之間的位姿“累加”起來,獲得相對于第一幀的旋轉矩陣// transformSum + (-transformCur) =(rx,ry,rz)AccumulateRotation(transformSum[0], transformSum[1], transformSum[2], -transformCur[0], -transformCur[1], -transformCur[2], rx, ry, rz);

其中 AccumulateRotation功能就是計算旋轉變化的:

void AccumulateRotation(float cx, float cy, float cz, float lx, float ly, float lz, float &ox, float &oy, float &oz){// 參考:https://www.cnblogs.com/ReedLW/p/9005621.html// 0--->(cx,cy,cz)--->(lx,ly,lz)// 從0時刻到(cx,cy,cz),然后在(cx,cy,cz)的基礎上又旋轉(lx,ly,lz)// 求最后總的位姿結果是什么?// R*p_cur = R_c*R_l*p_cur ==> R=R_c* R_l//// |cly*clz+sly*slx*slz clz*sly*slx-cly*slz clx*sly|// R_l=| clx*slz clx*clz -slx|// |cly*slx*slz-clz*sly cly*clz*slx+sly*slz cly*clx|// R_c=...// -srx=(ccx*scy,-scx,cly*clx)*(clx*slz,clx*clz,-slx)// ...// 然后根據R再來求(ox,oy,oz)float srx = cos(lx)*cos(cx)*sin(ly)*sin(cz) - cos(cx)*cos(cz)*sin(lx) - cos(lx)*cos(ly)*sin(cx);ox = -asin(srx);float srycrx = sin(lx)*(cos(cy)*sin(cz) - cos(cz)*sin(cx)*sin(cy)) + cos(lx)*sin(ly)*(cos(cy)*cos(cz) + sin(cx)*sin(cy)*sin(cz)) + cos(lx)*cos(ly)*cos(cx)*sin(cy);float crycrx = cos(lx)*cos(ly)*cos(cx)*cos(cy) - cos(lx)*sin(ly)*(cos(cz)*sin(cy) - cos(cy)*sin(cx)*sin(cz)) - sin(lx)*(sin(cy)*sin(cz) + cos(cy)*cos(cz)*sin(cx));oy = atan2(srycrx / cos(ox), crycrx / cos(ox));float srzcrx = sin(cx)*(cos(lz)*sin(ly) - cos(ly)*sin(lx)*sin(lz)) + cos(cx)*sin(cz)*(cos(ly)*cos(lz) + sin(lx)*sin(ly)*sin(lz)) + cos(lx)*cos(cx)*cos(cz)*sin(lz);float crzcrx = cos(lx)*cos(lz)*cos(cx)*cos(cz) - cos(cx)*sin(cz)*(cos(ly)*sin(lz) - cos(lz)*sin(lx)*sin(ly)) - sin(cx)*(sin(ly)*sin(lz) + cos(ly)*cos(lz)*sin(lx));oz = atan2(srzcrx / cos(ox), crzcrx / cos(ox));}

接著計算當前幀與初始幀的位移變化:

// 進行平移分量的更新float x1 = cos(rz) * (transformCur[3] - imuShiftFromStartX) - sin(rz) * (transformCur[4] - imuShiftFromStartY);float y1 = sin(rz) * (transformCur[3] - imuShiftFromStartX) + cos(rz) * (transformCur[4] - imuShiftFromStartY);float z1 = transformCur[5] - imuShiftFromStartZ;float x2 = x1;float y2 = cos(rx) * y1 - sin(rx) * z1;float z2 = sin(rx) * y1 + cos(rx) * z1;tx = transformSum[3] - (cos(ry) * x2 + sin(ry) * z2);ty = transformSum[4] - y2;tz = transformSum[5] - (-sin(ry) * x2 + cos(ry) * z2);

修正累計位姿變換(公式又讓我麻了,后面要是有心情在先詳細解釋這些數學原理):

// 與accumulateRotatio聯合起來更新transformSum的rotation部分的工作// 可視為transformToEnd的下部分的逆過程PluginIMURotation(rx, ry, rz, imuPitchStart, imuYawStart, imuRollStart, imuPitchLast, imuYawLast, imuRollLast, rx, ry, rz); void PluginIMURotation(float bcx, float bcy, float bcz, float blx, float bly, float blz, float alx, float aly, float alz, float &acx, float &acy, float &acz){// 參考:https://www.cnblogs.com/ReedLW/p/9005621.html// -imuStart imuEnd 0// transformSum.rot= R * R * R// YXZ ZXY k+1// bcx,bcy,bcz (rx, ry, rz)構成了 R_(k+1)^(0)// blx,bly,blz(imuPitchStart, imuYawStart, imuRollStart) 構成了 R_(YXZ)^(-imuStart)// alx,aly,alz(imuPitchLast, imuYawLast, imuRollLast)構成了 R_(ZXY)^(imuEnd)float sbcx = sin(bcx);float cbcx = cos(bcx);float sbcy = sin(bcy);float cbcy = cos(bcy);float sbcz = sin(bcz);float cbcz = cos(bcz);float sblx = sin(blx);float cblx = cos(blx);float sbly = sin(bly);float cbly = cos(bly);float sblz = sin(blz);float cblz = cos(blz);float salx = sin(alx);float calx = cos(alx);float saly = sin(aly);float caly = cos(aly);float salz = sin(alz);float calz = cos(alz);float srx = -sbcx*(salx*sblx + calx*caly*cblx*cbly + calx*cblx*saly*sbly) - cbcx*cbcz*(calx*saly*(cbly*sblz - cblz*sblx*sbly) - calx*caly*(sbly*sblz + cbly*cblz*sblx) + cblx*cblz*salx) - cbcx*sbcz*(calx*caly*(cblz*sbly - cbly*sblx*sblz) - calx*saly*(cbly*cblz + sblx*sbly*sblz) + cblx*salx*sblz);acx = -asin(srx);float srycrx = (cbcy*sbcz - cbcz*sbcx*sbcy)*(calx*saly*(cbly*sblz - cblz*sblx*sbly) - calx*caly*(sbly*sblz + cbly*cblz*sblx) + cblx*cblz*salx) - (cbcy*cbcz + sbcx*sbcy*sbcz)*(calx*caly*(cblz*sbly - cbly*sblx*sblz) - calx*saly*(cbly*cblz + sblx*sbly*sblz) + cblx*salx*sblz) + cbcx*sbcy*(salx*sblx + calx*caly*cblx*cbly + calx*cblx*saly*sbly);float crycrx = (cbcz*sbcy - cbcy*sbcx*sbcz)*(calx*caly*(cblz*sbly - cbly*sblx*sblz) - calx*saly*(cbly*cblz + sblx*sbly*sblz) + cblx*salx*sblz) - (sbcy*sbcz + cbcy*cbcz*sbcx)*(calx*saly*(cbly*sblz - cblz*sblx*sbly) - calx*caly*(sbly*sblz + cbly*cblz*sblx) + cblx*cblz*salx) + cbcx*cbcy*(salx*sblx + calx*caly*cblx*cbly + calx*cblx*saly*sbly);acy = atan2(srycrx / cos(acx), crycrx / cos(acx));float srzcrx = sbcx*(cblx*cbly*(calz*saly - caly*salx*salz) - cblx*sbly*(caly*calz + salx*saly*salz) + calx*salz*sblx) - cbcx*cbcz*((caly*calz + salx*saly*salz)*(cbly*sblz - cblz*sblx*sbly) + (calz*saly - caly*salx*salz)*(sbly*sblz + cbly*cblz*sblx) - calx*cblx*cblz*salz) + cbcx*sbcz*((caly*calz + salx*saly*salz)*(cbly*cblz + sblx*sbly*sblz) + (calz*saly - caly*salx*salz)*(cblz*sbly - cbly*sblx*sblz) + calx*cblx*salz*sblz);float crzcrx = sbcx*(cblx*sbly*(caly*salz - calz*salx*saly) - cblx*cbly*(saly*salz + caly*calz*salx) + calx*calz*sblx) + cbcx*cbcz*((saly*salz + caly*calz*salx)*(sbly*sblz + cbly*cblz*sblx) + (caly*salz - calz*salx*saly)*(cbly*sblz - cblz*sblx*sbly) + calx*calz*cblx*cblz) - cbcx*sbcz*((saly*salz + caly*calz*salx)*(cblz*sbly - cbly*sblx*sblz) + (caly*salz - calz*salx*saly)*(cbly*cblz + sblx*sbly*sblz) - calx*calz*cblx*sblz);acz = atan2(srzcrx / cos(acx), crzcrx / cos(acx));}

最終位姿變換:

transformSum[0] = rx;transformSum[1] = ry;transformSum[2] = rz;transformSum[3] = tx;transformSum[4] = ty;transformSum[5] = tz;}

9、發布里程計及上一幀點云信息

發布里程計:

void publishOdometry(){geometry_msgs::Quaternion geoQuat = tf::createQuaternionMsgFromRollPitchYaw(transformSum[2], -transformSum[0], -transformSum[1]);// rx,ry,rz轉化為四元數發布laserOdometry.header.stamp = cloudHeader.stamp;laserOdometry.pose.pose.orientation.x = -geoQuat.y;laserOdometry.pose.pose.orientation.y = -geoQuat.z;laserOdometry.pose.pose.orientation.z = geoQuat.x;laserOdometry.pose.pose.orientation.w = geoQuat.w;laserOdometry.pose.pose.position.x = transformSum[3];laserOdometry.pose.pose.position.y = transformSum[4];laserOdometry.pose.pose.position.z = transformSum[5];pubLaserOdometry.publish(laserOdometry);// laserOdometryTrans 是用于tf廣播laserOdometryTrans.stamp_ = cloudHeader.stamp;laserOdometryTrans.setRotation(tf::Quaternion(-geoQuat.y, -geoQuat.z, geoQuat.x, geoQuat.w));laserOdometryTrans.setOrigin(tf::Vector3(transformSum[3], transformSum[4], transformSum[5]));tfBroadcaster.sendTransform(laserOdometryTrans);}

發布點云:
把特征點云投影到每幀的結尾時刻:

void publishCloudsLast(){updateImuRollPitchYawStartSinCos();int cornerPointsLessSharpNum = cornerPointsLessSharp->points.size();for (int i = 0; i < cornerPointsLessSharpNum; i++) {// TransformToEnd的作用是將k+1時刻的less特征點轉移至k+1時刻的sweep的結束位置處的雷達坐標系下TransformToEnd(&cornerPointsLessSharp->points[i], &cornerPointsLessSharp->points[i]);}int surfPointsLessFlatNum = surfPointsLessFlat->points.size();for (int i = 0; i < surfPointsLessFlatNum; i++) {TransformToEnd(&surfPointsLessFlat->points[i], &surfPointsLessFlat->points[i]);}

用KD樹存儲當前幀點云:

pcl::PointCloud<PointType>::Ptr laserCloudTemp = cornerPointsLessSharp;cornerPointsLessSharp = laserCloudCornerLast;laserCloudCornerLast = laserCloudTemp;laserCloudTemp = surfPointsLessFlat;surfPointsLessFlat = laserCloudSurfLast;laserCloudSurfLast = laserCloudTemp;laserCloudCornerLastNum = laserCloudCornerLast->points.size();laserCloudSurfLastNum = laserCloudSurfLast->points.size();if (laserCloudCornerLastNum > 10 && laserCloudSurfLastNum > 100) {kdtreeCornerLast->setInputCloud(laserCloudCornerLast);kdtreeSurfLast->setInputCloud(laserCloudSurfLast);}frameCount++;

發布各類點云(發布界外點云、線特征點云、面特征點云):

if (frameCount >= skipFrameNum + 1) {frameCount = 0;// 調整坐標系,x=y,y=z,z=xadjustOutlierCloud();sensor_msgs::PointCloud2 outlierCloudLast2;pcl::toROSMsg(*outlierCloud, outlierCloudLast2);outlierCloudLast2.header.stamp = cloudHeader.stamp;outlierCloudLast2.header.frame_id = "/camera";pubOutlierCloudLast.publish(outlierCloudLast2);sensor_msgs::PointCloud2 laserCloudCornerLast2;pcl::toROSMsg(*laserCloudCornerLast, laserCloudCornerLast2);laserCloudCornerLast2.header.stamp = cloudHeader.stamp;laserCloudCornerLast2.header.frame_id = "/camera";pubLaserCloudCornerLast.publish(laserCloudCornerLast2);sensor_msgs::PointCloud2 laserCloudSurfLast2;pcl::toROSMsg(*laserCloudSurfLast, laserCloudSurfLast2);laserCloudSurfLast2.header.stamp = cloudHeader.stamp;laserCloudSurfLast2.header.frame_id = "/camera";pubLaserCloudSurfLast.publish(laserCloudSurfLast2);}}

參考:
LeGO-LOAM源碼解析5: featureAssociation(三)
坐標轉換與imu融合

總結

以上是生活随笔為你收集整理的【LeGO-LOAM论文阅读(二)--特征提取(二)】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

欧美成年人在线观看 | 99久e精品热线免费 99国产精品久久久久久久久久 | 亚洲精品国产精品国自产 | 91精品欧美| 国产一区高清在线 | 国产精品久久久久久妇 | 97视频在线观看成人 | 天天躁日日躁狠狠躁av麻豆 | 国产一区视频在线播放 | 国产传媒中文字幕 | www.天天成人国产电影 | 成人午夜电影在线播放 | 久热av在线| 久久夜色精品国产欧美一区麻豆 | 亚洲精欧美一区二区精品 | 91视频中文字幕 | 色噜噜狠狠狠狠色综合久不 | 中文字幕丝袜制服 | 成人网大片 | 国产网站在线免费观看 | 成人一区二区三区中文字幕 | 久久久久一区二区三区四区 | 亚洲成人家庭影院 | 国产精品99久久久久久久久久久久 | 日韩乱色精品一区二区 | 黄色小网站免费看 | www.狠狠插.com| 97色在线观看 | 国产原创中文在线 | 久99热 | 99在线精品视频观看 | 欧洲av不卡 | 亚洲国产精品人久久电影 | 麻豆视频www| 99久久精品视频免费 | 国产成人精品久久二区二区 | 99久久精品久久久久久清纯 | 九精品 | www.99久久.com | 天天摸夜夜操 | 国产精品久久久久久久久久久久 | 亚洲 精品在线视频 | 狠狠干狠狠色 | 在线观看视频三级 | 国产特级毛片aaaaaa高清 | 日韩二区在线观看 | 97色综合| 婷婷国产在线观看 | 一级黄色大片在线观看 | 涩涩网站在线播放 | 久久99精品久久久久久 | 97人人爽 | 精品福利国产 | 精品国产1区2区3区 国产欧美精品在线观看 | 精品亚洲一区二区三区 | 亚洲毛片在线观看. | 亚洲另类xxxx | 午夜精品福利影院 | 91色吧 | 婷婷综合五月天 | 在线观看播放av | 国产精品久久久免费 | 久久99网站 | 91香蕉视频好色先生 | 久草视频在线新免费 | 成人黄色大片在线观看 | 香蕉久久久久久av成人 | 毛片网站在线观看 | 伊人永久 | 粉嫩av一区二区三区四区在线观看 | 日韩欧美高清一区二区三区 | 久草在线资源免费 | 久久这里只有精品视频首页 | 国产精品精品久久久久久 | 久久99精品久久久久久三级 | 久久私人影院 | 国产一区福利在线 | 91亚洲国产 | 国产成人免费网站 | 日韩欧美高清 | 91久久爱热色涩涩 | 欧美a级在线 | 日韩精品免费在线视频 | 成人午夜精品福利免费 | 亚洲精品色视频 | 夜色资源站wwwcom | 99久久久成人国产精品 | 日韩国产精品久久久久久亚洲 | 青草视频在线看 | 伊人六月| 天天拍夜夜拍 | 一级黄视频 | 深夜国产福利 | 日本3级在线观看 | 日韩欧美高清在线观看 | 国产在线播放一区 | 成人av电影免费在线观看 | 久久伊人色综合 | 成人影音av| 97超碰人人澡人人 | 99av国产精品欲麻豆 | 亚洲国产中文字幕 | 黄色av播放| 五月天高清欧美mv | 五月婷婷综合在线视频 | 成人av在线一区二区 | 中文字幕视频免费观看 | 黄色小网站在线 | av在线影片 | 亚洲国产福利视频 | 欧美激情另类 | 天天操天天色天天 | 国产成人精品一区一区一区 | 亚洲精品福利在线 | 丝袜少妇在线 | 国产黄色高清 | 天堂av网站 | 久草电影免费在线观看 | 91麻豆精品国产91久久久使用方法 | 玖玖视频在线 | 欧美激情精品久久久久久免费 | 中文字幕一区二区三区在线观看 | 国产免费精彩视频 | 亚洲国产成人在线播放 | 中文字幕日韩高清 | 久久精品欧美一区二区三区麻豆 | 天天色天天操综合 | 天天操天天添 | 亚洲第一久久久 | 久久久国际精品 | 亚洲成av人影院 | 青青河边草观看完整版高清 | 手机av片 | 久久公开免费视频 | 亚洲国产日韩精品 | 9草在线| 欧美一二三区在线播放 | 久久再线视频 | 欧美综合干 | 成年人在线视频观看 | 亚洲精品一区二区久 | 精品免费国产一区二区三区四区 | 亚洲激情网站免费观看 | 91九色蝌蚪国产 | 亚洲高清av | 99热在线看| 午夜在线日韩 | 久久尤物电影视频在线观看 | av一区二区三区在线 | 亚洲黄色免费在线 | 久久久久久麻豆 | 插综合网| 五月婷婷丁香综合 | 日韩免费视频观看 | 国产欧美精品在线观看 | 天天草网站| 久久精品久久久久久久 | 国产中文字幕网 | 国产丝袜一区二区三区 | 99看视频在线观看 | 91福利在线导航 | 99久久日韩精品免费热麻豆美女 | 国产精品久久久久久99 | 色av婷婷 | 亚洲禁18久人片 | 国产一区精品在线 | 69xx视频| 久久激情网站 | 久久久午夜精品理论片中文字幕 | 中文字幕在线观看av | 色婷婷av一区 | 国产 中文 日韩 欧美 | 日韩午夜网站 | 黄色小网站在线观看 | 99精品在线看 | 日韩成人精品在线观看 | 成人av电影在线播放 | 国产精品免费久久 | 国产成人精品日本亚洲999 | 国产原厂视频在线观看 | 日日夜夜天天久久 | 国产黑丝一区二区 | 久久综合九色99 | 中日韩在线 | 天天干,天天射,天天操,天天摸 | 成人av免费在线播放 | 亚洲精品乱码久久久久 | 四川bbb搡bbb爽爽视频 | 国产香蕉视频在线播放 | 日韩欧美精选 | 国内久久精品 | www.天天射.com| 91爱看片 | 精品国产乱码一区二 | 福利电影一区二区 | 色噜噜在线观看 | 久久艹精品| 精品国产日本 | 亚洲国产中文字幕在线观看 | 激情文学综合丁香 | 五月天狠狠操 | 亚洲第一成网站 | 国产精品成久久久久三级 | 91精品日韩| 久久中文字幕导航 | 99久久精品午夜一区二区小说 | 啪嗒啪嗒免费观看完整版 | 天堂av在线中文在线 | 激情av五月婷婷 | 日韩av午夜在线观看 | 久久久久久久久国产 | av在线播放免费 | 波多野结衣在线观看一区 | 久久草视频 | 国产精品视频999 | 国产精品久久久久久久久久尿 | 日本成人免费在线观看 | 丁香网婷婷 | 欧美日韩一区二区三区视频 | 午夜精品久久 | www.色五月.com | 天天干天天射天天爽 | 免费观看福利视频 | 综合网久久 | 亚洲香蕉视频 | 手机在线永久免费观看av片 | 九九久久久久久久久激情 | 99re热精品视频 | 五月天网页| 激情五月婷婷综合 | 久久久久免费 | 就要干b| 日韩精品无码一区二区三区 | 国产精品毛片久久久久久久 | 国产破处精品 | 欧美激情精品久久久久久变态 | 日韩天天操 | 国产一区电影在线观看 | 97精品国产97久久久久久免费 | 精品久久精品久久 | 免费看国产曰批40分钟 | 欧美精品在线免费 | 五月综合激情婷婷 | 亚洲婷婷综合色高清在线 | 欧美成人aa| 伊人亚洲综合 | 免费a一级 | 天天爽天天摸 | 人人澡人人模 | 久久日本视频 | 一级片观看 | 91精品视频免费在线观看 | 91精品影视 | 国产精品美女在线观看 | www黄色 | 久久精品综合 | 亚洲欧洲精品一区二区精品久久久 | 不卡精品视频 | 国产精品久久久久久久久久免费看 | 中文十次啦 | 又污又黄网站 | www亚洲视频 | 亚洲自拍偷拍色图 | 久久一区二区三区国产精品 | 在线国产欧美 | 三级毛片视频 | 91av手机在线 | 免费在线观看成人小视频 | 日韩二区三区在线 | 国产精品成 | 中文字幕一区二区在线播放 | 色视频网址 | 国产不卡一二三区 | 国产精品1区2区3区在线观看 | 91传媒免费在线观看 | 国产不卡在线观看 | 精品久久福利 | 免费裸体视频网 | 日韩欧美xxx | 亚洲欧美国产精品久久久久 | 黄色av成人在线观看 | 久久视频这里有久久精品视频11 | 伊人伊成久久人综合网站 | 99视频免费看 | 欧美精品久久久久久久久久 | 色综合综合 | 欧美一二三专区 | 国产乱对白刺激视频在线观看女王 | 看片一区二区三区 | 色综合天天天天做夜夜夜夜做 | 最新av中文字幕 | 91精品网站在线观看 | 激情综合五月 | 波多野结衣视频一区 | 二区视频在线观看 | 18岁免费看片 | 五月天综合色激情 | 亚洲欧美视频 | 国产乱对白刺激视频在线观看女王 | 超碰公开在线观看 | 欧美激情第一页xxx 午夜性福利 | 欧美视频在线观看免费网址 | 亚洲激情在线观看 | 亚洲欧美日韩精品久久奇米一区 | 精品国产观看 | 婷婷丁香六月天 | 成年人在线播放视频 | 亚洲欧美国产精品18p | 成人毛片在线观看视频 | 91在线麻豆 | a在线免费观看视频 | 久久久激情网 | 久久99精品久久久久久秒播蜜臀 | 国产一二三区在线观看 | 午夜久久影视 | 高潮久久久 | 久久综合电影 | 麻豆视频在线免费观看 | 日日综合| 日韩国产欧美在线播放 | 最新日韩中文字幕 | 免费看黄在线观看 | 成片视频免费观看 | 999久久久免费视频 午夜国产在线观看 | 中文字幕日韩国产 | 91人人视频在线观看 | 在线免费日韩 | 国产日本在线播放 | 夜夜躁天天躁很躁波 | 成人一区二区在线 | 超碰免费在线公开 | 国产精品大尺度 | 亚洲天堂网在线观看视频 | 99热这里有 | 在线观看自拍 | 在线看黄色av | 久久久久久久久久久免费 | 99国产精品久久久久老师 | 天天干.com| 国产福利在线免费 | 精品av网站| 天天爽天天碰狠狠添 | 伊人伊成久久人综合网站 | 国产成人精品999 | 插综合网 | 国产成人精品一区二区在线 | 国产精品成人免费一区久久羞羞 | 欧美资源 | 国产精品成人av在线 | 69久久久久久久 | 99免费在线观看 | 天天爽夜夜爽人人爽曰av | 操操综合| 国产精品久久久毛片 | 亚洲欧洲国产视频 | 免费看一级片 | 国产精品美女免费 | 日日操日日插 | 麻豆一区在线观看 | 日日夜夜精品视频天天综合网 | 日本一区二区免费在线观看 | 久久久亚洲成人 | 亚州人成在线播放 | 免费人成网 | 久久久69| 日韩精品一区二区三区三炮视频 | 女人18毛片a级毛片一区二区 | 亚洲国产精品va在线看黑人 | 国产成人一区二区三区在线观看 | 日韩午夜大片 | 日本中文字幕电影在线免费观看 | 97精品久久人人爽人人爽 | 婷婷国产在线 | 婷婷开心久久网 | 91成人免费看 | 欧美日韩色婷婷 | 久久午夜电影网 | www.狠狠操 | 在线高清av | 成人av在线一区二区 | 日本黄色免费网站 | a黄色片 | 色永久免费视频 | 国产精品日韩欧美 | 久草在线这里只有精品 | 国产短视频在线播放 | 日韩精品在线视频 | 九九综合九九 | 欧美久久久 | 国产亚洲片 | 99精品国自产在线 | 欧美日韩一区二区三区免费视频 | 国产精品久久久久久久久大全 | 久草在线资源视频 | 99国产精品免费网站 | 日韩电影在线视频 | 欧美日韩裸体免费视频 | 91久久偷偷做嫩草影院 | 国产麻豆成人传媒免费观看 | 人人插人人玩 | 伊色综合久久之综合久久 | 91在线视频一区 | 激情综合狠狠 | 精品国产三级 | 中文字幕在线专区 | 久久国产午夜精品理论片最新版本 | 国产午夜免费视频 | 丁香九月婷婷综合 | 免费在线观看一区二区三区 | 日韩中文字幕视频在线 | 一区二区视频在线免费观看 | www.在线观看视频 | 欧美日韩国产一二三区 | 国产成人a v电影 | 免费在线观看av电影 | 天天操天天干天天爽 | 二区在线播放 | 免费日韩一区二区 | 伊人影院在线观看 | 亚洲精品黄色在线观看 | 日操干| 欧美日韩国产精品一区 | 欧美一级性生活片 | 在线观看日韩精品视频 | 久久久久久网址 | 五月婷婷视频在线 | 日本成人中文字幕在线观看 | av福利网址导航大全 | www.夜夜操.com | 久久久黄视频 | 婷婷去俺也去六月色 | 正在播放 国产精品 | 国语对白少妇爽91 | 丁香午夜婷婷 | 精品国产一区二区三区久久久蜜月 | 五月激情姐姐 | 久草在线视频资源 | 国产97av| 麻豆精品在线视频 | 亚洲四虎影院 | 黄色1级毛片| 中文字幕激情 | 免费看片色 | av片一区二区 | 黄色网址国产 | 成年人免费av网站 | 婷婷在线五月 | 999电影免费在线观看 | 91原创在线观看 | 99亚洲精品视频 | 在线电影 你懂得 | 色婷婷综合在线 | 天天人人| 三级黄免费看 | 人人干干人人 | 国产传媒一区在线 | 国产一级片一区二区三区 | 69视频在线播放 | 丁香六月激情 | 国产中文字幕免费 | 在线午夜电影神马影院 | 综合网中文字幕 | 久久99久久99精品免观看粉嫩 | 国产成人av电影 | 91成人精品国产刺激国语对白 | 中文字幕在线播放日韩 | 中文字幕在线观看不卡 | 最近中文字幕免费 | 国产精品一区二区三区免费视频 | va视频在线| 狂野欧美激情性xxxx | 久久精选视频 | 中文字幕五区 | 日韩精品久久久久久久电影99爱 | 久久精品直播 | 九九欧美 | 婷婷激情站 | 日本二区三区在线 | 射射色| 欧美色图狠狠干 | av综合网址 | 九九免费观看全部免费视频 | 国产剧情在线一区 | 色视频国产直接看 | 国产一区二区久久精品 | av丝袜制服 | 丁香久久久 | 国产精品久久久久免费 | 婷婷色婷婷 | 最新av电影网站 | 91av影视| 亚洲国产成人高清精品 | 日韩激情在线视频 | 日韩亚洲欧美中文字幕 | 精品久久久精品 | 色88久久| 国产精品原创av片国产免费 | 在线中文字幕av观看 | 美女黄频视频大全 | 深爱婷婷 | 中文字幕刺激在线 | 日本久久久久久久久久久 | 伊人影院在线观看 | 精品久久久久久久久亚洲 | 日韩二区三区在线观看 | 久久乱码卡一卡2卡三卡四 五月婷婷久 | 久久久国产视频 | 国产美女黄网站免费 | 91亚洲狠狠婷婷综合久久久 | 日本公妇在线观看 | 亚洲国产高清在线 | 六月丁香激情综合 | 亚洲2019精品| 天天干天天干天天干天天干天天干天天干 | 美女网站黄免费 | 中文字幕亚洲欧美日韩2019 | 美国三级黄色大片 | 欧美色图88 | 五月婷婷丁香网 | 国产日本在线 | 在线看一区 | 五月天婷婷视频 | 国产一线二线三线性视频 | 色综合色综合色综合 | 日韩av电影国产 | 国产精品免费久久 | 韩国av电影网 | 中文字幕色婷婷在线视频 | 午夜精品一区二区三区免费视频 | 国内精品久久久久久久97牛牛 | 欧美成亚洲 | 久久99精品一区二区三区三区 | 伊人成人久久 | 久久99国产精品 | 久久艹人人 | 亚洲成人黄色在线观看 | 在线观看一区二区视频 | 国产精品国产三级国产不产一地 | 91麻豆精品国产91久久久久久 | 国产精品日韩欧美一区二区 | 99av在线视频 | 亚洲视频免费在线看 | 亚洲午夜大片 | 国产精品免费一区二区 | 国产精品九九九九九 | 色婷五月天| 国产成人免费观看久久久 | 欧美精品久久人人躁人人爽 | 成人黄色片在线播放 | 热久久国产 | 婷婷丁香九月 | 福利在线看片 | 久久久久久久久艹 | 精品在线观看一区二区 | 国产黄色在线观看 | 444av| 激情五月婷婷网 | www..com黄色片| 成年人免费在线观看网站 | 日韩一二区在线 | 久久久综合香蕉尹人综合网 | 人人爽人人爽人人片 | 91网页版在线观看 | 在线成人免费av | 欧美成人性网 | 激情五月婷婷 | 国产成人一区二区三区免费看 | 黄色大片免费网站 | 午夜私人影院 | 成人av在线网址 | 成人免费观看网址 | 国产高清视频免费观看 | 天堂视频一区 | 午夜在线免费观看视频 | 香蕉网在线| sesese图片 | japanesexxx乱女另类 | 亚洲欧美日韩一区二区三区在线观看 | 黄色一区三区 | 奇米先锋 | 精品久久久久久久久亚洲 | 奇米四色影狠狠爱7777 | 日韩免费在线观看视频 | 国产亚洲小视频 | 狠狠干.com | 成人91视频 | 欧美日韩国产一区二区三区 | 日日操日日插 | 丁香六月在线观看 | www.亚洲| 国产精品自产拍在线观看网站 | 久久99热这里只有精品国产 | 国产精品黄色在线观看 | 69久久夜色精品国产69 | 久99热| 国产小视频福利在线 | 中文字幕视频在线播放 | 国产精品视频区 | 午夜国产在线观看 | 日本aaaa级毛片在线看 | 天天干天天插伊人网 | 国产成人一二片 | 成人久久18免费网站麻豆 | 激情五月亚洲 | 亚洲一区网站 | 伊人婷婷| 国产美女视频网站 | 极品国产91在线网站 | 91传媒视频在线观看 | 精品国产1区2区 | 五月婷婷精品 | 久草在线综合 | 午夜久久成人 | 亚洲国产合集 | 五月天久久狠狠 | 国产日韩亚洲 | 精品国产一二三四区 | 激情婷婷综合网 | 中文国产字幕 | av国产在线观看 | 激情网色 | 日韩av中文在线观看 | 亚洲激情 在线 | 偷拍精品一区二区三区 | 中文字幕三区 | 欧美一级免费片 | 日日夜夜精品免费 | 国产小视频在线观看免费 | 欧美大片在线观看一区 | 狠狠躁日日躁狂躁夜夜躁av | 成人午夜在线电影 | 99热精品国产 | 久久综合给合久久狠狠色 | 国产一区二区三区高清播放 | 亚洲精品乱码久久久久久按摩 | 欧美最新另类人妖 | 日韩视频一二三区 | 97精品国产97久久久久久免费 | 国内视频一区二区 | 欧美日韩中文国产一区发布 | 日韩精品久久一区二区 | 黄色aa久久 | 麻豆传媒电影在线观看 | 亚洲精品欧美精品 | 日韩区欧美久久久无人区 | 四虎精品成人免费网站 | 视频在线观看入口黄最新永久免费国产 | 久久免费在线观看视频 | 激情五月在线视频 | 四虎精品成人免费网站 | 国产午夜精品免费一区二区三区视频 | 欧美精彩视频 | 国产精品粉嫩 | 国产一级一级国产 | www.人人草 | 国产精品久久久久永久免费看 | 色姑娘综合网 | www五月婷婷 | 色94色欧美 | 日韩免费电影一区二区 | www.久久久 | 国产精品毛片一区视频播 | 五月婷婷中文网 | 91男人影院 | 色综合天天视频在线观看 | 午夜精品电影 | 亚洲精品视频免费在线观看 | www.福利视频 | 成年人看片 | 国产欧美综合视频 | 欧美专区国产专区 | 亚洲成人精品国产 | 日本性动态图 | 丁香久久激情 | 日韩av片无码一区二区不卡电影 | 日韩色高清 | 日日操天天射 | 精品91| 一本一道久久a久久精品蜜桃 | 99久久精品国 | 18国产精品白浆在线观看免费 | 毛片1000部免费看 | 久久成人一区 | 日本最新高清不卡中文字幕 | 日韩在线国产 | 日韩免费观看一区二区 | 成人黄色国产 | 2018亚洲男人天堂 | 欧美激情综合五月色丁香 | 99久久99热这里只有精品 | 精品一区二区三区久久 | 成人午夜影院在线观看 | 麻豆视频在线免费看 | 久久精品国产免费看久久精品 | 天天干天天拍 | 国产亚洲精品久久久久久电影 | 久久爱资源网 | 精品国产精品一区二区夜夜嗨 | 911国产精品| 最近最新mv字幕免费观看 | 天堂av网址 | 蜜桃av久久久亚洲精品 | 香蕉网在线播放 | 亚洲电影自拍 | 亚洲在线看 | se婷婷 | 亚洲第一区在线播放 | av一级久久 | 黄色a大片 | 欧美激情第八页 | 久久精品91久久久久久再现 | 五月天婷亚洲天综合网鲁鲁鲁 | 国产亚洲精品美女 | 国产欧美最新羞羞视频在线观看 | 亚洲va欧美va人人爽春色影视 | 久久久久国产一区二区 | 亚洲爱视频 | 狠狠gao| 亚洲精品在线视频网站 | wwwav视频| 天堂av网站 | 成年人电影免费在线观看 | 中文在线字幕免费观看 | 午夜久久久久久久久 | 欧美在线1 | 久久99精品久久只有精品 | 国产亚洲精品久 | 日韩免费不卡av | 99精品观看 | 亚洲激情免费 | 天天射天天舔天天干 | 亚洲精品久久久久中文字幕二区 | 久久国产精品久久久久 | 久久精品国产99国产 | av一级二级 | 91毛片视频| 91成人精品视频 | 91丨porny丨九色 | 日韩啪啪小视频 | 在线成人看片 | 视频一区在线播放 | 国产黄色片在线免费观看 | 国产一级片一区二区三区 | 亚洲欧美婷婷六月色综合 | 91亚洲精品久久久中文字幕 | 狠狠网| 91九色免费视频 | 久久99久久99精品免视看婷婷 | 玖玖视频精品 | av九九九 | 亚洲精品乱码久久久久久蜜桃动漫 | 天天艹天天操 | 久久艹艹| 91成人精品在线 | www.xxx.性狂虐| 久久久久国产精品一区二区 | 成人av电影网址 | 91精品久久久久久久久久入口 | 国产免费美女 | 欧美午夜激情网 | 色婷婷激情 | 女人18精品一区二区三区 | 欧美日韩国产精品一区 | 日韩免费视频在线观看 | 久精品一区 | 国产精品网红直播 | 国内精品久久久久久久久 | 最新一区二区三区 | 韩日精品在线观看 | 欧美淫视频 | 欧美一区二区三区免费看 | 国产精品大全 | 色综合久久久久久久 | 日日夜夜狠狠干 | 免费一级片在线观看 | 亚洲国产日韩在线 | 干干日日 | 永久免费精品视频 | 三级小视频在线观看 | 欧美日韩在线观看一区二区 | 在线视频日韩精品 | 久久久久女教师免费一区 | 欧美黑吊大战白妞欧美 | 久久久久国产精品免费免费搜索 | 国产免费小视频 | 中文字幕观看av | 性色av免费在线观看 | a成人在线 | 午夜视频在线网站 | 国产一级黄大片 | 人人狠狠综合久久亚洲婷 | 亚洲精品在线国产 | 日日操天天操夜夜操 | 国产成在线观看免费视频 | 国产精品日韩久久久久 | 成年美女黄网站色大片免费看 | 中文字幕123区 | 日韩av不卡在线 | 色婷婷激情电影 | 亚洲国产中文字幕 | 午夜精品福利一区二区三区蜜桃 | 五月婷婷丁香 | 日本动漫做毛片一区二区 | 操高跟美女 | 欧美另类z0zx | av千婊在线免费观看 | 国产精品地址 | 日日爱av | 91禁看片 | 日韩区欠美精品av视频 | 亚洲视频一区二区三区在线观看 | 99久久99久国产黄毛片 | 日韩在线观看网站 | 国产专区视频在线观看 | 久99久精品视频免费观看 | 日韩成人免费在线电影 | 精品久久久久久久久中文字幕 | 欧美日韩三级 | 免费涩涩网站 | 欧美a级在线播放 | 97超级碰碰碰视频在线观看 | 麻豆你懂的| 午夜视频在线观看一区二区三区 | 韩国三级av在线 | 又污又黄的网站 | 91在线视频观看 | 亚洲欧美国产视频 | 成人超碰97 | 国产在线欧美在线 | 黄色毛片视频免费 | 性色av一区二区三区在线观看 | 国产麻豆精品久久 | 天天综合视频在线观看 | 天天爱天天干天天爽 | 日韩国产在线观看 | 色综合久久久久网 | 欧美另类色图 | 亚洲欧美视频在线 | 日韩 在线| 久久精品欧美日韩精品 | 亚洲三级网站 | 中文字幕在线高清 | 成人亚洲网 | 久草视频99 | 啪啪av在线| 超碰在线观看97 | 中文字幕在线影院 | 久久艹欧美 | 日韩在线观看一区二区 | 国产高清视频在线 | 国产少妇在线观看 | 成人综合婷婷国产精品久久免费 | 中文字幕 国产精品 | 国产原创在线观看 | 亚洲视频播放 | 国产一线在线 | 超碰97人人干 | 欧美色黄 | 久久久精品成人 | 韩国一区二区三区视频 | 亚洲黄色片在线 | 激情久久网 | 中文字幕免费高清在线观看 | 玖玖视频精品 | 日韩在线首页 | www.国产在线视频 | 91免费看片黄 | 国产资源av| 国产视频一级 | 69久久99精品久久久久婷婷 | 免费a v网站 | 亚洲日韩中文字幕在线播放 | 九九热精品在线 | 成人免费中文字幕 | 婷婷午夜| 狠狠操综合 | 国产免费久久av | 色综合天天爱 | 三级av免费看 | 二区视频在线观看 | 91精品国产91热久久久做人人 | 中文字幕在线视频一区二区 | 国产无遮挡又黄又爽在线观看 | 亚洲一区日韩在线 | 国产视频2区 | 国产夫妻性生活自拍 | 国产在线视频资源 | 波多野结衣一区二区 | 国产精品成人国产乱一区 | 日韩城人在线 | 韩日电影在线观看 | 久久精品亚洲 | 国产夫妻性生活自拍 | 特级毛片网 | 欧美国产日韩一区二区三区 | 二区三区精品 | 欧美老人xxxx18 | 蜜桃视频在线观看一区 | 成人免费精品 | 成人在线免费观看网站 | 二区在线播放 | 中文字幕在线播放日韩 | 欧美一二三视频 | 六月婷婷网 | 91成版人在线观看入口 | 午夜国产影院 | 夜夜躁日日躁狠狠久久88av | 九九综合九九综合 | 女人久久久久 | 久草久草视频 | 日韩精品一区二区三区免费视频观看 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 中文字幕超清在线免费 | 欧美日韩国产在线一区 | 碰超人人| 视频国产区 | 香蕉视频网址 | 欧美精品在线视频观看 | 亚洲欧美日韩精品久久奇米一区 | 成人黄色小说视频 | 色婷婷亚洲婷婷 | 亚洲精品视频在线观看免费 | 黄色成年片 | 精品久久久久久久久中文字幕 | 最新色站 | 婷婷中文字幕在线观看 | 午夜在线看片 | 福利电影一区二区 | 国产精品女人久久久久久 | 亚洲最快最全在线视频 | 黄色一级性片 | 国产h片在线观看 | 久久精品1区 | 久久96国产精品久久99软件 | 亚洲视频中文 | 九九九九九国产 | 天堂网一区二区 | 精品国产一二区 | 一区二区三区中文字幕在线 | 成人日批视频 | 在线观看免费视频你懂的 | 午夜成人免费电影 | 精品成人网 | 97av影院| 99热这里只有精品8 久久综合毛片 | 欧美一级片免费在线观看 | 黄色不卡av | 97人人爽人人 | 精品v亚洲v欧美v高清v | 久久少妇免费视频 | 天天干天天射天天爽 | 亚洲欧美日韩国产一区二区三区 | 日韩精品不卡在线 | 中日韩欧美精彩视频 | 成人影视免费看 | 国产精品久久久久永久免费 | 日本h在线播放 | 91精品网站在线观看 | 国产精品大尺度 | 久久香蕉国产 | 午夜骚影 | 亚洲欧洲精品久久 | 91九色综合 | 美女视频黄是免费的 | 国产成人免费网站 | 国产精品一区在线播放 | 嫩草av在线 | 国产精品一级视频 | 日本黄色a级大片 | 欧美日韩视频一区二区三区 | 国产不卡在线观看 | 久久久久久影视 | 日韩美女黄色片 | 中文字幕精品www乱入免费视频 | 国产96在线 | 综合色站导航 | 久久久久久久久久久综合 | 亚洲一区免费在线 | 四虎成人免费影院 | 91精品国产综合久久久久久久 | 天天操夜夜操夜夜操 | 国产精品一区二区av麻豆 | 三级av中文字幕 | 五月天天在线 | 色偷偷88888欧美精品久久 | 成人av在线资源 | 日韩一区二区久久 | www.玖玖玖 | 国产成人av电影在线观看 | 免费在线观看91 | 国产伦精品一区二区三区免费 | 欧美色图亚洲图片 | 日韩精品一区二区三区外面 | 久久精品精品电影网 | 在线观看一区二区精品 | 欧美一区二区在线免费观看 | 国产黄色片在线 | 国产精品久久久久久影院 |