OpenCVの鳥瞰図用のホモグラフィを計算するために渡す点の座標がわかりません。
参考にしたのは「詳解OpenCV3」という本のP672の例19-1のプログラムです。
##問題点
本に書いてあることをほぼそのまま写して実行しました。
元の画像は次の画像です。(解像度を少し下げました)
鳥瞰図の結果は次のようになりました。
少し見づらいですが、左上に元の画像の鳥瞰画像が出ています。
コードは次に示します。
C++
1#include <iostream> 2#include <fstream> 3#include <opencv2/opencv.hpp> 4#include <stdlib.h> 5 6const int WIDTH = 600; 7const int HEIGHT = 600; 8 9//入力は[board_w] = 6, [board_h] = 9, [intinsics.xml] = intrinsics.xml, [checker_image] = image.png 10void help(char *argv[]){ 11 std::cout << "Call: " /Users/shimizumiwa/coyomi/apps/bird/main.cpp<< argv[0] << "[board_w] [board_h] [intrinsics.xml] [checker_image]" << std::endl; 12 //std::cout << "Demonstrates Pyramid Lucas-Kanade optical flow." << std::endl; 13} 14 15//引数:[board_w], [board_h], [intrinsics.xml], [checker_image] 16//[board_w]:チェスボードの横のマス数 17//[board_h]:チェスボードの盾のマス数 18//[intrinsics.xml]:カメラ定数とかが入ってるファイル 19//[checker_image]:入力画像 20int main(int argc, char *argv[]){ 21 22 //argcはプログラムの引数の数 23 //./bird image.jpgで実行したとしたらargv[0] = bird,argv[1] = image.jpgでargcは2 24 if(argc != 5){ 25 std::cout << "\nERROR: too few parameters\n"; 26 //help(argv); 27 return -1; 28 } 29 30 //atoiは文字列を数値に変換 31 int board_w = atoi(argv[1]); 32 int board_h = atoi(argv[2]); 33 int board_n = board_w * board_h; 34 cv::Size board_sz = cv::Size2i(board_w, board_h); 35 //cv::Size board_sz(board_w, board_h); 36 //読み込みでファイルを開く 37 cv::FileStorage fs(argv[3], cv::FileStorage::READ); 38 cv::Mat intrinsic, distortion; 39 40 fs["camera_matrix"] >> intrinsic; 41 fs["distortion_coefficients"] >> distortion; 42 if(!fs.isOpened() || intrinsic.empty() || distortion.empty()){ 43 std::cout << "Error: Couldn't load intrinsic parameters from " 44 << argv[3] << std::endl; 45 return -1; 46 } 47 fs.release(); 48 49 cv::Mat gray_image, image, image0 = cv::imread(argv[4], 1); 50 if(image0.empty()){ 51 std::cout << "Error: Couldn't load image" << argv[4] << std::endl; 52 return -1; 53 } 54 55 //画像の歪みを補正する 56 cv::undistort(image0, image, intrinsic, distortion, intrinsic); 57 //入力画像、出力画像、グレーにする定数 58 cv::cvtColor(image0, gray_image, cv::COLOR_BGR2GRAY); 59 60 //その平面上のチェスボードを得る 61 std::vector<cv::Point2f> corners; 62 //チェスボードの内側コーナー位置を求める 63 bool found = cv::findChessboardCorners( 64 image, 65 //内側コーナーの個数 66 board_sz, 67 //コーナーの出力配列 68 corners/*, 69 //白黒画像に変換する際に固定閾値の代わりに適応的閾値を利用 70 //輪郭抽出の際の誤った四角を除外するための基準追加(あると逆に上手くいかない) 71 cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FILTER_QUADS*/); 72 if(!found){ 73 std::cout << "Couldn't acquire checkerboard on " << argv[4] 74 << ", only found " << corners.size() << " of " << board_n 75 << " corners\n"; 76 return -1; 77 } 78 //これらのコーナーをサブピクセルの精度で得る 79 std::vector<std::vector<cv::Point2f>> img_points; 80 cv::Mat src_gray = cv::Mat(image.size(), CV_8UC1); 81 cv::cvtColor(image, src_gray, cv::COLOR_BGR2GRAY); 82 cv::find4QuadCornerSubpix(src_gray, corners, cv::Size(3,3)); 83 cv::drawChessboardCorners(image, board_sz, corners, found); 84 img_points.emplace_back(corners); 85 86 87 //画像と物体の点を得る 88 //物体の点(r,c) 89 //(0, 0), (board_w-1, 0), (0, board_h-1), (board_w-1, board_h-1) 90 //これはコーナーがcorners[r*board_w + c]であることを意味するらしい 91 92 cv::Point2f objPts[4], imgPts[4]; 93 objPts[0].x = 0; objPts[0].y = 0; 94 objPts[1].x = board_w - 1; objPts[1].y = 0; 95 objPts[2].x = 0; objPts[2].y = board_h - 1; 96 objPts[3].x = board_w - 1; objPts[3].y = board_h - 1; 97 imgPts[0] = corners[0]; 98 imgPts[1] = corners[board_w - 1]; 99 imgPts[2] = corners[(board_h - 1) * board_w]; 100 imgPts[3] = corners[(board_h - 1) * board_w + board_w - 1]; 101 102 103 //点をB,G,R,YELLOWの順で描画する 104 cv::circle(image, imgPts[0], 9, cv::Scalar(255, 0, 0), 3); 105 cv::circle(image, imgPts[1], 9, cv::Scalar(0, 255, 0), 3); 106 cv::circle(image, imgPts[2], 9, cv::Scalar(0, 0, 255), 3); 107 cv::circle(image, imgPts[3], 9, cv::Scalar(0, 255, 255), 3); 108 109 //発見したチェスボードを描画する 110 cv::drawChessboardCorners(image, board_sz, corners, found); 111 cv::imshow("Checkers", image); 112 cv::imwrite("./apps/bird/Checkers.png", image); 113 114 //ホモグラフィを求める 115 116 cv::Mat H = cv::getPerspectiveTransform(objPts, imgPts); 117 118 //このビューの高さzをユーザーが調整できるようにする 119 double Z = 1; 120 cv::Mat birds_image = cv::Mat::zeros(HEIGHT + 100, WIDTH + 100, CV_8UC3); 121 //Escキーで止まる 122 for(;;){ 123 H.at<double>(2, 2) = Z; 124 //ホモグラフィを用いて再マッピングする 125 126 cv::warpPerspective( 127 image, 128 birds_image, 129 //変換配列 130 H, 131 //出力画像の配列 132 birds_image.size(), 133 cv::WARP_INVERSE_MAP | cv::INTER_LINEAR, 134 cv::BORDER_CONSTANT, 135 //境界を黒で埋める 136 cv::Scalar::all(0) 137 ); 138 139 cv::imshow("Birds_Eye", birds_image); 140 int key = cv::waitKey() & 255; 141 if(key == 'u') Z += 0.5; 142 if(key == 'd') Z -= 0.5; 143 if(key == 27) break; 144 } 145 146 cv::imwrite("./apps/bird/Birds_Eye.png", birds_image); 147 // cv::moveWindow("./apps/bird/Birds_Eye.png", 3000, 3000); 148 149 //回転と平行移動ベクトルを表示 150 std::vector<cv::Point2f> image_points; 151 std::vector<cv::Point3f> object_points; 152 for(int i = 0; i < 4; ++i){ 153 image_points.push_back(imgPts[i]); 154 object_points.push_back( 155 cv::Point3f(objPts[i].x, objPts[i].y, 0) 156 ); 157 } 158 159 cv::Mat rvec, tvec, rmat; 160 cv::solvePnP( 161 //オブジェクト座標系の3次元座標系 162 object_points, 163 //画像座標系の2次元座標点 164 image_points, 165 //カメラ行列 166 intrinsic, 167 //最初に歪みを補正したので歪み係数はゼロになる 168 cv::Mat(), 169 //回転ベクトルを出力 170 rvec, 171 //平行移動ベクトルを出力 172 tvec 173 ); 174 175 cv::Rodrigues(rvec, rmat); 176 177 //出力と終了 178 std::cout << "rotation matrix: " << rmat << std::endl; 179 std::cout << "translation vector: " << tvec << std::endl; 180 std::cout << "homography matrix: " << H << std::endl; 181 std::cout << "inverted homography matrix: " << H.inv() << std::endl; 182 183 return 1; 184 185} 186
自分のやりたいのは、この元の画像を回転せずにそのままの向きで鳥瞰図にすることです。
また、本に載っていた鳥瞰図取得の結果では、ウィンドウの下の真ん中あたりからから上に画像が広がっていくような鳥瞰図になっていました。
##特に知りたいこと
ホモグラフィを求めるための座標(objPts,imgPts)が間違っているのではないかと考えています。ですが、本のサンプルコードに書いてあるようにその座標がどうしてそう求められるのか理解していません。どのような考え方でこのobjPtsとimgPtsがこの求め方で出るのか教えていただきたいです。

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/08/23 01:41 編集
2021/08/23 01:50 編集
2021/08/23 01:55
2021/08/23 05:25
2021/08/23 05:40
2021/08/23 06:38 編集
2021/08/23 06:12
2021/08/23 07:47 編集
2021/08/23 07:46
2021/08/23 08:06 編集
2021/08/23 08:12
2021/08/23 08:16