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

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

ただいまの
回答率

88.32%

射影変換がうまくできない

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,641

_pumpkin

score 30

前提・実現したいこと

c++で射影変換をするプログラムを作っております。(Eigen導入)
できれば、opencv等のライブラリは導入しない方向です。

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

変換後の画像が変換したい四角形におさまらず、歪んだ画像になってしまいます。
元画像...256 * 256
青い四角が変換したい位置で、Aとかかれた図形が変換後の図形です。

該当のソースコード

//指摘された通りに内容を変更しました
void getSystem(POINTd* in,POINTd* out,double *ht) {//8個のパラメータを求める
    Matrix<double, 8 , 8> dATA;
    dATA<< in[0].x, in[0].y, 1,       0,       0, 0, -out[0].x * in[0].x, -out[0].x * in[0].y,
           in[1].x, in[1].y, 1,       0,       0, 0, -out[1].x * in[1].x, -out[1].x * in[1].y,
           in[2].x, in[2].y, 1,       0,       0, 0, -out[2].x * in[2].x, -out[2].x * in[2].y,
           in[3].x, in[3].y, 1,       0,       0, 0, -out[3].x * in[3].x, -out[3].x * in[3].y,
                 0,       0, 0, in[0].x, in[0].y, 1, -out[0].y * in[0].x, -out[0].y * in[0].y,
                 0,       0, 0, in[1].x, in[1].y, 1, -out[1].y * in[1].x, -out[1].y * in[1].y,
                 0,       0, 0, in[2].x, in[2].y, 1, -out[2].y * in[2].x, -out[2].y * in[2].y,
                 0,       0, 0, in[3].x, in[3].y, 1, -out[3].y * in[3].x, -out[3].y * in[3].y;
    dATA = dATA.inverse();
    for (int i = 0; i < 8; i++) {
        ht[i] = 0;
        for (int j = 0; j < 4; j++) {
            ht[i] +=
                dATA(i, j) * out[j].x;
        }
        for (int j = 0; j < 4; j++) {
            ht[i] +=
                dATA(i, j + 4) * out[j].y;
        }
    }
}

void draw(){//求めたパラメータから実際にイメージ(DIB)に描画する
        /* 変数の定義など */
    double ht[8] = { 0 };
    getSystem(pointin, pointout,ht);
    for(int x = 0;x < image_src.Width;x++){
        for(int y = 0;y < image_src.Height;y++){
            int x1 = (double)x * ht[0] + (double)y * ht[1] + ht[2] /
                ((double)x * ht[6] + (double)y * ht[7] + 1.0);
            int y1 = (double)x * ht[3] + (double)y * ht[4] + ht[5] /
                ((double)x * ht[6] + (double)y * ht[7] + 1.0);
            if (x1 > Width)x1 = 0;
            if (y1 > Height)y1 = 0;
            if (x1 < 0)x1 = 0;
            if (y1 < 0)y1 = 0;
            lpPixel_target[x1 + y1 * Width] = image_src.GetPixel(x,y);
        }
    }
}

試したこと

参考サイト:

http://yaju3d.hatenablog.jp/entry/2013/08/04/152524
http://mf-atelier.sakura.ne.jp/mf-atelier/modules/tips/program/algorithm/a6.html
ネットで調べる限り調べましたが、結果は変わりませんでした。

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

visualstudio 2015 c++
Eigen導入済み

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yohhoy

    2016/04/23 11:57

    「歪んだ画像」はどのように確認しましたか?また、画像幅image_src.Widthは何pixelですか?(DIBデータは4の倍数以外の扱いに癖があります)

    キャンセル

  • _pumpkin

    2016/04/23 15:44

    画像の青い四角が変換したい四角形で、'A'とかかれたのが実際のコードで作った変換後の画像です。

    キャンセル

回答 3

+4

getSystem関数の戻り値に、ローカル変数として関数内で定義した配列のポインタを返していますが、C/C++ではその方法は御法度です。getSystemから抜けたときにdATA2は破棄されるため、htで受け取ったポインタの指す場所には別の値で上書きされてしまった可能性があります。

呼び出し側で配列変数を定義し、そのポインタをgetSystem関数に渡して、そこに計算結果を格納するようにしてください。

こんな感じ

double* getSystem(POINTd* in,POINTd* out)
    ↓
void getSystem(POINTd* in,POINTd* out, double dATA2[])
// double dATA2[8] = { 0.0 }; と return dATA2; は不要なので削除
// draw関数の中
double ht[8] = { 0.0 };        // 呼び出し側で配列変数を定義
getSystem(pointin, pointout, ht);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/20 14:47

    その通りにやってみたのですが、結果は変わりませんでした。
    (visual studioだとローカルなポインタを返しても大丈夫?)

    キャンセル

  • 2016/04/20 18:50

    Visual Studioだとローカルなポインタを返して良いということはありません。

    結果が変わらないとなると、別のところに原因があるのかもしれませんね。射影変換についてはやったことがないので具体的にアドバイスすることはできないのですが、他の人が試せる形のコードを提示して、どのようにゆがんでいるのかを説明していただければ、その方面に詳しい人からのアドバイスをもらえるかもしれません。

    キャンセル

checkベストアンサー

0

x1y1計算時の分子がおかしいのでは?

部分式(double)x * ht[0] + (double)y * ht[1] + ht[2]を括弧でくくる必要があるかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/23 17:03

    できました!
    何時間も悩んでいたのに演算子の優先順位とは...
    本当にありがとうございます!!

    キャンセル

0

catsforepawさんが書かれた方法が安全で私もお勧めだと思いますが、どうしてもgetSystem()をポインタを返す関数にしたい場合、関数内でnewした変数を返すことで実現できます。

double dATA2[8] = { 0.0 }; 
   ↓
double* dATA2 = new double[8];


ただ、これだと呼び出し側でちゃんとdelete[]してやらないといけませんし、戻り値のポインタのNULLチェックもしなければいけないので、getSystem()を使う側も注意が必要になります。

上記の例はあくまでも「そういう方法もある」程度に解釈していただければと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る