読者です 読者をやめる 読者になる 読者になる

ラジコン用360°全方位カメラ、透視変換のPython書き起こし

f:id:else-something:20160515235843j:plain

透視変換/射影変換部分のPython試し書き

光が足りてなくて、とても汚い絵になっちゃってますが、前回作ったカメラ部分から透視変換した映像を取得することができた。

livelifeulove.hatenablog.com

出来上がった画像はこんな感じ。

f:id:else-something:20160515235725j:plain

うーん。汚い。。。

コードはこんな感じになりました。

これを、Androidに移植しつつ、2−3手を加えたいところ。 しかし、Androidの開発したことないんだよなー。 環境作って、OpenCVを使えるようにならないと。。。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cv2
import numpy
import math
import pdb

###各種設定(半円のどのへんを使うかはgetPoints内で設定してる)
setWidth = 1280 #取り込み画像解像度(X)
setHeight = 720 #取り込み画像解像度(Y)
picCenter=(640,375) #半円ミラーのセンター
valDiv=24 #一周の分割数
segDeg = 360 / valDiv #1セグメントの角度
valRad = 300 #透視変換する際のセンターからの半径
retWidth = 800 #出力画像の解像度(X)
retHeight = valRad #出力画像の解像度(Y)


def getPerspectiveImage(img, points,width=50,height=300):
    
    pts1= numpy.array(points,dtype='float32')
    
    pts2 = numpy.array(((0,0),(0,height),(width,height),(width,0)),numpy.float32)
    
    M = cv2.getPerspectiveTransform(pts1, pts2)  # 透視変換行列を作成。
    return cv2.warpPerspective(img, M, (width, height))  # 透視変換行列を使って切り抜き。

def getPoints(Deg1,Deg2,R,C):
    S,L = 0.3,0.98 #センターから近い方の円周と遠い方の円周のそれぞれの割合
    x1 = int(R*L*math.cos(math.radians(Deg1)) + C[0])
    x2 = int(R*S*math.cos(math.radians(Deg1)) + C[0])
    x3 = int(R*S*math.cos(math.radians(Deg2)) + C[0])
    x4 = int(R*L*math.cos(math.radians(Deg2)) + C[0])

    y1 = int(R*L*math.sin(math.radians(Deg1)) + C[1])
    y2 = int(R*S*math.sin(math.radians(Deg1)) + C[1])
    y3 = int(R*S*math.sin(math.radians(Deg2)) + C[1])
    y4 = int(R*L*math.sin(math.radians(Deg2)) + C[1])
    
    #print ((x1,y1),(x2,y2),(x3,y3),(x4,y4))

    return ((x1,y1),(x2,y2),(x3,y3),(x4,y4))
    
if __name__ == '__main__':
    
    valWidth = int(retWidth/valDiv)

    cam = cv2.VideoCapture(0)
    cam.set(cv2.CAP_PROP_FRAME_WIDTH, int(setWidth))
    cam.set(cv2.CAP_PROP_FRAME_HEIGHT, int(setHeight))

    while True:
        #orig = cv2.imread('img1.jpg')
        orig = cam.read()[1]
        lines = orig.copy()
        
        #センターに丸をつける。
        lines = cv2.circle(lines,picCenter,5,(0,255,0),-1)
        
        valDeg1 = 1
        sumWarped = None
        for i in range(1,valDiv+1):
            #分割した数だけ、透視変換処理を繰り替えす
            valDeg2 = segDeg * i

            #分割用のポイントを得る
            valPoints =  getPoints(valDeg1,valDeg2,valRad,picCenter)
            
            #分割ラインを描画
            lines = cv2.line(lines,valPoints[2],valPoints[3],(0,255,0),3)
            
            #透視変換画像を得る
            warped = getPerspectiveImage(orig, valPoints,valWidth,retHeight)
            
            #画像の結合
            if sumWarped == None: 
                sumWarped = warped.copy()
            else:
                sumWarped = cv2.hconcat([sumWarped, warped])
            
            cv2.imshow('orig',lines)
            cv2.imshow('warp', sumWarped)
            valDeg1 = valDeg2
            
        if cv2.waitKey(1) & 0xFF == ord('q'):
            cam.release()
            cv2.destroyAllWindows()