360视频:CMP和ACP投影

CMP投影

立方体投影格式(Cubemap projection format,CMP)是通过将球面内容投影在立方体模型上后将各个面展开,然后拼接为矩形的一种投影方式。

和ERP不同,CMP采用正方体进行投影,内容会投影到6个面上,如图1所示。

图1 CMP投影

6个面编号PX、PY、PZ、NX、NY、NZ,P表示沿坐标轴正方形,N表示沿坐标轴负方向。

表1 CMP face index

Face indexFace label说明
0PX正面,沿x轴正方向
1NX背面,沿x轴负方向
2PY上面,沿Y轴正方向
3NY下面,沿Y轴负方向
4PZ右面,沿Z轴正方向
5NZ左面,沿Z轴负方向
>5null

每个面都对应一个uv平面,uv平面是2x2的正方向平面(等于单位球体的直径),u和v的取值[-1,1]。

假定每个面都是AxA的正方形,则对于某个面f上的坐标(m,n),其对应(u,v)计算方式为:

由(u,v)可按表2求3D坐标(X,Y,Z),

表2 由(f,u,v)计算(X,Y,Z)

fXYZ
01.0-v-u
1-1.0-vu
2u1.0v
3u-1.0-v
4u-v1.0
5-u-v-1.0

对于3D到2D的投影变换,给定(X,Y,Z)可以按表3求得(f,u,v),

表3 由(X,Y,Z)计算(f,u,v)

条件fuv
|X|≥ |Y| and |X| ≥ |Z| and X >00−Z/|X|−Y/|X|
|X|≥ |Y| and |X| ≥ |Z| and X <01Z/|X|−Y/|X|
|Y|≥ |X| and |Y| ≥ |Z| and Y >02X/|Y|Z/|Y|
|Y|≥ |X| and |Y| ≥ |Z| and Y <03X/|Y|-Z/|Y|
|Z|≥ |X| and |Z| ≥ |X| and Z >04X/|Z|−Y/|Z|
|Z|≥ |X| and |Z| ≥ |Y| and Z <05-X/|Z|−Y/|Z|

Frame Packing  

CMP投影到6个面上,但是这6个面要拼成一个矩形2D平面才能编码。360Lib对CMP提供了2种面的拼接方式,分别为3x4和2x3形式,

图2 CMP frame packing

图2.1是原始360图像ERP投影的结果,红色虚线是经度。图2.2是图像按照CMP投影后6个面按3x4拼接的结果,其中有6个灰色的面是无效的,即表1中索引大于5的面,红色虚线是面的边界。图2.2是图像按照CMP投影后6个面按2x3拼接的结果,红色虚线是面的边界。

6个面拼接的时候还可以按照90、180、270度旋转,如图3中面1,2,3均逆时针旋转了270度。

图3 frame packing旋转

CMP是直接透视投影,均匀性仍然较差,由于透视投影过程不改变立体角的大小,这表现在对应于球面上等立体角的两点,投影到立方体上后会出现中心区域密度高而边缘区域密度低的现象。

/********************
face order:
PX: 0
NX: 1
PY: 2
NY: 3
PZ: 4
NZ: 5
********************/
Void TCubeMap::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 + (POSType)(0.5);
  v = IPosIn.y + (POSType)(0.5);
  pu = (POSType)((2.0*u)/m_sVideoInfo.iFaceWidth-1.0);
  pv = (POSType)((2.0*v)/m_sVideoInfo.iFaceHeight-1.0);
  //map 2D plane ((convergent direction) to 3D ;
  switch(IPosIn.faceIdx)
  {
  case 0:
    pSPosOut->x = 1.0;
    pSPosOut->y = -pv;
    pSPosOut->z = -pu;
    break;
  case 1:
    pSPosOut->x = -1.0;
    pSPosOut->y = -pv;
    pSPosOut->z = pu;
    break;
  case 2:
    pSPosOut->x = pu;
    pSPosOut->y = 1.0;
    pSPosOut->z = pv;
    break;
  case 3:
    pSPosOut->x = pu;
    pSPosOut->y = -1.0;
    pSPosOut->z = -pv;
    break;
  case 4:
    pSPosOut->x = pu;
    pSPosOut->y = -pv;
    pSPosOut->z = 1.0;
    break;
  case 5:
    pSPosOut->x = -pu;
    pSPosOut->y = -pv;
    pSPosOut->z = -1.0;
    break;
  default:
    assert(!"Error TCubeMap::map2DTo3D()");
    break;
  }
}

