Darkside(https対応しました)

2022年6月5日(日) 21:56

DUAL FISHEYE 静止画ステッチソフト

 静止画 VR180 3D のステッチソフトを、自作で完成させてみた。

 DUAL FISHEYE で撮影した静止画は、jpeg 撮って出しでなければ EOS VR Utility でステッチできない。そのため、ステッチ前に jpeg 圧縮されてしまっているので最高画質は狙えないし、画質調整も行えない。
 Digital Photo Professinal でRAW現像し、場合によっては更に画質調整も行った上で、ステッチしたい。そこで役立つのが、自作ソフトだ。

 LX、LY、RX、RY は左右魚眼映像の中心座標であり、自分の DUAL FISHEYE の値が入っている。製品レンズの個体差により、ベストな値は少しずつ異なっているはずである。調査して最適値を設定するのが望ましい。
 コマンドラインから、python vrst.py d:\1234.tif out.png のような感じで実行する。 コマンドライン用なので、ファイル入出力のエラー処理などは省略。入力ファイルが無かったりしても、そのままコマンドラインでエラー吐いてくれて実用上は別に困らない。気になるなら、処理を追加してみて欲しい。

import sys
import numpy as np
import cv2
import argparse
parser = argparse.ArgumentParser(description='VR180 3D 撮影した静止画のステッチ')
parser.add_argument('infile', help='入力画像ファイル名')
parser.add_argument('outfile', help='出力画像ファイル名')
args = parser.parse_args()
dm_w = 4096
dm_h = 4096
dfish = 3684
arr_sin_dm_phi = [np.pi] * (dm_w * 2)
arr_cos_dm_phi = [np.pi] * (dm_w * 2)
xmap = np.zeros((dm_h, dm_w), np.float32)
ymap = np.zeros((dm_h, dm_w), np.float32)
try:
    # try to load map file
    xmap = np.load("xmap.npy")
    ymap = np.load("ymap.npy")
except IOError:
    # if the map files are not exist, generate new map files.
    print("Generating map files...")
    for x in range(dm_w * 2):
        dm_x = float(x)
        dm_phi = np.pi * 2.0 * dm_x / dm_w / 2.0
        arr_sin_dm_phi[x] = np.sin(dm_phi)
        arr_cos_dm_phi[x] = np.cos(dm_phi)
    for y in range(dm_h):
        dm_y = float(y)
        dm_theta = np.pi * dm_y / (dm_h-1)
        sin_dm_theta = np.sin(dm_theta)
        cos_dm_theta = np.cos(dm_theta)
        xst = int(dm_w / 2)
        xen = int(dm_w * 3 / 2)
        for x in range(xst,xen):
            dm_x = float(x)
            sin_dm_phi = arr_sin_dm_phi[x]
            cos_dm_phi = arr_cos_dm_phi[x]
            tmp2_x = sin_dm_theta * cos_dm_phi
            tmp2_y = sin_dm_theta * -sin_dm_phi
            tmp2_z = cos_dm_theta
            tmp_x = tmp2_x
            tmp_y = tmp2_y
            tmp_z = tmp2_z
            tmp2_x = tmp_x
            tmp2_y = tmp_y
            tmp2_z = tmp_z
            car_x = tmp2_x
            car_y = tmp2_y
            car_z = tmp2_z
            tmp_x = car_x
            tmp_y = car_y
            tmp_z = car_z
            car_x = tmp_z;
            car_y = tmp_y;
            car_z = -tmp_x;
            dm_theta = np.arccos(car_z)
            if (car_y > 0):
                dm_phi = np.arctan(car_x / car_y)
            elif (car_y < 0):
                dm_phi = np.pi - np.arctan(car_x / -car_y)
            elif (car_y == 0 and car_x > 0):
                dm_phi = np.pi / 2.0
            elif (car_y == 0 and car_x < 0):
                dm_phi = -np.pi / 2.0
            else:
                dm_phi = 0
            xmap[y,x-xst] = (dm_theta / (np.pi) * np.cos(-dm_phi)) * float(dfish) + float(dfish/2)
            ymap[y,x-xst] = (dm_theta / (np.pi) * np.sin(-dm_phi)) * float(dfish) + float(dfish/2)
    np.save("xmap.npy", xmap)
    np.save("ymap.npy", ymap)
xmapL = np.zeros((dm_h, dm_w), np.float32)
ymapL = np.zeros((dm_h, dm_w), np.float32)
xmapR = np.zeros((dm_h, dm_w), np.float32)
ymapR = np.zeros((dm_h, dm_w), np.float32)
LX = 6210
LY = 2595
RX = 1982
RY = 2609
CX = LX - dfish / 2
CY = LY - dfish / 2
for i in range(len(xmapL)):
    xmapL[i] = xmap[i] + CX
for i in range(len(ymapL)):
    ymapL[i] = ymap[i] + CY
CX = RX - dfish / 2
CY = RY - dfish / 2
for i in range(len(xmapR)):
    xmapR[i] = xmap[i] + CX
for i in range(len(ymapR)):
    ymapR[i] = ymap[i] + CY
im = cv2.imread(args.infile)
left = cv2.remap(im, xmapL, ymapL, cv2.INTER_LINEAR, cv2.BORDER_CONSTANT)
right = cv2.remap(im, xmapR, ymapR, cv2.INTER_LINEAR, cv2.BORDER_CONSTANT)
om = cv2.hconcat([left, right])
cv2.imwrite(args.outfile, om)

 読み書きは OpenCV 任せなので、読める画像フォーマットと書ける画像フォーマットも OpenCV 次第。
 現像と画質調整をしっかり行い、8bit 無圧縮TIFF で出力。それを読ませるのがお薦め。16bit TIFF を読ませたいなどと考えても、たぶん OpenCV は over 8bit を生かしてくれない。だから読ませる前に、画質調整は完璧に済ませておくこと。
 出力は、png が最高画質だ。

 Quest 2 で表示させる場合は、どうやら jpeg にしないと駄目な模様。適当なツールで、png を jpeg に変換する。OpenCV 出力画像で拡張子を jpg にしても良いが、最高画質の jpeg にしてくれるかどうか怪しい。それよりは、素性の分かっているソフトで最高画質の jpeg に変換した方が良い。
 動画化素材にするなら、png のまま Davinci Resolve などに読ませる。

written by higashino [Virtual Reality] [この記事のURL] [コメントを書く] [コメント(0)] [TB(0)]

この記事へのトラックバックPingURL

Comments

TrackBacks

Darkside(https対応しました)

Generated by MySketch GE 1.4.1

Remodelling origin is MySketch 2.7.4