1. 程式人生 > >基於輪廓的三維骨架重建方法和核心程式碼

基於輪廓的三維骨架重建方法和核心程式碼

 背景(為什麼要這麼做?):

        目前獲取三維資料的方法很多,比如:雙目視覺技術,深度相機等等。

        但是存在一個問題:資料量巨大!如果要做線上檢測,那速度很可能達不到要求。

總思路:

        用二維的資料來表示三維資料(資料量從n3降到n2)

課題需求:

        本人的實驗室目前的課題是要做馬鈴薯的形狀檢測。通過二維影象誤差很大,通過傳統三維方法達不到線上檢測速度要求。

步驟:

1.推匯出二維輪廓畫素點到三維空間的座標對映關係;

2.通過影象處理獲取輪廓座標;

3.轉換到三維空間;

4.通過PCL點雲資料庫顯示合成三維影象。

核心程式碼:

        //計算x,y軸的方向餘弦
//p1表示上面點x,p2表示上面點y,p3表示下面點x,p4表示下面點y
float StaticClassify::DirectionCosineX(float angle,float p1,float p2,float p3,float p4)
{
float pp=p3-p1;
float ppp=sqrt(pow((p3-p1),2)+pow((p2-p4),2));
float Cosine;
if (angle<100)
{Cosine=-pp/ppp;

else
{Cosine=pp/ppp;
}
return Cosine;
}

    //輪廓的二維點到三維點轉換

for (i0 = 0; i0 < length0; i0++)
{
point0[i0]=*CV_GET_SEQ_ELEM(CvPoint,contours0,i0);//在當前contour下一個一個的讀取資料

point30[i0].x=(float)(point0[i0].x-x0);
point30[i0].y=(float)(point0[i0].y-y0);
point30[i0].z=(float)0;
}
for (i1 = 0; i1 < length1; i1++)
{
point1[i1]=*CV_GET_SEQ_ELEM(CvPoint,contours1,i1);
   point31[i1].x=((float)(point1[i1].x-x1))*0.92388;    //cos22.5°
   point31[i1].y=((float)(point1[i1].y-y1));
   point31[i1].z=((float)-(point1[i1].x-x1))*0.38268;   //sin22.5°
    }
for (i2 = 0; i2 < length2; i2++)
{
point2[i2]=*CV_GET_SEQ_ELEM(CvPoint,contours2,i2);


point32[i2].x=((float)(point2[i2].x-x2))*0.7071;
point32[i2].y=((float)(point2[i2].y-y2));
point32[i2].z=((float)-(point2[i2].x-x2))*0.7071;
}
for (i3 = 0; i3 < length3; i3++)
{
point3[i3]=*CV_GET_SEQ_ELEM(CvPoint,contours3,i3);

point33[i3].x=((float)(point3[i3].x-x3))*0.38268;
point33[i3].y=((float)(point3[i3].y-y3));
point33[i3].z=(float)-(point3[i3].x-x3)*0.92388;
}
for (i4 = 0; i4 < length4; i4++)
{
point4[i4]=*CV_GET_SEQ_ELEM(CvPoint,contours4,i4);

   point34[i4].x=(float)0;
   point34[i4].y=((float)(point4[i4].y-y4));
point34[i4].z=(float)-(point4[i3].x-x3);
}
for (i5 = 0; i5 < length5; i5++)
{
point5[i5]=*CV_GET_SEQ_ELEM(CvPoint,contours5,i5);

   point35[i5].x=((float)-(point5[i5].x-x5))*0.38268;
   point35[i5].y=((float)(point5[i5].y-y5));
   point35[i5].z=((float)-(point5[i5].x-x5)*0.92388);
}
for (i6 = 0; i6 < length6; i6++)
{
point6[i6]=*CV_GET_SEQ_ELEM(CvPoint,contours6,i6);

     point36[i6].x=(float)-(point6[i6].x-x6)*0.7071;
    point36[i6].y=((float)(point6[i6].y-y6));
    point36[i6].z=((float)-(point6[i6].x-x6))*0.7071;
}
for (i7 = 0; i7 < length7; i7++)
{
point7[i7]=*CV_GET_SEQ_ELEM(CvPoint,contours7,i7);

point37[i7].x=((float)-(point7[i7].x-x7))*0.92388;
    point37[i7].y=((float)(point7[i7].y-y7));
    point37[i7].z=((float)-(point7[i7].x-x7))*0.38268;
}
}

//三維點雲顯示
void StaticClassify::OnBnClickedButtonThreeDimensional()
{
pcl::PointXYZ p;
// TODO: 在此新增控制元件通知處理程式程式碼
TwoPointToThreePoint();

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud0(new pcl::PointCloud<pcl::PointXYZ>);   //Ptr是一種指標
cloud0->reserve(contours0->total);                                                //reserve開闢空間
for(int i=0;i<contours0->total;i++)
{
p.x=point30[i].x;
p.y=point30[i].y;
p.z=point30[i].z;
cloud0->push_back(p);
}

pcl::visualization::CloudViewer viewer("點雲");
viewer.runOnVisualizationThreadOnce(viewerOneOff);
viewer.showCloud(cloud0,"cloud0");

while(!viewer.wasStopped())
{
}
}