CMP投影是将球体投影到正方体上,但是透视投影过程不改变立体角的大小,即对应于球面上等立体角的两点,投影到立方体上后会出现中心区域密度高而边缘区域密度低的现象,导致投影均匀性较差。当使用的投影体和球体越接近时投影的均匀性越好,正八面体投影(Octahedron projection format,OHP)投影的均匀性比CMP要好,计算复杂度也相应变高。
OHP投影模型有8个面(记为F0, F1, F2, F3, F4, F5, F6,F7),每个面都是正三角形,有6个角(记为V0,V1,V2,V3,V4,V5),如图1。
图1 OHP模型面和角的定义
OHP有紧凑型和非紧凑型两种投影方式,两种方式的6个角的(X,Y,Z)坐标定义如表1,
表1 OHP角的XYZ坐标定义
表2 OHP中用角定义面
表2是用6个角对8个面进行定义。
Frame Packing
OHP投影展开成2D平面有两种方式:紧凑型和非紧凑型。
图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]。
图3 OHP frame packing
投影变换
在介绍OHP的2D和3D间的投影变换之前先进行一些符号定义,图4是包裹球体的八面体的一个面的侧视图,这个面被一个矩形包围,矩形左上角为R,其坐标为(X_R,Y_R,Z_R),向量定义为 。
图4 八面体的1个面
三角形的三个定点定义为 ,则 可由公式(1)生成,
定义面上两个正交的基向量,
则该面的法向量为,
2D到3D的坐标映射为,
1、首先根据(m,n)求得(u,v),
2、由(u,v)可求得(X,Y,Z),
其中下标X,Y,Z表示对应向量的对应分量。
3D到2D的坐标映射为,
1、对于球面上的P点首先根据公式(10)求其所在的面的索引
2、P点在面f上的投影点Q计算如下,其中 是面f的法向量,
3、坐标(u,v)可由面f的基向量求得,
4、最终(m,n)按下式求得,
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