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

回答編集履歴

2

やってみたことを追加

2018/10/25 11:08

投稿

fana
fana

スコア12229

answer CHANGED
@@ -1,3 +1,99 @@
1
1
  OpenCVであれば,例えば,cv::remap()を使えばとりあえず達成はできそうです.
2
2
 
3
- 「元座標→射影変換→(通常の変換後座標)→さらに平行移動」という結果になるマッピングテーブルを自前で求めてやることになりますが.
3
+ 「元座標→射影変換→(通常の変換後座標)→さらに平行移動」という結果になるマッピングテーブルを自前で求めてやることになりますが.
4
+
5
+ ---
6
+
7
+ > とりあえず「今ある変換行列」で元画像の4隅の変換結果座標を調べれば,必要なオフセット量(や出力画像バッファのサイズ)がわかるでしょうから,その情報使って射影変換行列を作り直しちゃうとか.
8
+
9
+ これをやってみました.
10
+ ```
11
+ //何か謎の射影変換行列を返す
12
+ cv::Mat CreateSomeHomographyMat()
13
+ { //てきとーな変換を求めて返すよ
14
+ std::vector< cv::Point2f > SrcPoints;
15
+ SrcPoints.emplace_back( cv::Point2f(0, 0) );
16
+ SrcPoints.emplace_back( cv::Point2f(200, 0) );
17
+ SrcPoints.emplace_back( cv::Point2f(0, 200) );
18
+ SrcPoints.emplace_back( cv::Point2f(200, 200) );
19
+
20
+ std::vector< cv::Point2f > DstPoints;
21
+ DstPoints.emplace_back( cv::Point2f(-10, 12) );
22
+ DstPoints.emplace_back( cv::Point2f(155, -10) );
23
+ DstPoints.emplace_back( cv::Point2f(-50, 130) );
24
+ DstPoints.emplace_back( cv::Point2f(170, 155) );
25
+
26
+ return cv::findHomography( SrcPoints, DstPoints );
27
+ }
28
+
29
+ //main
30
+ int main(void)
31
+ {
32
+ //元画像
33
+ cv::Mat SrcImg = cv::imread( "Test.png" );
34
+ cv::imshow( "Src", SrcImg );
35
+
36
+ //------------------------------------
37
+ //(1)
38
+
39
+ //何か(既存の?)射影変換行列が与えられて…
40
+ cv::Mat M = CreateSomeHomographyMat();
41
+ //とりあえずてきとーなサイズの変換結果画像バッファを用意して変換したら…
42
+ cv::Mat ResultImg= cv::Mat::zeros( 200, 200, CV_8UC3 );
43
+ cv::warpPerspective( SrcImg, ResultImg, M, cv::Size(ResultImg.cols,ResultImg.rows) );
44
+ cv::imshow( "1stResult", ResultImg ); //元の絵の範囲が結果画像バッファに収まらない
45
+
46
+ //------------------------------------
47
+ //(2)
48
+
49
+ //元画像の四隅の変換結果画像を求めて,
50
+ //はみ出さないようにするのに必要なオフセット量と,結果画像バッファサイズを求める.
51
+ std::vector< cv::Point2f > SrcPoints;
52
+ SrcPoints.emplace_back( cv::Point2f(0, 0) );
53
+ SrcPoints.emplace_back( cv::Point2f(SrcImg.cols-1, 0) );
54
+ SrcPoints.emplace_back( cv::Point2f(0, SrcImg.rows-1) );
55
+ SrcPoints.emplace_back( cv::Point2f(SrcImg.cols-1, SrcImg.rows-1) );
56
+
57
+ std::vector< cv::Point2f > ResultPoints;
58
+ ResultPoints.reserve( 4 );
59
+ double MinX=0, MaxX=ResultImg.cols-1;
60
+ double MinY=0, MaxY=ResultImg.rows-1;
61
+ for( const auto &P : SrcPoints )
62
+ {
63
+ auto Src = cv::Matx<double,3,1>( P.x, P.y, 1 );
64
+ cv::Mat Dst = M * cv::Mat(Src);
65
+ double X = Dst.at<double>(0,0) / Dst.at<double>(2,0);
66
+ double Y = Dst.at<double>(1,0) / Dst.at<double>(2,0);
67
+ ResultPoints.emplace_back( cv::Point2f(X,Y) );
68
+
69
+ MinX = (std::min)( MinX, X );
70
+ MaxX = (std::max)( MaxX, X );
71
+ MinY = (std::min)( MinY, Y );
72
+ MaxY = (std::max)( MaxY, Y );
73
+ }
74
+ //結果バッファを必要なサイズで作り直す
75
+ //※行列の内容次第ではとんでもないサイズになるかもなので注意する必要があるが,とりあえずここでは何も考慮しない.
76
+ int NeedWidth = (int)( std::ceil( MaxX - MinX ) );
77
+ int NeedHeight = (int)( std::ceil( MaxY - MinY ) );
78
+ ResultImg= cv::Mat::zeros( NeedHeight, NeedWidth, CV_8UC3 );
79
+
80
+ //必要なぶんだけ結果をオフセットする形に射影変換行列を作り直してみる
81
+ double NeedOffsetX = ( MinX<0 ? -MinX : 0 );
82
+ double NeedOffsetY = ( MinY<0 ? -MinY : 0 );
83
+ for( auto &P : ResultPoints )
84
+ {
85
+ P.x += NeedOffsetX;
86
+ P.y += NeedOffsetY;
87
+ }
88
+ M = cv::findHomography( SrcPoints, ResultPoints );
89
+ cv::warpPerspective( SrcImg, ResultImg, M, cv::Size(ResultImg.cols,ResultImg.rows) );
90
+ cv::imshow( "2ndResult", ResultImg ); //元の絵の範囲が結果画像バッファに収まるハズ
91
+
92
+ //---
93
+ cv::waitKey();
94
+ return 0;
95
+ }
96
+ ```
97
+ 結果.
98
+ 1stResultは絵がはみ出している→2ndResultは収まっている
99
+ ![結果例](ffc8a4922d8f021e8afc40bdbf153e7a.png)

1

単語が抜けていた

2018/10/25 11:08

投稿

fana
fana

スコア12229

answer CHANGED
@@ -1,3 +1,3 @@
1
1
  OpenCVであれば,例えば,cv::remap()を使えばとりあえず達成はできそうです.
2
2
 
3
- 「元座標→射影変換→(通常の変換後座標)→さらに平行移動」という結果になるマッピングテーブルを自前でやることになりますが.
3
+ 「元座標→射影変換→(通常の変換後座標)→さらに平行移動」という結果になるマッピングテーブルを自前で求めてやることになりますが.