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

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

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

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenCV

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

C++

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

Q&A

解決済

3回答

3269閲覧

OpenCvのRemap()の引数について

trickster

総合スコア14

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenCV

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

C++

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

0グッド

0クリップ

投稿2018/08/01 11:31

編集2018/08/01 16:42

前提・実現したいこと

C# + OpenCv 2.4.6 + OpenCvSharpを利用して「チェスパターンを読み込み、歪みのないチェスパターン画像に変換」しようとしています。
0. チェスパターン画像を読み込み、交点の座標を取り出す
0. 撮像された交点の位置から、それぞれの交点に対応する理想的な表示位置を算出
0. Remap()で元のチェスパターン画像から歪みのないチェスパターン画像を生成。

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

Remap()の第3、4引数 (map1, map2) をどう生成すれば良いか判らず困っています。
コードというより、引数の意味とOpenCvに生成のための関数が用意されているか教えて頂ければ幸いです。

※当該引数について、ドキュメントでは
map1 – 型 CV_16SC2 , CV_32FC1 あるいは CV_32FC2 である座標点 (x,y) ,または単なる値 x の1番目のマップ.高速化のために浮動小数点表現から固定小数点表現に変換する方法については, convertMaps() を参照してください
map2 – 型 CV_16UC1 , CV_32FC1 あるいは none(map1 が (x,y) である場合は空のマップ) である値 y の2番目のマップ
と記述されているのですが、理解できません。

該当のソースコード

C#でのソースコード該当部分です。

C#

1 2/// <summary>ファイルから読み出したチェスパターンの点群とその理想的な位置から画像の歪みを変換する</summary> 3/// <param name="fn">チェスパターン画像ファイルパス</param> 4/// <returns>成否</returns> 5private bool AnalyzeCheckImages2( string fn ) 6{ 7 try 8 { 9 var confCol = _config.PtnCol; // チェスパターン交点数(列) 10 var confRow = _config.PtnRow; // チェスパターン交点数(行) 11 var cornerCount = confCol * confRow; // チェスパターン交点総数 12 var corners = new CvPoint2D32f[cornerCount]; 13 var pattern_size = Cv.Size(confCol, confRow); 14 15 16 // チェスパターンを読み込み 17 using (var ipl = new IplImage(fn)) 18 using (var src_gray = Cv.CreateImage(Cv.GetSize(ipl), BitDepth.U8, 1)) 19 { 20 int cCount; 21 // 読み込んだ(ゆがんだ)チェスパターン画像の交点座標群を取得する 22 var found = Cv.FindChessboardCorners(ipl, pattern_size, out corners, out cCount); 23 24 // 画像上の交点座標群(corners)から、対応する理想的な座標群を生成する。 25 var targetPoss = CreateTargetPoss(corners, confCol, confRow ); 26 27 // Remap()でゆがんだ元画像を、綺麗な形にする 28 using (var dst_ipl = new IplImage(ipl.Size, ipl.Depth, ipl.NChannels)) 29 { 30 // ! Map1, Map2はどう生成すれば良い??(多分、corners, targetPosから生成できる?) 31 32 Cv.Remap( ipl, dst_ipl, Map1, Map2 ) ; 33 34 // この時点でdst_iplには綺麗なチェスパターンが欲しい。 35 } 36 } 37 } 38 catch (Exception ex) 39 { 40 MessageBox.Show(String.Format("例外が発生 Message={0}, Stack={1}", ex.Message, ex.StackTrace)); 41 return false; 42 } 43 return false; 44} 45 46 47/// <summary>理想的な表示位置(群)を生成します</summary> 48/// <param name="cPos">コーナー位置群</param> 49/// <param name="MaxCol">コーナーカラム数</param> 50/// <param name="MaxRow">コーナー列数</param> 51/// <returns>理想的なマッピング</returns> 52private CvPoint2D32f[] CreateTargetPoss(CvPoint2D32f[] cPos, int MaxCol, int MaxRow ) 53{ 54 try 55 { 56 // 中央の位置と(その右側の点から割り出した)間隔をもとに、理想的な表示位置の点群を生成する 57 var centerCol = MaxCol / 2; 58 var centerRow = MaxRow / 2; 59 var center = cPos[centerCol + centerRow * MaxCol]; 60 var right = cPos[centerCol + centerRow * MaxCol + 1]; // 中央の右隣 61 var len = Math.Sqrt((center.X - right.X) * (center.X - right.X) + (center.Y - right.Y) * (center.Y - right.Y)); 62 var list = Enumerable.Range(0, MaxRow).SelectMany(yy => Enumerable.Range(0, MaxCol).Select(xx => new { XX = xx, YY = yy }).Select(p => new CvPoint2D32f(center.X + (p.XX - centerCol) * len, center.Y + (p.YY - centerRow) * len))); // 理想位置 63 return list.ToArray(); 64 } 65 catch (Exception ex) 66 { 67 MessageBox.Show(String.Format("例外が発生 Message={0}, Stack={1}", ex.Message, ex.StackTrace)); 68 return null; 69 } 70} 71 72 73### 補足 74 75map1とmap2の意味については判りました。  76歪み補正マップと呼ばれ、入力画像の任意のピクセルがどの位置に移動すれば良いかを示しており、map1(x座標用)、map2(y座標用)と分かれているようです。 77問題は、これが画像サイズ分・各ピクセル毎の情報ということです。 78交点の移動前・後の座標が判っているので、全ピクセル分補間すれば、全ピクセルが計算できるとは思うのですが、これを算出するような関数を見つけることができません。 79 80なお、calibrateCamera()undistort()による補正は キャリブレーション画像が1枚ではできないと聞いているので、アプローチからは外して考えています。

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

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

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

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

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

