Math 如何基于深度信息找到平坦区域

Math 如何基于深度信息找到平坦区域,math,drone,depth-camera,Math,Drone,Depth Camera,我有一架可以自主飞行的无人机,我希望它能安全着陆。。 我有一个深度相机在它下面,现在我找不到一种方法来检测平坦区域,告诉无人机降落在上面。 我使用的是realsense D435i相机。这是一个从下向相机获得的深度图像样本 请问你能帮忙吗 根据 但是,如果使用线性输出或透视对深度帧进行后期处理,则我看不到有关深度帧的任何信息。你可以从图像中推断,如果物体随着距离变小,它仍然处于透视图中,我不知道,但假设是这样 您的图像是848x480,因此我假设它只是按1/1.5线性缩放,因此视野是相同的 将

我有一架可以自主飞行的无人机,我希望它能安全着陆。。 我有一个深度相机在它下面,现在我找不到一种方法来检测平坦区域,告诉无人机降落在上面。 我使用的是realsense D435i相机。这是一个从下向相机获得的深度图像样本

请问你能帮忙吗

根据

但是,如果使用线性输出或透视对深度帧进行后期处理,则我看不到有关深度帧的任何信息。你可以从图像中推断,如果物体随着距离变小,它仍然处于透视图中,我不知道,但假设是这样

您的图像是848x480,因此我假设它只是按
1/1.5
线性缩放,因此视野是相同的

  • 将深度线性化为规则网格采样点/网格

    因此,每个像素必须转换为相对于相机的3D位置。所以只需从相机焦点投射光线穿过像素,并在其距离处停止。得到的位置就是我们想要的3D位置。对每个点执行此操作将生成连接点的二维栅格(曲面网格)。但是,我们不知道深度是欧几里德还是垂直距离(
    cos
    corrected),因此我们需要尝试这两种组合,并选择一种效果更好的组合(建筑是长方体而不是金字塔…)

    从我手边得到的信息来看,这是我能从您的输入图像中得到的最好信息:

    所以我从你的图像中提取了所有像素,将x,y位置转换成球面
    经度,纬度
    角度(从深度相机视场和图像分辨率的线性插值),然后将像素强度转换成深度,并将其转换成笛卡尔坐标

    //深度->PCL
    for(y=0;yScanLine[y];//指向深度图像中第y条扫描线的指针
    b=深度fovy*((双(y)-深度y0)/双(ys-1))-0.5;//纬度
    对于(x=x3=0;x笛卡尔坐标
    p[0]=cos(a)*cos(b);//x
    p[1]=sin(a)*cos(b);//y
    p[2]=sin(b);//z
    if(int(depthcfg&_DepthImage_cos_correct_z))r/=p[0];
    pnt[y][x3+0]=r*p[1];
    pnt[y][x3+1]=r*p[2];
    pnt[y][x3+2]=r*p[0];
    }
    }
    
    其中
    pnt[][]
    是三维点的二维数组,存储为后续
    x、y、z
    和:

    pcl.depthz0=0.8;
    pcl.depthz1=1.00;
    pcl.depthcfg=_DepthImage_invert_z|_DepthImage_cos_correct_z;
    
    图像分辨率为
    xs,ys

    有关更多信息,请参阅:

  • 从相邻点计算每个点(曲面)的法线

    简单的叉积就可以了,但是重要的是要使用正确的操作数顺序,以便得到的法线指向相同的方向而不是相反的方向……否则我们以后需要使用
    abs
    of
    dot
    result来处理它

  • 在法线上绘制直方图(与有限的方向集对齐)

    直方图是变量的某个值与其概率或发生率之间的关系。例如,图像直方图告诉我们每种颜色(范围/箱)有多少像素着色。出于我们的目的,平面区域(平面)应具有相同的法线(在深度图像中,噪声太大,但我假设将深度转换为颜色的梯度函数的比例奇怪,并且非线性地强调了噪声,因为标准深度相机没有这么大的噪声)因此,平面区域的法线应该是非常频繁的,因此应该用直方图中的峰值来表示。首先,我们应该将3D法线转换为单个整数值(为了简化代码),并将可能的方向限制为仅某些固定的方向(以排除噪声并压缩输出数据大小)

    标准化法线是三维向量,坐标范围为
    ,因此我们可以将该范围转换为某个位宽的无符号整数,并将其中的3个叠加为单个整数。例如,每个坐标5位:

    normal = (nx,ny,nz)
    nx = 31.0*(nx+1.0)*0.5; // <-1,+1> -> <0,31>
    ny = 31.0*(nx+1.0)*0.5; // <-1,+1> -> <0,31>
    nz = 31.0*(nx+1.0)*0.5; // <-1,+1> -> <0,31>
    int ni =  int(nx) + int(ny)<<5 + int(nz)<<10
    
    其中,允许在
    deg
    rad
    中的法线之间存在角度差,这取决于
    cos
    实现

  • [Edit1]您的数据噪音太大,无法正常接近

    这里的图像(在平滑数据以减少噪声后)显示了各个法线方向的出现,因此蓝色出现的次数最少,红色出现的次数最多,绿色介于两者之间

    正如你所看到的,大多数情况下,像素超出范围或无效值(很难说)以及框的顶部测量正确。但是,你视图的大部分表面都有奇怪的非常大的噪声(振幅和半径…这些斑点),这是我以前在深度图像上从未见过的。我打赌是你从原始深度到深度的转换“颜色”渐变是非线性的,强调噪声(这很可能也是我很难将场景重建回3D的原因)+JPEG有损压缩伪影

    所以,除非你提供像素颜色和深度之间转换的明确等式,否则这是不可能的。因此,你需要不同的更慢的方法。我会做一个窗口“暴力”搜索:

  • 定义窗口

    所以你的无人机有一定的尺寸,所以我们需要一个规定尺寸的矩形(略大于你的无人机在地面上的投影面积,多少取决于着陆轨迹和飞行控制的稳定性和精度…)

    因此,我们需要一些大小为
    wx*wy
    的矩形,以米为单位(或者以任何单位重建场景)

  • 测试窗口的“所有”可能位置

    所以,只要从左上角开始测试我们的点云窗口是否足够fla,如果找到了解决方案,如果没有,测试位置将稍微向右移动…直到到达点云的末端。然后从左上角重新开始,但稍微向下移动。因此,对于以小于w的某个值递增的循环,这将是2个嵌套indow大小(不需要仅为像素)

  • <
    normal = (nx,ny,nz)
    nx = 31.0*(nx+1.0)*0.5; // <-1,+1> -> <0,31>
    ny = 31.0*(nx+1.0)*0.5; // <-1,+1> -> <0,31>
    nz = 31.0*(nx+1.0)*0.5; // <-1,+1> -> <0,31>
    int ni =  int(nx) + int(ny)<<5 + int(nz)<<10
    
    dot(n1,n2)/(|n1|.|n2|) >= cos(margin)