hirax.net::Keywords::「撮影」のブログ



2015-02-17[n年前へ]

身近な「レンタル撮影スタジオ」で非日常体験をしてみたい!? 

 「レンタル撮影スタジオ」…さまざまな状況・場所の撮影を行うための場所が、意外に身近な街角にあったりする(参考:レンタル撮影スタジオ)。たとえば、東京山手線駅チカな場所でさえ、軍艦島廃病院病室と美術室が隣り合う建物刑務所サイバーなローマ宮殿…といった未知なる場所が一時間5千円ナリくらいのお値段で、借りることができたりする。

 ずっと昔、カラオケなんて存在ができる前は、素人が歌を他人に聴かせる一般的な場なんて存在しなかった気がする。それと同じように、極端な例だけれども、刑務所や廃病院やローマ宮殿なんて、一般的ではない場所だ。…そんな非日常な場所を、月に一回くらいの頻度で借りてみて、そこで飲み会とか勉強会をやってみるのも面白いかも。

2016-07-31[n年前へ]

Ricoh Theta S 撮影動画で3次元の世界を撮影してみよう!? 

 昨年の秋、バンコクの路地を自転車で走りながら、右手でRicoh Theta Sを空に向かって差し上げて動画を撮影しました。その撮影動画を使って、今日は3次元の世界を再構成をしてみました。
 その1例が下に貼り付けた動画です。手に持たれたTheta Sが移動していった「視点・撮影点」を青くマーキングしてあるので、狭い路地を進む自分の軌跡を眺めることもできます。

 今日やってみたことはとても簡単です。多視点からの撮影画像を使って三角測量を行い立体形状を求める手法を全天周カメラであるRicoh の Theta S画像に適用してみただけです。
 解像度的には静止画像からの復元の方が良いですが、ただ移動しながら動画撮影するだけで3次元の世界を撮影できるというのはお手軽感が高いものです。

 ちなみに、Ricoh Theta Sを室内で移動させつつ撮影し、その撮影画像から3次元空間を復元させてみると下動画のようになります。カメラの歪みをきちんと校正していないこともあり、その歪みを反映して復元空間自体も歪んでしまっていますが、今度はそんな歪みも除去して、綺麗な3次元空間を撮影してみたいと思います。

Ricoh Theta S 撮影動画で3次元の世界を撮影してみよう!?






2016-08-31[n年前へ]

100円ショップのダイソー凹面鏡(200円)で、シュリーレン光学系撮影をしてみよう!? 

 空気中の屈折率分布・密度分布を可視化するシュリーレン撮影のデモ映像で、「たて v.s. ほこ」的にドライヤー2本が勝負をし合う動画を面白く楽しみました。それが、下に貼り付けた動画です。

 面白く楽しいなら、それはもちろん真似てやってみよう!というわけで、100円ショップのダイソーに行き、一個200円ナリの大型凹面鏡を2個買い、シュリーレン光学系を簡易的に組んでみました。組んだ光学系は、おおよそ右のようなレイアウトです(右の写真はカメラ画角に納まるように、実際に使用したレイアウトより少し小さく配置しています)。また、使ったライトは机の上に転がっていた、小さなLEDライトスタンドです。

 この凹面鏡2個のトータル400円ナリで作ったシュリーレン光学系、雑極まりない作りですが、ライターから出るガスや炎の動きを可視化するくらいならとても簡単にできます。空気のような「その動きを普通は目にすることができないもの」が一体どんな風に流れているのか、それを眺めることができるというのは意外に楽しいものです。…というわけで、100円ショップのダイソー凹面鏡(200円)で、シュリーレン光学系を組んでみて、遊んでみるのは少しお勧めです。

 100円ショップでどんなもの買い、そしてどんな風に並べれば超簡単なシュリーレン光学系撮影実験をすることができるか…は明日以降に書いてみることにします。

100円ショップのダイソー凹面鏡(200円)で、シュリーレン光学系撮影をしてみよう!?






2017-01-29[n年前へ]