yohhoy

2018/08/03 05:51 編集

calibrateCamera()はキャリブレーション画像の枚数に関わらず実行可能だったと思います。精度の良いカメラパラメータ推定には、複数のキャリブレーション画像が必要ですが、1枚でもそれなりに求まりはします。(calibrateCameraのflag指定で一部パラメータの推定を止める/強い仮定を置く必要があるかも) remap()と組み合わせる場合はinitUndistortRectifyMap()が提供されます。
trickster

2018/08/03 13:49

情報、ありがとうございます。 キャリブレーション画像は複数枚必要(=1枚では不可)という情報を鵜呑みにしていて、試していませんでした。 「(calibrateCameraのflag指定で一部パラメータの推定を止める/強い仮定を置く必要があるかも) 」の部分がキモになのかもしれませんね。トライしてみます。
trickster

2018/08/03 18:24

試してみたところ、1枚でもcalibrateCamera()+undistort()の組み合わせで、実行・変換できました。 私の思い込みで皆さんにご迷惑をかけてしまったようです。 もっとも、場合によっては、1枚ではダメな(精度が出ない)ケースがあるのかもしれませんが。 また、フラグについてはいくつか指定してみましたが、無い場合との変化は見られませんでした。 本来ならば、yohhoyさんにベストアンサーをつけるべきなのでしょうが、「回答」側に表示されていないためできませんでした。 初めての投稿でよくわからず申し訳ありません。
guest

回答3

0

大昔にカメラ校正系の論文で,
「内部パラメータが欲しいんじゃなくて,歪補正結果画像だけが欲しいんなら,
【撮影画像上の点群→理想的な点群】のずれ量を,スプライン局面か何かで全画素位置に対して
補間してやればいいんじゃねーの?」
的なのを見たことがある覚えがあるのですが,探せませんでした.

今回のケースでも同じような考え方で「チェスパターンの内部の画素群は」ある程度補間できるかもしれませんが,パターンの外側が補外になるため問題になりそうです.

カメラの歪がどの程度あるのかにもよりますが,もしも「ぱっと見,歪んでいることがわからない程度」であれば,例えば,(歪が無いものと仮定して)平面射影行列とかを解けばどうでしょうか.

投稿2018/08/03 04:22

fana

総合スコア11652

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

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

trickster

2018/08/03 13:39

私もfanaさんが昔見られたような論文とかを探しているのですが、安易に「OpenCvにもあるのでは」と思い探していた次第です。 unmap()はまさにそのためのメソッドですね。 最低限、チェスパターン内部領域だけでも良いのですが、それすら実装はかなり面倒ですよね・・。 カメラのゆがみ具合は「どの程度か判らない」前提で考えています。
fana

