質問するログイン新規登録

Q&A

1回答

1883閲覧

2枚の画像に対してステレオ平行化をおこないたい

stereo

総合スコア0

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2023/07/05 14:59

0

0

実現したいこと

2枚の画像の平行化処理した画像を出力する

前提

webカメラ2台を使用して撮影した画像からキャリブレーションを行い、内部、外部パラメータを求めて平行化マップを計算した。その計算した数値を使い平行化処理を画像2枚に対して行う

発生している問題・エラーメッセージ

実行して表示された画像が斜めって表示されており、正しく平行化されているのかが分かっていない。
斜めではなく表示するにはどうすればいいのでしょうか。

イメージ説明

エラーメッセージ ### 該当のソースコード このコードでキャリブレーションを行いました。 import numpy as np import cv2 from tqdm import tqdm # Set the path to the images captured by the left and right cameras #画像のパス設定 pathL = "./sutereo_L/" pathR = "./sutereo_R/" #各3Dパターンの画像座標を抽出しています print("Extracting image coordinates of respective 3D pattern ....\n") #検出したコーナーを # Termination criteria for refining the detected corners criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) objp = np.zeros((10*7,3), np.float32) objp[:,:2] = np.mgrid[0:10,0:7].T.reshape(-1,2) img_ptsL = [] img_ptsR = [] obj_pts = [] for i in tqdm(range(0,15)): imgL = cv2.imread(pathL+"camera1_%d.jpg"%i) imgR = cv2.imread(pathR+"camera2_%d.jpg"%i) imgL_gray = cv2.imread(pathL+"camera1_%d.jpg"%i,0) imgR_gray = cv2.imread(pathR+"camera2_%d.jpg"%i,0) outputL = imgL.copy() outputR = imgR.copy() retR, cornersR = cv2.findChessboardCorners(outputR,(10,7),None) retL, cornersL = cv2.findChessboardCorners(outputL,(10,7),None) if retR and retL: obj_pts.append(objp) cv2.cornerSubPix(imgR_gray,cornersR,(5,5),(-1,-1),criteria) cv2.cornerSubPix(imgL_gray,cornersL,(5,5),(-1,-1),criteria) cv2.drawChessboardCorners(outputR,(10,7),cornersR,retR) cv2.drawChessboardCorners(outputL,(10,7),cornersL,retL) cv2.imshow('cornersR',outputR) cv2.imshow('cornersL',outputL) cv2.waitKey(0) img_ptsL.append(cornersL) img_ptsR.append(cornersR) print("Calculating left camera parameters ... ") # Calibrating left camera retL, mtxL, distL, rvecsL, tvecsL = cv2.calibrateCamera(obj_pts,img_ptsL,imgL_gray.shape[::-1],None,None) hL,wL= imgL_gray.shape[:2] new_mtxL, roiL= cv2.getOptimalNewCameraMatrix(mtxL,distL,(wL,hL),1,(wL,hL)) print("Calculating right camera parameters ... ") # Calibrating right camera retR, mtxR, distR, rvecsR, tvecsR = cv2.calibrateCamera(obj_pts,img_ptsR,imgR_gray.shape[::-1],None,None) hR,wR= imgR_gray.shape[:2] new_mtxR, roiR= cv2.getOptimalNewCameraMatrix(mtxR,distR,(wR,hR),1,(wR,hR)) print("Stereo calibration .....") flags = 0 flags |= cv2.CALIB_FIX_INTRINSIC # Here we fix the intrinsic camara matrixes so that only Rot, Trns, Emat and Fmat are calculated. # Hence intrinsic parameters are the same criteria_stereo= (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # This step is performed to transformation between the two cameras and calculate Essential and Fundamenatl matrix retS, new_mtxL, distL, new_mtxR, distR, Rot, Trns, Emat, Fmat = cv2.stereoCalibrate(obj_pts, img_ptsL, img_ptsR, new_mtxL, distL, new_mtxR, distR, imgL_gray.shape[::-1], criteria_stereo, flags) # Once we know the transformation between the two cameras we can perform stereo rectification # StereoRectify function rectify_scale= 1 # if 0 image croped, if 1 image not croped rect_l, rect_r, proj_mat_l, proj_mat_r, Q, roiL, roiR= cv2.stereoRectify(new_mtxL, distL, new_mtxR, distR, imgL_gray.shape[::-1], Rot, Trns, rectify_scale,(0,0)) # Use the rotation matrixes for stereo rectification and camera intrinsics for undistorting the image # Compute the rectification map (mapping between the original image pixels and # their transformed values after applying rectification and undistortion) for left and right camera frames Left_Stereo_Map= cv2.initUndistortRectifyMap(new_mtxL, distL, rect_l, proj_mat_l, imgL_gray.shape[::-1], cv2.CV_16SC2) Right_Stereo_Map= cv2.initUndistortRectifyMap(new_mtxR, distR, rect_r, proj_mat_r, imgR_gray.shape[::-1], cv2.CV_16SC2) print("Saving paraeters ......") cv_file = cv2.FileStorage("data/params_py.xml", cv2.FILE_STORAGE_WRITE) cv_file.write("Left_Stereo_Map_x",Left_Stereo_Map[0]) cv_file.write("Left_Stereo_Map_y",Left_Stereo_Map[1]) cv_file.write("Right_Stereo_Map_x",Right_Stereo_Map[0]) cv_file.write("Right_Stereo_Map_y",Right_Stereo_Map[1]) cv_file.release() ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 次に平行化を行うコードを示します。 import numpy as np import cv2 # 読み込む画像のパス pathL = "./parallel/camera1_sample2.jpg" pathR = "./parallel/camera2_sample2.jpg" # ステレオカメラのパラメータファイル params_file = "data/params_py.xml" # 画像の読み込み imgL = cv2.imread(pathL) imgR = cv2.imread(pathR) # ステレオカメラのパラメータの読み込み cv_file = cv2.FileStorage(params_file, cv2.FILE_STORAGE_READ) Left_Stereo_Map_x = cv_file.getNode("Left_Stereo_Map_x").mat() Left_Stereo_Map_y = cv_file.getNode("Left_Stereo_Map_y").mat() Right_Stereo_Map_x = cv_file.getNode("Right_Stereo_Map_x").mat() Right_Stereo_Map_y = cv_file.getNode("Right_Stereo_Map_y").mat() cv_file.release() # 画像の平行化 outputL = cv2.remap(imgL, Left_Stereo_Map_x, Left_Stereo_Map_y, cv2.INTER_LANCZOS4) outputR = cv2.remap(imgR, Right_Stereo_Map_x, Right_Stereo_Map_y, cv2.INTER_LANCZOS4) # 平行化された左右の画像を表示 cv2.imshow("Rectified Left Image", outputL) cv2.imshow("Rectified Right Image", outputR) cv2.waitKey(0) cv2.destroyAllWindows() ### 試したこと パラメーラの妥当性確認 ### 補足情報(FW/ツールのバージョンなど) 出力されたパラメータを記載します。 Left Camera Matrix: [[645.06275565 0. 332.32329196] [ 0. 646.19435302 225.40499002] [ 0. 0. 1. ]] Left Distortion Coefficients: [[ 0.05016129 -0.01679789 0.00309687 0.00344186 -0.556103 ]] Left Rectification Matrix: [[ 0.98153948 -0.13233007 0.13809058] [ 0.13485803 0.9908234 -0.00907188] [-0.13562289 0.02752704 0.99037806]] Left Projection Matrix: [[632.16119385 0. 241.69674492 0. ] [ 0. 632.16119385 222.93207932 0. ] [ 0. 0. 1. 0. ]] Right Camera Matrix: [[644.81940636 0. 320.50608279] [ 0. 645.35477403 232.42834496] [ 0. 0. 1. ]] Right Distortion Coefficients: [[ 0.05672832 -0.15310448 -0.00042549 0.00191608 -0.08251009]] Right Rectification Matrix: [[ 0.98675117 -0.13354429 0.09213063] [ 0.13182216 0.99096912 0.02455863] [-0.09457827 -0.0120884 0.99544403]] Right Projection Matrix: [[ 6.32161194e+02 0.00000000e+00 2.41696745e+02 -4.53300506e+03] [ 0.00000000e+00 6.32161194e+02 2.22932079e+02 0.00000000e+00] [ 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00]]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