「手持ちスマホ撮影動画からの超巨大開口レンズ撮影」に挑戦してみよう!? 

 かつて、スマホに搭載されているカメラのレンズはとても小さく、綺麗なボケとは無縁の存在でした。しかし、今や最新のスマホには特殊処理によるボケ生成機能などが備えられています。カメラレンズの光学開口径が小さくとも、たとえば2眼カメラなどを備えて距離情報を取得して、距離情報などからボケを人工的に合成するといった仕組みです。

 そんな最新スマホを持たずとも、大レンズのボケ味を手に入れるために、「手持ちスマホ撮影動画からの超巨大開口レンズ撮影」に挑戦してみました。スマホ動画から巨大開口レンズ撮影の手順はとても簡単、まずは目の前の風景にスマホを向けて・なるべくスマホが平面上を動くように意識しながら(スマホを動かしつつ)動画撮影します。そして、動画の各コマから画像ファイル群を生成し、それぞれの画像が撮影された位置や方向にもとづいて撮影された光情報を加算合成する、というものになります。

 細かい手順は、スマホ撮影動画(の展開画像をもとに) Bundler: Structure from Motion (SfM) から出力された刻々のカメラ位置・方向や特徴点情報ファイル(bundler.out)を読み込み、それらのカメラ情報にもとづいて、刻々の撮影画像をレンズ開口面に沿った(同じ方向を向く平行カメラが存在していた場合の)光線画像を位置・角度ズレを踏まえて重ねることで、任意のピント位置に焦点を合わせた超巨大開口レンズ撮影画像を生成する…というものです。

 試しに、iPhoneを約1.5m×1.0mの範囲で動かしつつ動画撮影し、つまり、レンズ直径約1.5mに相当する範囲で動かしつつ動画撮影し、その画像群から開口合成により超巨大カメラの撮影画像を作り出してみた結果が右上の画像です。

 右上画像を眺めてみても、良好なボケ味どころか、全くピントが合っていない画像にしか見えません。直径が1mを超える開口を持つカメラレンズとなると焦点深度もとても浅くなるのでピントがなかなか合わない…というわけでなく、手持ち撮影動画からのカメラ位置・方向精度が低いせいか、単一カメラに平行合成した後のズレが大きいようです。

 ちなみに、試しに各画像を(撮影方向による傾きを補正しつつ)位置毎に並べてみると、下の画像のようになります。動画撮影からのカメラ位置推定精度が果たして不十分なのかどうか、次は撮影カメラ位置を精度良く知る事ができる撮影治具でも作り、また再挑戦してみたいと思います。

 上記処理のコード手順、Python/OpenCVで書いたコード処理手順は、bundler.outからカメラ位置・方向・焦点距離や歪みパラメータを読み込み、cv2.initUndistortRectifyMapにカメラ情報を渡して、各撮影画像の向き補正用のホモグラフィーマップを作成してremapで変換した後に、各撮影画像を加算合成するという手順です。

 Bundlerの出力ファイルを読み込んでライトフィールド合成を行うOpenCV/Pythonコード、まだまだ間違い含まれているような気もしますが、とりあえずここに貼り付けておくことにします。

import cv2
import numpy as np
from matplotlib import pyplot as plt
from PIL import Image
import math
%matplotlib inline