Void TCubeMap::map3DTo2D(SPos *pSPosIn, SPos *pSPosOut)
{
  POSType aX = sfabs(pSPosIn->x);
  POSType aY = sfabs(pSPosIn->y);
  POSType aZ = sfabs(pSPosIn->z);
  POSType pu, pv;
  if(aX >= aY && aX >= aZ)
  {
    if(pSPosIn->x > 0)
    {
      pSPosOut->faceIdx = 0;
      pu = -pSPosIn->z/aX;
      pv = -pSPosIn->y/aX;
    }
    else
    {
      pSPosOut->faceIdx = 1;
      pu = pSPosIn->z/aX;
      pv = -pSPosIn->y/aX;
    }
  }
  else if(aY >= aX && aY >= aZ)
  {
    if(pSPosIn->y > 0)
    {
      pSPosOut->faceIdx = 2;
      pu = pSPosIn->x/aY;
      pv = pSPosIn->z/aY;
    }
    else
    {
      pSPosOut->faceIdx = 3;
      pu = pSPosIn->x/aY;
      pv = -pSPosIn->z/aY;
    }
  }
  else
  {
    if(pSPosIn->z > 0)
    {
      pSPosOut->faceIdx = 4;
      pu = pSPosIn->x/aZ;
      pv = -pSPosIn->y/aZ;
    }
    else
    {
      pSPosOut->faceIdx = 5;
      pu = -pSPosIn->x/aZ;
      pv = -pSPosIn->y/aZ;
    }
  }
  //convert pu, pv to [0, width], [0, height];
  pSPosOut->z = 0;
  pSPosOut->x = (POSType)((pu+1.0)*(m_sVideoInfo.iFaceWidth>>1) + (-0.5));
  pSPosOut->y = (POSType)((pv+1.0)*(m_sVideoInfo.iFaceHeight>>1)+ (-0.5));
}

ACP投影

ACP(Adjustedcubemap projection format)投影是CMP的改进。

在2D转3D的计算过程中,对公式(1)(2)计算的(u,v)进行改进,

在3D转2D的计算过程中,计算得到的(u,v)再进一步处理,

将公式(3)(4)的变换用f(x)表示,公式(5)(6)的变换用g(x)表示(其中x为u或v),则f(x)和g(x)变换如下:

EAC和HEC投影

EAC(Equi-angular cubemap projection)和HEC(Hybrid equi-angular cubemap projection)和ACP类似,就是(u,v)的转换函数不同,

EAC的(u,v)计算为:

HEC和EAC类似,对于所有面的u的计算使用公式(7)(8),对于顶面和底面的v的计算使用公式(7)(8),不过对于其他4个面的v的正向和逆向变换如下:

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

### ADI、AEI CMP 的技术概念或工具解析 #### 1. ADI (Application Dependency Injection) 在软件开发中,ADI 通常指 **Application Dependency Injection** 或 **自动依赖注入**。这是一种设计模式,用于管理对象之间的依赖关系[^3]。通过依赖注入(DI),开发者可以将组件的创建使用分离,从而提高代码的可测试性可维护性。常见的依赖注入框架包括 Spring Framework(Java)、Ninject(C#) Dagger(Android/Java)。 ```java public class Service { private Repository repository; // Constructor-based Dependency Injection public Service(Repository repository) { this.repository = repository; } public void performAction() { repository.saveData(); } } ``` #### 2. AEI (Application Entity Integration) AEI 可以理解为 **Application Entity Integration**,即应用程序实体集成。它涉及在不同系统之间同步交换数据实体。例如,在企业级应用中,AEI 被用来确保客户信息、订单状态等实体在多个数据库或服务之间保持一致。这通常通过 ESB(Enterprise Service Bus)或 API 集成工具实现[^4]。 ```python # 示例:Python 中的数据实体同步 import requests def sync_entity(entity_id): source_data = get_entity_from_source(entity_id) target_url = "http://target-system/api/entity" response = requests.post(target_url, json=source_data) return response.status_code == 200 ``` #### 3. CMP (Container Managed Persistence) CMP 是 **Container Managed Persistence** 的缩写,主要用于 Java EE(现为 Jakarta EE)环境中。CMP 是一种持久化机制,允许开发者定义业务逻辑而不必担心底层数据库操作。容器会自动生成必要的 SQL 语句来处理数据的存储检索[^5]。 ```java @Entity public class Employee implements java.io.Serializable { @Id private int id; private String name; // Getters and Setters public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ``` ### 技术背景与应用场景 - **ADI** 主要应用于需要高内聚低耦合的系统架构中,尤其是在微服务模块化设计中。 - **AEI** 常见于需要跨系统数据同步的企业级应用,如 ERP、CRM 系统。 - **CMP** 则是传统 Java EE 开发中的一种持久化方式,尽管现代开发更倾向于使用 JPA(Java Persistence API)或 Hibernate。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值