meg_

2023/07/05 21:23

確認ですが質問のコードは全て自作でしょうか?どこまで思った通りに動作しているか分かりますか?
guest

回答1

0

実行して表示された画像が斜めって表示されており、正しく平行化されているのかが分かっていない。

それでは,まずは,斜めなのが何らかのバグやパラメータの悪さに起因するものなのか,それともその斜めな結果が正しいのか,というのを確認する必要がありそうです.
(まぁ,文脈から推測するに,それが正しいような実施形態をわざわざ採用しているとは思えませんので,前者側なのでしょうが…)

「そもそも並行化すると何が嬉しいんですか? / 何のために平行化するんですか?」ということに立ち戻って考えれば,「目的に見合った画像になっているか否か」を見ることが一定の確認手段となります.
(「正しさ」の確認,というよりも,処理結果の「良さ」の確認みたいな意味合いになる気もしますが)

並行化とは「同一の対象の像のY座標が2枚の平行化画像上で同一になっている」を理想的な結果とする処理なのでしょうから,そうなっているかどうかを画像上の様々な位置に関して調べて見ればよいです.
目視確認する用に,画像上でクリックした位置(Y座標)にただ水平線を描画する(もちろん両画像に描画する)だけの機能みたいなのをおまけで実装すると便利ですよ.


