質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenCV

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1889閲覧

opencvのZhangのキャリブレーションが合っているのかどうか

nuiri1343

総合スコア54

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenCV

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/12/02 10:36

前提・実現したいこと

OpenCVを使って、Zhangのキャリブレーションを行い、内部パラメータと外部パラメータを求めたいです。

求めるところまではできましたが、結果得られたパラメータが合っているのかすごく心配です。

以下のソースコード(一般的なZhangのキャリブレーションを実行するプログラムです)でZhangのキャリブレーションを行いました。
この時使用した画像の一枚目がこれです。
1枚目の画像(原画像)

この画像に、findChessboardCornersとdrawChessboardCornersを実行した結果得られた画像がこれです。
1枚目の画像(コーナー検出後)

そして、今回のキャリブレーションによって得られたパラメータのうち、回転行列と並進ベクトルが以下のようになりました。

回転行列 :
[0.8864976089930998, -0.2546690562624887, 0.3863491439512847;
0.06027432266890168, 0.8913665284993816, 0.4492579636442369;
-0.4587907968522497, -0.3749791776263512, 0.8055443011221314]

並進ベクトル
[-95.4959092690081;
-97.60717747135726;
452.887102880167]

この二つのパラメータ(外部パラメータ)は、上で載せた1枚目のチェスボードパターン画像の回転行列と並進ベクトルです。

しかし、この並進ベクトルがおかしいのではないかと思います。
なぜなら、ワールド座標の座標軸は、画像のチェスボードパターンの左上の交点を原点として、
右方向にx軸、下方向にy軸、手前から奥に向かってz軸なので(OpenCVは右手座標系なので)
カメラのある位置と全く違う位置を示しているように思えるのです。

少なくとも、チェスボードパターンの左側にカメラはありませんし、チェスボードパターンの上側にもありません。
ましてや、チェスボードパターンの裏側にカメラがあるなどありえないと思うのです。

再投影誤差は0.409436でした。
一枚目の画像の再投影誤差は0.261726でした。
あまり誤差があるとは思えないのですが
何か解釈が間違っているのでしょうか?

お詳しい方、どうか教えてください。
よろしくお願いします。

該当のソースコード

C++

1int main(void) { 2 3 const std::string win_src = "Source"; 4 const std::string win_und = "Undistorted Image"; 5 const std::string file_cam_param = "camera_param.xml"; 6 7 std::vector<Mat> img; 8 const int NUM_IMG = 9; 9 const Size PAT_SIZE(13, 9); 10 float CHESS_SIZE = 18.8; 11 12 std::vector<std::vector<Point3f>> objectPoints(NUM_IMG); 13 std::vector<std::vector<Point2f>> imagePoints(NUM_IMG); 14 15 TermCriteria criteria(TermCriteria::MAX_ITER | TermCriteria::EPS, 20, 0.001); 16 17 Mat cameraMatrix; 18 Mat distCoeffs; 19 std::vector<Mat> rvec; 20 std::vector<Mat> tvec; 21 22 for (int i = 0; i < NUM_IMG; i++) { 23 std::string fileName = "./calib_img" + std::to_string(i + 1) + ".jpg"; 24 img.push_back(imread(fileName)); 25 } 26 27 for (int i = 0; i < NUM_IMG; i++) { 28 for (int j = 0; j < PAT_SIZE.area(); j++) { 29 objectPoints[i].push_back(Point3f(static_cast<float>(j%PAT_SIZE.width*CHESS_SIZE), static_cast<float>(j / PAT_SIZE.width*CHESS_SIZE), 0.0)); 30 } 31 } 32 33 for (int i = 0; i < NUM_IMG; i++) { 34 std::cout << "calib_img" << i + 1 << ".jpg"; 35 imshow(win_src, img[i]); 36 if (findChessboardCorners(img[i], PAT_SIZE, imagePoints[i])) { 37 drawChessboardCorners(img[i], PAT_SIZE, imagePoints[i], true); 38 imshow(win_src, img[i]); 39 std::cout << " - siccess" << std::endl; 40 waitKey(0); 41 } 42 else { 43 std::cout << " - fail" << std::endl; 44 waitKey(0); 45 return -1; 46 } 47 } 48 49 double result = calibrateCamera(objectPoints, imagePoints, img[0].size(), cameraMatrix, distCoeffs, rvec, tvec); 50 std::cout << "result:" << result << std::endl; 51 52 53 for (int i = 0; i < (int)objectPoints.size(); i++) { 54 std::vector<Point2f> imagePoints2; 55 projectPoints(objectPoints[i], rvec[i], tvec[i], cameraMatrix, distCoeffs, imagePoints2); 56 double error = cv::norm(imagePoints[i], imagePoints2, cv::NORM_L2); 57 error = std::sqrt(error * error / (int)objectPoints[i].size()); 58 std::cout << "error" << i + 1 << ":" << error << std::endl; 59 60 } 61 62 63 64 Mat rmat; 65 Rodrigues(rvec[0], rmat); 66 67 Mat extr(4, 4, CV_64F); 68 setIdentity(extr); 69 Rodrigues(rvec[0], extr(Rect(0, 0, 3, 3))); 70 tvec[0].copyTo(extr(Rect(3, 0, 1, 3))); 71 72 73 74 FileStorage fswrite(file_cam_param, FileStorage::WRITE); 75 if (fswrite.isOpened()) { 76 fswrite << "cameraMatrix" << cameraMatrix; 77 fswrite << "distCoeffs" << distCoeffs; 78 fswrite << "rvec" << rvec[0]; 79 fswrite << "rmat" << rmat; 80 fswrite << "tvec" << tvec[0]; 81 fswrite << "extr" << extr; 82 } 83 fswrite.release(); 84 85 Mat img_undist; 86 for (int i = 0; i < NUM_IMG; i++) { 87 undistort(img[i], img_undist, cameraMatrix, distCoeffs); 88 imshow(win_src, img[i]); 89 imshow(win_und, img_undist); 90 //imwrite("undistort_img" + std::to_string(i + 1) + ".jpg", img_undist); 91 waitKey(0); 92 } 93 94 return 0; 95 96 97 98}

補足情報(FW/ツールのバージョンなど)

Windows10
VisualStudio2017
Opencv-3.4.2

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

外部パラメータの意味が異なるのではないでしょうか.

別の質問:
画素のカメラに対する角度を求めたい
で引用した式では,外部パラメータ(R,t)は

カメラ座標 = R * ワールド座標 + t

となっています.

  • tとは,ワールド原点をカメラ座標系で書いたもの
  • Rの各行ベクトルが,カメラ座標系の基底ベクトルをワールド座標系で書いたもの
  • Rの各列ベクトルが,ワールド座標系の基底ベクトルをカメラ座標系で書いたもの

ではないかと.

投稿2018/12/03 13:18

fana

総合スコア11634

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問