class camera:
    def __init__(self):
        self.f = 1.0
        self.k1 = 0.0
        self.k2 = 0.0
        self.R = [[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]
        self.T = [0.0,0.0,0.0]

def readBundlerOut( filePath ):
    f = open(filePath, 'r')
    list = f.readlines()
    f.close()

    numberOfCameras = int((list[1].split())[0]) 
    cameras = []
    for i in range(numberOfCameras):
        aCamera = camera()
        fk1k2 = [float(j) for j in list[5*i+2].split()]
        aCamera.f  = fk1k2[0]
        aCamera.k1 = fk1k2[1]
        aCamera.k2 = fk1k2[2]
        rot = []
        for j in range(1,4):
            rot.append( [float(k) for k in list[ 5*i+2+j ].split()] )
        aCamera.R = rot
        aCamera.T = [float(k) for k in list[ 5*i+2+4 ].split()]
        cameras.append(aCamera)
    return cameras

def readImageList( listPath, imageDirPath ):
    f = open(listPath, 'r')
    list = f.readlines()
    list = [ i.rstrip() for i in list ]
    f.close()
    list = [imageDirPath+fileName for fileName in list]
    return list

class lightField:
    
    def __init__(self):
        self.w = 2000
        self.h = 2000
    
    def loadImageListAndMakeLightField( self, 
                    imagePathList, cameraList, workList, scaleA ):
        self.cimg  = np.zeros((self.h, self.w,3), dtype=np.uint8)
        sum = 1.0
        for i in workList:
            img = cv2.imread( imagePathList[i], cv2.IMREAD_COLOR )
            h, w = img.shape[:2]
            imageHeight = img.shape[0]
            imageWidth =  img.shape[1]
            focalLength = cameraList[i].f
            principalPointX = 0.500000
            principalPointY = 0.500000
            distCoef = np.array([ 0.0, 0.0, 0.0, 0.0, 0.0 ])
            cameraMatrix = np.array([ 
                [focalLength,   
                 0.0,          
                 imageWidth  * principalPointX], 
                [0.0,           
                 focalLength,  
                 imageHeight * principalPointY], 
                [0.0,           0.0,          1.0] 
                           ])
            newCameraMatrix, roi = cv2.getOptimalNewCameraMatrix(
                cameraMatrix,
                distCoef,
                (img.shape[1], img.shape[0]),1,
                (img.shape[1], img.shape[0]) )
            rotMatrix = np.array( cameraList[i].R )
            map = cv2.initUndistortRectifyMap( 
                newCameraMatrix,
                distCoef,
                rotMatrix,
                newCameraMatrix, 
                (img.shape[1], img.shape[0]),
                cv2.CV_32FC1)
            
            undistortedAndRotatedImg = cv2.remap( img, 
                        map[0], map[1],
                        cv2.INTER_LINEAR )
            
            scale = 1.0
            pt3 = np.array(cameraList[i].T) - np.array(cameraList[0].T)
            x =  ( self.w/2.0 - pt3[0] * scale * scaleA ) 
            y =  ( self.h/2.0 - pt3[1] * scale * scaleA ) 
            pts1 = np.float32( [[0,      0],
                                [w, 0],
                                [w, h],
                                [0, h]])
            pts2 = np.float32(  [[x,           y],
                                 [x + w*scale, y],
                                 [x + w*scale, y + h*scale],
                                 [x,           y + h*scale]] )
            M = cv2.getPerspectiveTransform( pts1, pts2 )
            img2 = cv2.warpPerspective( 
                undistortedAndRotatedImg, M, (self.w, self.h) )
            sum = sum + 1.0
            self.cimg = cv2.addWeighted(
                 self.cimg, (sum-1) / sum, 
                 img2,      (1.0) / sum, 0)
    
    def showImage(self):
        plt.figure( figsize=(14,14) )
        plt.imshow( np.array(self.cimg2) ) 
        plt.autoscale( False )

「手持ちスマホ撮影動画からの超巨大開口レンズ撮影」に挑戦してみよう!?「手持ちスマホ撮影動画からの超巨大開口レンズ撮影」に挑戦してみよう!? 






2017-10-07[n年前へ]

スマホ撮影画像の「距離マップ」を使って「レンブラント」写真を撮ってみる 

 AppleのiPhone新機能の紹介記事、”コスプレをiPhone 8 Plusの新機能「ポートレートライティング」で撮影するとこうなる”がとても面白いです。内容は、(おそらく)スマホのステレオカメラなどを使って得られる「スマホの撮影画像に写る各点までの距離マップ」を使った画像処理により、さまざまな照明効果を使った写真撮影や動画撮影ができるというものです。紹介記事中では、 ”iPhone 8 Plus / Xの新機能「”ということだったので、普通のスマホで同じことをやったらどうなるか?を簡単に確かめてみることにしました。

 やったことはとても簡単です。まず、普通のスマホ(iPhone 6s )で撮影位置を少し動かしながら画像を撮り、その画像から3次元・距離マップ情報を作り出します。そして、その距離情報を使って、撮影画像の色画像に適切な階調変換や照明処理を掛けてやるわけです。

 距離マップ情報が無い場合、つまり、色画像情報だけだと、(もしも単純に処理をしたとすると)「同じ色・輝度の場所は同じような画像処理を掛ける」ことになってしまいます。すると、階調変換処理により被写体だけを浮かび上がらせようとしても、背景にも同じ階調変換処理が掛かってしまい、できばえがイマイチということになってしまいます。けれど、距離マップ情報があれば、被写体だけを上手く浮かび上がらせた処理も、割と楽にできるというわけです。

 というわけで、撮影した生画像(左下画像)から、他撮影画像(右画像)との視差で生成した距離マップを処理データとして使いつつ作成した「レンブラントライティング」を掛けてみたのが右下画像です。「同じ明るさの場所に対して同じような階調変換」が掛けられているのではないことがわかるかと思います。そして、被写体(マネキン頭部ですが)だけを浮かび上がらせることもわかるのではないでしょうか。

 眺めていると、「レンブラントライティング」だけでなく、色んなリライティングの「モード」を、スマホのカメラで試したくなります。

スマホ撮影画像の「距離マップ」を使って「レンブラント」写真を撮ってみるスマホ撮影画像の「距離マップ」を使って「レンブラント」写真を撮ってみるスマホ撮影画像の「距離マップ」を使って「レンブラント」写真を撮ってみるスマホ撮影画像の「距離マップ」を使って「レンブラント」写真を撮ってみる








■Powered by yagm.net