で,どうやら斜めな結果というのは正しくなさそうな場合……

ある程度感覚的に確認できるものはカメラ間の相対外部パラメータ(が「どう見ても異常 か否か」)でしょうか.
あなたは2台のカメラの配置関係を ある程度の精度では 知っているハズ(現物が手元にあるのだから).
それと照らし合わせてみて,明らかに異常ではないか? というのを確認しましょう.

  • 2台のカメラはほぼ同じ姿勢なハズなのに, R の中身を見ると明らかにめっちゃ回転してるとか,T の複数の要素が妙に大きい絶対値を持ってるとか
  • 2台のカメラ間の距離はおおよそ10cmくらいなのに T のノルムがそうなってないとか

カメラの内部パラメータの精度も疑うべき要素ではありますが,ほんとうにひどい精度(というか滅茶苦茶な値)でもない限りは,そんなにぱっと見で「明らかに平行化がおかしい」という結果は生じ難いんじゃないかな?

…といった感じで,入力データを見ても怪しいところが見つからないようであれば,
あとは並行化自体が悪いか,その他の凡ミスみたいなのを疑うことになるでしょう.
凡ミスについてはちまちまとデバッグして見つけるくらいしか手は無いんじゃないかと思いますが,
並行化処理部分については並行化画像を自前で作る実装を書いてみるのがある意味手っ取り早いかと.(自前で原理通りに実装したやつでも同じように妙に斜めな結果を生じるようであれば問題はどこか別の部分にあるのではないか,と判断する)

投稿2023/07/06 01:24

編集2023/07/06 01:29
fana

総合スコア12401

fana

2023/07/06 01:43 編集

> 並行化画像を自前で作る実装を書いてみる 今回の場合,「精度がちょっと…」とかいう話では無く,「明らかに変になる」みたいな事柄に関する確認だから, 既存処理と解像度とか視野方向だとかを厳密に揃える必要とかも無いだろうし,その自前実装を今後実用するという話でもないのだから,かなりやっつけ仕事的に書き殴ったコードでOKだと思う. 適当に「基線に垂直な方向の視野の(ピンホールカメラモデルによる)画像」を作る程度の話なハズ. (「基線に垂直な方向」には自由度があるけども,そこは常識的な範囲の方向を選べばいい) あと,こういう場面では「それじゃあ,マッピングテーブルを作って OpenCV の remap で…」とかなんとか「凝らない」方がいい. とにかく「理屈通りに正しく動く」ことが最重要で,処理速度とか諸々に関してはどうでもいいのだから ちょっとでも間違いを起こしそうな/既存処理でも用いているような 処理は使わずに,愚直に1画素ずつ描画するような2重ループみたいなのを書くことを勧める.(言うまでも無く,「画素の色を補間で求めてどうの」とかも不要)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.25%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問