2018/08/03 15:05 編集

特定のカメラが手元にあるのではなくて,一般的なアルゴリズムを作りたい側の話ですか. 撮影状況などがわかりませんが,他の方がコメントされているように,まずは画像1枚でもCVのカメラ校正に食わせて様子をみるとよいかもしれません. (無理やりCVの関数使うよりもむしろ適当になんちゃって校正を自前ででっちあげた方が調整面の小回りが利いてよいかも?) 広角~魚眼なら別ですが,一般的な,画像の縁あたりに直線を写すと「ちょっと曲がってるかな」くらいのカメラであれば,とりあえず平面射影行列(これはCVに求める関数があったハズ)でCoarseな外部パラメタ推定にはなるんじゃないかと思います. 結果画像を「チェスパターンがカメラに正対している形の絵」にするのであれば,役に立つかもしれません. 歪側については,点の座標対応をオプティカルフローだと見なせば,farnebackの方法(フロー場を2次関数に近似して解く感じだったかと)みたいな感じで点の周囲のフローをある程度補間できるかも? (farnebackの手法はCVにあり,CVのリファレンスから論文のタイトルとかがわかります.とはいえ,読むのはとても大変ですが……)
fana

2018/08/03 15:12

> 最低限、チェスパターン内部領域だけでも良いのですが 乱暴ですが,絵作りの方法としては「画像のごく狭い範囲であれば歪の影響をほぼ無視できる」という仮定の元で,チェスパターンの一部ずつ(例えば近隣4点の範囲とか),何か適当な変換(アフィン変換とか射影変換とか)をかけていく,という手もあるかもしれません. (「結果のつなぎ目を滑らかにする手段が必要」という新たな問題が生じるかもしれませんが)
trickster

2018/08/03 16:47

適当な対応が見つからない場合には、分割しての変換にチャレンジするかもしれません。(つなぎ目の対応はうまくいく自信がありません・・)
guest

0

私的に理解しやすく思ったのが石立氏の17番目。リンク内容

投稿2018/08/01 11:55

MasahikoHirata

総合スコア3747

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

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

trickster

2018/08/01 14:36

早速の回答、ありがとうございます。リンクの変換についての説明は丁寧で判りやすかったです。(Remapに関してはないようでした) 質問からは読みにくかったと思うのですが、キャリブレーションは1枚(その代わり、撮像対象位置は固定されている)しかなく、リンク先の方法は採れないためRemap()ならばどうかと考えた次第です。 入力条件+Remap()でできそうもなければ、リンク先の方法でできないかチャレンジしてみます。 探しているそのものではありませんでしたが、知見を得られ感謝します。
MasahikoHirata

2018/08/01 14:59

石立氏はfacebookでも、たまにopencvやpythonについて書かれておられ、渡しもフォローしてます。
trickster

2018/08/03 13:31

立石さんの方は詳しく、後者「カメラ校正」の方はやさしい説明ですね。 「カメラ校正」では「最低でも10枚のテストパターンが必要」との記述がありました。 やはりこの方法(calibrateCamera()メソッド)では1枚のテストパターンでのキャリブレーションは不可と考えるべきなのでしょうね。 ありがとうございました。
guest

0

自己解決

yohhoyさんより、calibrateCamera()は1枚でも実行できるのではとご指摘をいただき、試してみたところ確かに実行できました。 被写体が2次元面で固定されている私の例では複数枚は必要ないのかもしれません。
「calibrateCamera()が1枚では実行できない」前提の元での質問でしたので、Remap()を直接使用する方法は不明のままではありますが「解決」とさせて頂きます。
私の思い込みで、アイディアを下さった皆様には申し訳ありませんでした。
なお、結果的には CalibrateCamera() + Undistort()の組み合わせでコードすることになると思いますので、MasahikoHirata さんをベストアンサーにさせて頂きます。
また、私の示した条件下を正確に理解してアイディアを下さった fana さん、ありがとうございました。

投稿2018/08/03 18:40

trickster

総合スコア14

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問