Pipenvで再現環境を構築したかった(+α)
前々回の記事で,RICOH Theta Sを使ってスティッチング処理を行いました.
その動作環境を改善しようとして少し手間取ってしまったので,
備忘録も兼ねて,構築環境のPipfileと手間取りポイントをメモしておきます.
早速Pipenvファイルから晒していきましょう.
[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] [packages] opencv-contrib-python = "==3.4.4.19" opencv-python = "==3.4.4.19" intel-numpy = "*" numpy = "==1.15.1" [requires] python_version = "3.6"
はい,気になる点が3点ありますね.
- Opencv-pythonのバージョン古くない?
- なんでintel-numpyを入れるの?Anacondaにすれば?
- なんでintel-numpyが入ってるのになんでバージョン指定でnumpyを入れるの?
実はそれぞれに手間取りポイントがありました.
Q1: Opencv-pythonのバージョン古くない?
A: 最新版だとpipenv install opencv-python
が出来なかったから.
”Opencv python”で検索すると,色々と記事が出てくると思います.
ですが,そのとおり実行すると色んな所からエラーが発生します.
(代表的エラーは下記のリンクをご参照ください..)
解決方法が説明されてはいるのですが,なぜか私の環境では解決出来なかったので,
Raspiで上手くできた例を参考にして,
pipenv install opencv-contrib-python==3.4.4.19 pipenv install opencv-python==3.4.4.19
として,古いバージョンを導入することで,動作させることができました.
Q2: なんでintel-numpyを入れるの?Anacondaにすれば?
A: 高速に処理してほしいものの,Anacondaが好きになれないから.
ちなみに,Python3.6にしたのはintel-numpyを導入するためでした.
Python3.7だとインストールに失敗します.
Q3: intel-numpyが入ってるのになんでバージョン指定でnumpyを入れるの?
A: 指定しておかないと,後でnumpyインストール時に上書きされるから..
参考:https://github.com/pypa/pipenv/issues/3471
以上の詰まりポイントの結果,冒頭のPipfileになりました.
ソースコードも整理して,どこかでGithubにUpします.
1年どころか
3日も続きませんでした.はい.
...ブログの存在を忘れた前任者はZapしました.
次はうまくやってくれるでしょう.
Theta S の動画をPythonを使ってリアルタイムスティッチングしたかった.
Thetaも次世代機が現れて安価に手に入るようになりました.中古だと2万円を切るんですね.
今更ながら,このTheta SをUSBカメラとしてライブストリーミングして,スティッチングしてみました.
コードは以下のブログを参考にしています.
https://ensekitt.hatenablog.com/entry/2017/12/19/200000
http://blog.livedoor.jp/tmako123-programming/archives/50769806.html
上記からの変更点は,以下の二点
- 一番重なり方が自然な立体射影を採用
- Numpyを利用して高速化
# python3 import cv2 import numpy as np import matplotlib.pyplot as plt import random # %matplotlib inline import itertools import math # def cv_imshow(image_bgr): # image_rgb = cv2.cvtColor(image_bgr,cv2.COLOR_BGR2RGB) # plt.imshow(image_rgb) # plt.show() vertex = 640 src_cx = 319 src_cy = 319 src_r = 283 src_cx2 = 1280 - src_cx def align_imshow(image): image_s = cv2.resize(image, (1280, 720)) dst_map = np.array( list(itertools.product(range(vertex), range(vertex * 2)))) map_x = np.zeros((vertex, vertex * 2)) map_y = np.zeros((vertex, vertex * 2)) phi1 = math.pi * np.arange(vertex * 2) / vertex theta1 = math.pi * np.arange(vertex) / vertex X = np.matrix(np.cos(phi1)).T * np.sin(theta1) Y = np.matrix(np.sin(phi1)).T * np.sin(theta1) Z = np.cos(theta1) phi2 = np.arccos(-X) phi_cond = phi2 < np.pi / 2 # tmp = np.sqrt(np.multiply(Y,Y) + np.multiply(Z,Z)) # theta2 = np.multiply(np.sign(Y),np.arccos(-np.divide(Z,tmp))) theta2 = np.multiply(np.sign( Y), np.arccos(-np.divide(Z, np.sqrt(np.multiply(Y, Y) + np.multiply(Z, Z))))) # 立体射影 r_ = np.where(phi_cond, np.tan((phi2) / 2), np.tan((np.pi - phi2) / 2)) cos_theta2 = np.cos(np.where(phi_cond, theta2, math.pi - theta2)) sin_theta2 = np.sin(np.where(phi_cond, theta2, math.pi - theta2)) map_x = (src_r * r_ * cos_theta2 + np.where(phi_cond, src_cx, src_cx2)).T map_y = (src_r * r_ * sin_theta2 + src_cy).T map_x = map_x.astype('float32') map_y = map_y.astype('float32') return cv2.remap(image_s, map_x, map_y, cv2.INTER_LINEAR, cv2.BORDER_CONSTANT) cap = cv2.VideoCapture(-1) while True: # VideoCaptureから1フレーム読み込む frame = cap.read() edframe = align_imshow(frame) cv2.imshow('Edited Frame', edframe) # キー入力を1ms待って、k が27(ESC)だったらBreakする k = cv2.waitKey(1) if k == 27: break # キャプチャをリリースして、ウィンドウをすべて閉じる cap.release() cv2.destroyAllWindows()
結果
リアルタイム...?という感じですね.
自分が写り込んでしまうので,公開できる全天球動画を録画するのは難しい...
追記 (2020/08/23)
上記の処理のうち,map_x, map_yはリアルタイム計算には不要な処理でした. 下記のようにするとほぼリアルタイムに動作させることができます.
# python3 import cv2 import numpy as np import random import itertools import math vertex = 640 src_cx = 319 src_cy = 319 src_r = 283 src_cx2 = 1280 - src_cx dst_map = np.array( list(itertools.product(range(vertex), range(vertex * 2)))) map_x = np.zeros((vertex, vertex * 2)) map_y = np.zeros((vertex, vertex * 2)) phi1 = math.pi * np.arange(vertex * 2) / vertex theta1 = math.pi * np.arange(vertex) / vertex X = np.matrix(np.cos(phi1)).T * np.sin(theta1) Y = np.matrix(np.sin(phi1)).T * np.sin(theta1) Z = np.cos(theta1) phi2 = np.arccos(-X) phi_cond = phi2 < np.pi / 2 theta2 = np.multiply(np.sign( Y), np.arccos(-np.divide(Z, np.sqrt(np.multiply(Y, Y) + np.multiply(Z, Z))))) # 立体射影 r_ = np.where(phi_cond, np.tan((phi2) / 2), np.tan((np.pi - phi2) / 2)) cos_theta2 = np.cos(np.where(phi_cond, theta2, math.pi - theta2)) sin_theta2 = np.sin(np.where(phi_cond, theta2, math.pi - theta2)) map_x = (src_r * r_ * cos_theta2 + np.where(phi_cond, src_cx, src_cx2)).T map_y = (src_r * r_ * sin_theta2 + src_cy).T map_x = map_x.astype('float32') map_y = map_y.astype('float32') def align_imshow(image): return cv2.remap(cv2.resize(image, (1280, 720)), map_x, map_y, cv2.INTER_LINEAR, cv2.BORDER_CONSTANT) cap = cv2.VideoCapture(-1) while True: # VideoCaptureから1フレーム読み込む _, frame = cap.read() edframe = align_imshow(frame) cv2.imshow('Edited Frame', edframe) # キー入力を1ms待って、k が27(ESC)だったらBreakする k = cv2.waitKey(1) if k == 27: break # キャプチャをリリースして、ウィンドウをすべて閉じる cap.release() cv2.destroyAllWindows()
ブログ始めました
はじめましての方ははじめまして.
そうでない方もはじめまして.
Motzと申します.ITではないエンジニアをやっています.
このブログはアウトプットの練習を兼ねて,まとめてみようというものです.
書いてみたけどQitaに挙げるまでもないな,という気持ちからのブログです.
自身の興味がてんでバラバラなので,内容も雑多な形になると思いますが,
よろしくお願いいたします.