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

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

ただいまの
回答率

88.63%

matlabやopencv+C++での画像処理において、マイナスの座標のバッファを確保することは可能でしょうか?

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,384

ttyy1101

score 18

画像に対して射影変換処理を行った際に、マイナス側(左側)に画像がはみ出してしまいます。
予め右側に平行移動させてから射影変換を行うしか回避方法はないのでしょうか。

それとも、マイナスの座標のバッファを確保すること、もしくはそれに似た処理を行うことは可能でしょうか?

今はmatlabを使っているので、よければmatlabでの方法を教えていただきたいです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • tiitoi

    2018/10/17 16:02

    Matlab はわかりませんが、OpenCV の場合、右側に平行移動させてから射影変換を行う必要があります。

    キャンセル

  • ttyy1101

    2018/10/18 11:10

    そうなんですね、ありがとうございます。

    キャンセル

  • fana

    2018/10/25 17:18

    「元画像を単純に右方向にずらした絵を作成してそれを変換元の画像として使う」ということを指しているのであれば,変換結果の絵の具合が変わってしまうと思うのですが,良いのでしょうか?(やりたいことは「変換結果の絵」を並行移動することなのでは…?)

    キャンセル

  • ttyy1101

    2018/10/25 17:23

    変換結果が変わってしまわないように変換パラメータを調整する必要があるので困っています。。

    キャンセル

回答 1

checkベストアンサー

+1

OpenCVであれば,例えば,cv::remap()を使えばとりあえず達成はできそうです.

「元座標→射影変換→(通常の変換後座標)→さらに平行移動」という結果になるマッピングテーブルを自前で求めてやることになりますが.


とりあえず「今ある変換行列」で元画像の4隅の変換結果座標を調べれば,必要なオフセット量(や出力画像バッファのサイズ)がわかるでしょうから,その情報使って射影変換行列を作り直しちゃうとか.

これをやってみました.

//何か謎の射影変換行列を返す
cv::Mat CreateSomeHomographyMat()
{    //てきとーな変換を求めて返すよ
    std::vector< cv::Point2f > SrcPoints;
    SrcPoints.emplace_back( cv::Point2f(0, 0) );
    SrcPoints.emplace_back( cv::Point2f(200, 0) );
    SrcPoints.emplace_back( cv::Point2f(0, 200) );
    SrcPoints.emplace_back( cv::Point2f(200, 200) );

    std::vector< cv::Point2f > DstPoints;
    DstPoints.emplace_back( cv::Point2f(-10, 12) );
    DstPoints.emplace_back( cv::Point2f(155, -10) );
    DstPoints.emplace_back( cv::Point2f(-50, 130) );
    DstPoints.emplace_back( cv::Point2f(170, 155) );

    return cv::findHomography( SrcPoints, DstPoints );
}

//main
int main(void)
{
    //元画像
    cv::Mat SrcImg = cv::imread( "Test.png" );
    cv::imshow( "Src", SrcImg );

    //------------------------------------
    //(1)

    //何か(既存の?)射影変換行列が与えられて…
    cv::Mat M = CreateSomeHomographyMat();
    //とりあえずてきとーなサイズの変換結果画像バッファを用意して変換したら…
    cv::Mat ResultImg= cv::Mat::zeros( 200, 200, CV_8UC3 );
    cv::warpPerspective( SrcImg, ResultImg, M, cv::Size(ResultImg.cols,ResultImg.rows) );
    cv::imshow( "1stResult", ResultImg );    //元の絵の範囲が結果画像バッファに収まらない

    //------------------------------------
    //(2)

    //元画像の四隅の変換結果画像を求めて,
    //はみ出さないようにするのに必要なオフセット量と,結果画像バッファサイズを求める.
    std::vector< cv::Point2f > SrcPoints;
    SrcPoints.emplace_back( cv::Point2f(0, 0) );
    SrcPoints.emplace_back( cv::Point2f(SrcImg.cols-1, 0) );
    SrcPoints.emplace_back( cv::Point2f(0, SrcImg.rows-1) );
    SrcPoints.emplace_back( cv::Point2f(SrcImg.cols-1, SrcImg.rows-1) );

    std::vector< cv::Point2f > ResultPoints;
    ResultPoints.reserve( 4 );
    double MinX=0, MaxX=ResultImg.cols-1;
    double MinY=0, MaxY=ResultImg.rows-1;
    for( const auto &P : SrcPoints )
    {
        auto Src = cv::Matx<double,3,1>( P.x, P.y, 1 );
        cv::Mat Dst = M * cv::Mat(Src);
        double X = Dst.at<double>(0,0) / Dst.at<double>(2,0);
        double Y = Dst.at<double>(1,0) / Dst.at<double>(2,0);
        ResultPoints.emplace_back( cv::Point2f(X,Y) );

        MinX = (std::min)( MinX, X );
        MaxX = (std::max)( MaxX, X );
        MinY = (std::min)( MinY, Y );
        MaxY = (std::max)( MaxY, Y );
    }
        //結果バッファを必要なサイズで作り直す
        //※行列の内容次第ではとんでもないサイズになるかもなので注意する必要があるが,とりあえずここでは何も考慮しない.
    int NeedWidth = (int)( std::ceil( MaxX - MinX ) );
    int NeedHeight = (int)( std::ceil( MaxY - MinY ) );
    ResultImg= cv::Mat::zeros( NeedHeight, NeedWidth, CV_8UC3 );

        //必要なぶんだけ結果をオフセットする形に射影変換行列を作り直してみる
    double NeedOffsetX = ( MinX<0   ?   -MinX   :   0 );
    double NeedOffsetY = ( MinY<0   ?   -MinY   :   0 );
    for( auto &P : ResultPoints )
    {
        P.x += NeedOffsetX;
        P.y += NeedOffsetY;
    }
    M = cv::findHomography( SrcPoints, ResultPoints );
    cv::warpPerspective( SrcImg, ResultImg, M, cv::Size(ResultImg.cols,ResultImg.rows) );
    cv::imshow( "2ndResult", ResultImg );    //元の絵の範囲が結果画像バッファに収まるハズ

    //---
    cv::waitKey();
    return 0;
}


結果.
1stResultは絵がはみ出している→2ndResultは収まっている
結果例

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/10/25 17:35

    回答ありがとうございます。試してみます。

    キャンセル

  • 2018/10/25 17:37 編集

    cv::findHomography()みたいに{入力画像上の座標N点 vs 出力画像上の座標N点}の対応関係から射影変換行列を求めているのであれば,単に出力側の座標をオフセットした状態で射影変換行列を求めればよいのですが.

    キャンセル

  • 2018/10/25 17:56

    とりあえず「今ある変換行列」で元画像の4隅の変換結果座標を調べれば,必要なオフセット量(や出力画像バッファのサイズ)がわかるでしょうから,その情報使って射影変換行列を作り直しちゃうとか.

    キャンセル

  • 2018/10/26 09:44

    わざわざコードまで書いて試していただき、大変感謝します。

    キャンセル

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

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

関連した質問

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

  • トップ
  • C++に関する質問
  • matlabやopencv+C++での画像処理において、マイナスの座標のバッファを確保することは可能でしょうか?