【Android】お手軽VR画像撮影・体験 のバックアップ(No.2)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 【Android】お手軽VR画像撮影・体験 へ行く。
- 1 (2020-04-29 (水) 20:18:49)
- 2 (2020-04-29 (水) 20:24:31)
100均とスマホでVR画像撮影 †
今ではある程度当たり前になってきたVR技術ですが、それでも自分でVR画像を撮影したりするのはあまり一般的ではありません。
鑑賞するだけなら100均の簡易なゴーグルでもいいのですが、自分で撮影するとなるとRICOH THETAのような専用デバイスが必要になってきます。
……本当にそうでしょうか?
考えてみればRICOH THETAは広角の魚眼レンズを前後に張り付けただけのものです。幸い魚眼レンズなら100均で手に入ります。スマホで魚眼画像をVR表示するソフトもVR Media Playerなどがあります。
というわけで試してみました。
VR Media Playerで写真を選択して、キャン★ドゥの魚眼レンズの場合LensはFisheye3、3DはNon-3DにしてVR表示をすると、若干反応が遅いもののそれなりにVRな体験ができました。
魚眼画像の正距円筒画像変換 †
魚眼のままVR表示できるのは楽でいいのですが、他のソフトでの表示なども考えると、正距円筒画像に変換しておきたくなります。
ひとまずstackoverflowで見つけたコード。正方形でないとうまく動かないようです。
いずれきちんとしたものを作りましょう。
using OpenCvSharp;
using System;
namespace FisheyeTest
{
class Program
{
const string PATH_IMAGE = "fisheyetest.jpg";
const int ESC = 27;
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Mat fisheyeImage, equirectangularImage;
int Wf, Hf;
float FOV;
int We, He;
fisheyeImage = Cv2.ImRead(PATH_IMAGE);
Cv2.NamedWindow("Fisheye Image");
Cv2.ImShow("fisheye Image", fisheyeImage);
Wf = fisheyeImage.Size().Width;
Hf = fisheyeImage.Size().Height;
FOV = (180 * (float)Math.PI) / 180;
We = Wf;
He = Hf;
while (Cv2.WaitKey(0) != ESC)
{
}
equirectangularImage = new Mat();
equirectangularImage.Create(He, We, MatType.CV_8UC3);
for (int Xe = 0; Xe < We; Xe++)
{
for (int Ye = 0; Ye < He; Ye++)
{
Point2f fisheyePoint = findCorrespondingFisheyePoint(Xe, Ye, We, He, FOV);
if (fisheyePoint.X >= We || fisheyePoint.Y >= He)
continue;
if (fisheyePoint.X < 0 || fisheyePoint.Y < 0)
continue;
//equirectangularImage.At<Vec3b>(Xe, Ye) = fisheyeImage.At<Vec3b>((int)fisheyePoint.X, (int)fisheyePoint.Y);
equirectangularImage.Set<Vec3b>(Xe,Ye, fisheyeImage.At<Vec3b>((int)fisheyePoint.X, (int)fisheyePoint.Y));
}
}
Cv2.NamedWindow("Equirectangular Image");
Cv2.ImShow("Equirectangular Image", equirectangularImage);
while (Cv2.WaitKey(0) != ESC)
{
}
Cv2.ImWrite("im2.jpg", equirectangularImage);
}
static Point2f findCorrespondingFisheyePoint(int Xe, int Ye, int We, int He, float FOV)
{
Point2f fisheyePoint = new Point2f();
float theta, phi, r;
Point3f sphericalPoint = new Point3f();
theta = (float)(Math.PI * (Xe / ((float)We) - 0.5));
phi = (float)(Math.PI * (Ye / ((float)He) - 0.5));
sphericalPoint.X = (float)(Math.Cos(phi) * Math.Sin(theta));
sphericalPoint.Y = (float)(Math.Cos(phi) * Math.Cos(theta));
sphericalPoint.Z = (float)Math.Sin(phi);
theta = (float)Math.Atan2(sphericalPoint.Z, sphericalPoint.X);
phi = (float)Math.Atan2(Math.Sqrt(Math.Pow(sphericalPoint.X, 2) + Math.Pow(sphericalPoint.Z, 2)), sphericalPoint.Y);
r = ((float)We) * phi / FOV;
fisheyePoint.X = (int)(0.5 * ((float)We) + r * Math.Cos(theta));
fisheyePoint.Y = (int)(0.5 * ((float)He) + r * Math.Sin(theta));
return fisheyePoint;
}
}
}


