360视频:正八面体投影OHP

CMP投影是将球体投影到正方体上,但是透视投影过程不改变立体角的大小,即对应于球面上等立体角的两点,投影到立方体上后会出现中心区域密度高而边缘区域密度低的现象,导致投影均匀性较差。当使用的投影体和球体越接近时投影的均匀性越好,正八面体投影(Octahedron projection format,OHP)投影的均匀性比CMP​​​​​​​要好,计算复杂度也相应变高。

OHP投影模型有8个面(记为F0, F1, F2, F3, F4, F5, F6,F7),每个面都是正三角形,有6个角(记为V0,V1,V2,V3,V4,V5),如图1。

360视频:正八面体投影OHP

图1 OHP模型面和角的定义

OHP有紧凑型和非紧凑型两种投影方式,两种方式的6个角的(X,Y,Z)坐标定义如表1,

表1 OHP角的XYZ坐标定义

360视频:正八面体投影OHP

表2 OHP中用角定义面

360视频:正八面体投影OHP

表2是用6个角对8个面进行定义。

Frame Packing

OHP投影展开成2D平面有两种方式:紧凑型和非紧凑型。

360视频:正八面体投影OHP

图2 OHP紧凑型和非紧凑型格式

图2是OHP的两种投影格式,展开正2D平面如图3所示,图3(a)是非紧凑型的展开方式,2D平面上存在一些无效填充内容。图3(b)(c)的紧凑型的展开方式,其中图3(b)为了将8个三角形放到一个矩形平面上,面2和3被垂直分割为面2-1、3-1和面2-2、3-2。非紧凑型投影会将球体赤道上的内容投影到三角形的边上,紧凑型投影将八面体旋转90度,赤道上的内容都会投影到三角形的面上[1]。

360视频:正八面体投影OHP

图3 OHP frame packing

投影变换

在介绍OHP的2D和3D间的投影变换之前先进行一些符号定义,图4是包裹球体的八面体的一个面的侧视图,这个面被一个矩形包围,矩形左上角为R,其坐标为(X_R,Y_R,Z_R),向量定义为360视频:正八面体投影OHP 。

360视频:正八面体投影OHP

图4 八面体的1个面

三角形的三个定点定义为 360视频:正八面体投影OHP ,则 360视频:正八面体投影OHP 可由公式(1)生成,

360视频:正八面体投影OHP

 定义面上两个正交的基向量,

360视频:正八面体投影OHP

 则该面的法向量为,

360视频:正八面体投影OHP

2D到3D的坐标映射为,

1、首先根据(m,n)求得(u,v),

  

360视频:正八面体投影OHP

2、由(u,v)可求得(X,Y,Z),

  

360视频:正八面体投影OHP

其中下标X,Y,Z表示对应向量的对应分量。

3D到2D的坐标映射为,

1、对于球面上的P点首先根据公式(10)求其所在的面的索引

  

360视频:正八面体投影OHP

2、P点在面f上的投影点Q计算如下,其中  是面f的法向量,

  

360视频:正八面体投影OHP

3、坐标(u,v)可由面f的基向量求得,

  

360视频:正八面体投影OHP

4、最终(m,n)按下式求得,

  

360视频:正八面体投影OHP

Void TOctahedron::map2DTo3D(SPos& IPosIn, SPos *pSPosOut)
{ 
  pSPosOut->faceIdx = IPosIn.faceIdx;
  POSType u, v;
  POSType pu, pv; //positin in the plane of unit sphere;
  u = IPosIn.x;
  v = IPosIn.y;
  u += (POSType)(0.5);
  v += (POSType)(0.5);
  pu = (POSType)((2.0*u)/m_sVideoInfo.iFaceWidth);
  pv = (POSType)((ssqrt(3.0f)*v)/m_sVideoInfo.iFaceHeight);
  pSPosOut->x = m_meshFaces[pSPosOut->faceIdx].origin[0] + pu*m_meshFaces[pSPosOut->faceIdx].baseVec[0][0] + pv*m_meshFaces[pSPosOut->faceIdx].baseVec[1][0];
  pSPosOut->y = m_meshFaces[pSPosOut->faceIdx].origin[1] + pu*m_meshFaces[pSPosOut->faceIdx].baseVec[0][1] + pv*m_meshFaces[pSPosOut->faceIdx].baseVec[1][1];
  pSPosOut->z = m_meshFaces[pSPosOut->faceIdx].origin[2] + pu*m_meshFaces[pSPosOut->faceIdx].baseVec[0][2] + pv*m_meshFaces[pSPosOut->faceIdx].baseVec[1][2]; 
}

Void TOctahedron::map3DTo2D(SPos *pSPosIn, SPos *pSPosOut)
{
  Int iFaceIdx=0;
  POSType dMax = std::numeric_limits<POSType>::min();
  POSType pu, pv;
  //determine face idx;
  for(Int f=0; f<m_sVideoInfo.iNumFaces; f++)
  {
    POSType d = (pSPosIn->x*m_meshFaces[f].normVec[0] + pSPosIn->y*m_meshFaces[f].normVec[1] + pSPosIn->z*m_meshFaces[f].normVec[2]);
    if(d >dMax)
    {
      iFaceIdx = f;
      dMax = d;
    }
  }
  TriMesh& tmFace = m_meshFaces[iFaceIdx];
  POSType d = tmFace.origin[0] *tmFace.normVec[0] + tmFace.origin[1]*tmFace.normVec[1] + tmFace.origin[2]*tmFace.normVec[2];
  POSType projected[3];
  projected[0] = pSPosIn->x * d/dMax - tmFace.origin[0];
  projected[1] = pSPosIn->y * d/dMax - tmFace.origin[1];
  projected[2] = pSPosIn->z * d/dMax - tmFace.origin[2];
  pu = projected[0]*tmFace.baseVec[0][0] + projected[1]*tmFace.baseVec[0][1] + projected[2]*tmFace.baseVec[0][2];
  pv = projected[0]*tmFace.baseVec[1][0] + projected[1]*tmFace.baseVec[1][1] + projected[2]*tmFace.baseVec[1][2];
  //convert pu, pv to [0, width], [0, height];
  pSPosOut->faceIdx = iFaceIdx;
  pSPosOut->z = 0;
  pSPosOut->x = (POSType)(pu*(m_sVideoInfo.iFaceWidth>>1) + (-0.5));
  pSPosOut->y = (POSType)(pv*(m_sVideoInfo.iFaceHeight)/ssqrt(3.0f)+ (-0.5));
}

参考

[1] H.-C. Lin, C.-C. Huang, C.-Y. Li, Y.-H. Lee, J.-L.Lin, S.-K. Chang, “AHG8: An improvement on the compact OHP layout,” Joint VideoExploration Team of ITU-T SG16 WP3 and ISO/IEC JTC1/SC29/WG11, JVET-E0056, Jan. 2017, Geneva, Switzerland.

感兴趣的请关注微信公众号Video Coding

360视频:正八面体投影OHP

上一篇:html:canvas画布绘图简单入门-3


下一篇:多啦咪图虫_浏览器插件图片批量下载工具扩展插件图片下载