[ARKit]8-對裸眼3D效果一次不太成功的嘗試

蘋果API搬運工發表於2018-04-29

說明

ARKit系列文章目錄

The Parallax View

The Parallax View是個國外開發者開發的好玩的軟體,它利用iPhoneX實現了裸眼3D的效果.

[ARKit]8-對裸眼3D效果一次不太成功的嘗試
其實它是利用了iPhone X的ARKit面部追蹤介面和TrueDepth感測器。
[ARKit]8-對裸眼3D效果一次不太成功的嘗試
通過追蹤使用者的頭部運動,確定眼睛在三維空間中的確切位置。
[ARKit]8-對裸眼3D效果一次不太成功的嘗試
然後生成實時響應使用者位置的影像,從而為使用者帶來一種3D影像的錯覺。
[ARKit]8-對裸眼3D效果一次不太成功的嘗試

原理特點

通過使用ARKit和iPhone X進行3D頭部追蹤來獲得深度幻象。

為獲得最佳效果,應該只開啟一隻眼睛(該應用允許選擇要追蹤的眼睛,或者可以嘗試自動選擇眼睛)

通過跟蹤使用者頭部方向和位置,可以找到3D中的眼睛位置。

應用可以在該顯示器上呈現從該位置看到的正確檢視。

為了呈現該檢視,使用離軸投影(非對稱相機平截頭體)。

這給人一種錯覺,即物體出現在螢幕的前面和後面。

模仿

受此啟發,我嘗試在非iPhoneX裝置上用人臉識別框架來實現低精度的裸眼3D效果. 原理是:

  • 利用人臉識別,檢測人臉位置;
  • 將人臉的二維位置轉換到3維空間中(z軸固定,xy按比例轉換);
  • 將轉換後的3D座標賦值給攝像機;

原本打算,用識別出人臉的大小,做為依據來判斷攝像機在z軸上的位置,但測試中發現,人臉識別出的大小變化很大,無規律可轉換.

建立模型

[ARKit]8-對裸眼3D效果一次不太成功的嘗試
自己用SceneKit的編輯器搭建了一個場景,裡面有多根高度不同的柱子.

人臉識別

原來以為蘋果的新框架Vision會更好,結果在我的iPhone SE上非常卡,而且Vision框架在識別人臉時對方向有要求,需要指定方向.所有最後還是使用了AVFoundation中的metadataObjectTypes來識別.

if session.canAddOutput(metaDataOutput) {
       session.addOutput(metaDataOutput)
}
 //7.AVFoundation框架識別型別
metaDataOutput.metadataObjectTypes = [.face]
複製程式碼

在代理方法中處理識別到的人臉:

//AV框架人臉識別
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
    
    for obj in metadataObjects {
        if obj.type == .face {
            print("face---\(obj.bounds)")
            // 座標轉換
            let oldRect = obj.bounds;
            let w = oldRect.size.height * self.previewView.bounds.size.width;
            let h = oldRect.size.width * self.previewView.bounds.size.height;
            let x = oldRect.origin.y * self.previewView.bounds.size.width;
            let y = oldRect.origin.x * self.previewView.bounds.size.height;
            
            // 新增矩形
            rectLayer.frame = CGRect(x: x, y: y, width: w, height: h)
            rectLayer.isHidden = false
            
            //湊出合理的資料
            let cameraX = (oldRect.origin.y - 0.3) * 2
            let cameraY = (0.4 - oldRect.origin.x) * 2
            // 移動攝像機
            self.cameraNode.position = SCNVector3(cameraX, cameraY, 20)
            
        }else {
            rectLayer.isHidden = true
        }
    }
}

複製程式碼

效果初步有了:

[ARKit]8-對裸眼3D效果一次不太成功的嘗試

但是我們還應該看到,我們的3D效果是通過直接移動攝像機的位置來實現,攝像機的視野範圍並沒有改變,所以看上去像是透過窗戶看後面的景物,而不是像The Parallax View那樣,3D物體像是與手機螢幕綁在一起.

最主要原因是:The Parallax View使用了離軸投影(非對稱相機平截頭體)處理攝像機看到的物體範圍,如下圖,不論如何移動,FOV(Field Of View)都始終對齊了底座的四個角:

[ARKit]8-對裸眼3D效果一次不太成功的嘗試

投影變換

在SceneKit中,是可以給camera設定自定義的投影變換矩陣的 self.cameraNode.camera?.projectionTransform

蘋果也給出了說明,一旦設定該項,則對攝像機設定的 zFar,zNear, 和fieldOfView都會失效,原因是這些值無法從矩陣中得到(數學上不可逆). 另外需要注意的是:ARKit中的ARSCNView類會重寫這個投影變換,所以不要在AR應用中修改.

如果有深厚的3D數學功底,只要重寫這個投影變換矩陣,就可以得到離軸投影效果,可惜我現在不會,相關配置還需要研究,以後更新.

程式碼

程式碼地址NakedEye3D

相關文章