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

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

ただいまの
回答率

90.51%

  • C++

    4188questions

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

  • OpenCV

    1432questions

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

OpenCVにおけるパターンマッチングについて

受付中

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 3,227

TTR470000

score 2

前提・実現したいこと

現在、OpenCVとC++でDICひずみ計測システム(デジタル画像相関)を作っています。プログラミング初心者です。よろしくお願い致します。

まず、このシステムの原理ですが、変形する対象を画像からその変形量を求めるというものです。
CCDカメラから取り込まれた動画像におきまして、対象の負荷変形前後の画素の小集合(例えば30×30pixel)で比較、パターンマッチングしその小集合がどこに変位したかを画像全体でループ処理することで試験片の変形を計測するというものです。
イメージ説明

今、行っているのは全画素に対して順番にアクセスし、アクセスした画素の周りで画素の集合(30×30pixelのサブセット)をテンプレートとしそれを画像全体にマッチング。マッチングが終わるとすぐとなりの画素にアクセスしサブセットを作ってテンプレートマッチング・・・を繰り返す部分です。

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

実行しますと、途中まではうまく作動しているようですがある段階から(0,0) score=1 がずっと出力されてしまいます。

該当のソースコード

c++

include <iostream>
include <vector>   
int main(int argc, char *argv[])
{
cv::Mat src_img = cv::imread("./lenna.png",CV_LOAD_IMAGE_GRAYSCALE);
if (!src_img.data) return -1;

cv::Mat result_img;

for( int y = 0 ; y < src_img.rows ; ++y ){

for( int x = 0 ; x < src_img.cols ; ++x ){
//unsigned char    *p = &src_img.at<unsigned char>(y, 0);

cv::Size patch_sie(30, 30);     //サブセットのサイズ
cv::Point2f  points( x, y);

cv::Mat dst_img;

cv::getRectSubPix(src_img, patch_sie, points, dst_img);        // 矩形領域ピクセル値をサブピクセル精度で取得

cv::Mat result_img;
cv::matchTemplate(src_img, dst_img, result_img, CV_TM_CCOEFF_NORMED);    // テンプレートマッチング

cv::Rect roi_rect(0, 0, dst_img.cols, dst_img.rows);   // 最大のスコアの場所を探す
cv::Point max_pt;
double maxVal;
cv::minMaxLoc(result_img, NULL, &maxVal, NULL, &max_pt);
roi_rect.x = max_pt.x;
roi_rect.y = max_pt.y;
std::cout << "(" << max_pt.x << ", " << max_pt.y << "), score=" << maxVal << std::endl;
// 探索結果の場所に矩形を描画
cv::rectangle(src_img, roi_rect, cv::Scalar(0, 0, 255), 3);
++x;

}
}
cv::namedWindow("search image", CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO);
cv::namedWindow("result image", CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO);
cv::imshow("search image", src_img);
cv::imshow("result image", result_img);
cv::waitKey(0);

}

試したこと

各画素にはポインタでアクセスしますが、画像の端まで行った時にサブセットが画像からはみ出すことになるので不具合が起きているのかなとは思っていますが、何が原因かわかりません。そもそも、この方法でのアプローチが合っているのでしょうか。

長文乱文たいへん失礼いたしました。
よろしくお願いいたします。

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

c++ VS2015 OpenCV3.1

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

0

内側のloopなんですが:

for( int x = 0 ; x < src_img.cols ; ++x ){ 
    ...
    ++x; 
  }

 
となってます。xは+2されちゃいますが、これでいいんですか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/06/28 15:20

    お疲れ様です。お返事をありがとうございます。

    なるほど、文末の ++x; は要らないですね。
    意図とずれていました。

    また、仮になのですが画素へのアクセスをひとつずつではなく、飛び飛びにすることは可能でしょうか。飛び飛びとは、画素へのアクセス→すぐ一つ隣の画素ではなくサブセット分(30pixel飛ばして)アクセスしていき画像全体を網羅するにはどのようにすればよいでしょうか・・・。

    ご教授頂けますと幸いです。
    よろしくお願い致します。

    キャンセル

  • 2016/06/28 17:19

    for( int x = 0 ; x < src_img.cols ; x += 30 ) でよくね?

    キャンセル

0

こんにちは。

変形前画像はたぶんsrc_imgと思いますが、変形後画像はどれでしょうか?

実行しますと、途中まではうまく作動しているようですがある段階から(0,0) score=1 がずっと出力されてしまいます。

src_imgに矩形を書き込んでますので、それが影響する筈です。

ところで、result_imgが2つ定義されてます。1つ目は使ってないようですので影響はないとは思いますが。

各画素にはポインタでアクセスしますが、画像の端まで行った時にサブセットが画像からはみ出すことになる

はみ出した時、何が起こるか判らない状態であれば、まずははみ出さないようにすることをお薦めします。
画像処理の動作は非常に理解しづらい動作をすることが多いので、混乱する要素はなるべく減らしておいた方が開発期間を短縮できます。低レベル画像処理は急がば回れです。

matchTemplate()関数が返却するresult_imgのサイズを確認しましょう。src_imgより小さいですよ。
ということは、src_imgと座標系が異なります。そのまま使うとうまく行きません。

そもそも、この方法でのアプローチが合っているのでしょうか。

考え方は間違っていないと思います。オプティカル・フローとも呼ばれる考え方の1つです。
しかし、特徴がないサブセットをサーチしてもうまく見つかるとは限りません。というか、普通は特長のない領域についてテンプレートマッチしてもでたらめな場所にマッチします。

ですので、特徴的な場所を抽出してそれがどこへ移動したのか何らかの方法でマッチングするのが一般的です。下記などが参考になると思います。
特徴点の検出と追跡
SIFT SURFを用いた特徴点マッチング
iOS / OpenCV 3.0 で画像の特徴点を検出する(AKAZE, SIFT, SURF, ORB)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/06/28 15:14

    お疲れ様です。お返事くださりありがとうございます。
     
     >変形前画像はたぶんsrc_imgと思いますが、変形後画像はどれでしょうか?
    なるほど、変形後の画像がありませんね・・・初歩的な事で申し訳ないです。

    最終的にやりたいことは、CCDカメラの1フレームごとの計測ですので次々と更新される新フレームが毎回の変形後の画像ということになります。

    この場合、変形前の画像(1枚目のフレーム)でのテンプレート作成→次のフレームでのマッチング→画像全体で終了し次第、次の新しいフレームで最初のテンプレートをマッチングを繰り返させる事になると思うのですが、最初のフレームでのテンプレートを保持したまま次のフレームを処理するにはどのようにすればよいでしょうか。


     >はみ出した時、何が起こるか判らない状態であれば、まずははみ出さないようにすることをお薦めします。

    こちらはROIを指定すればよいでしょうか。
    としますと、観測領域は
    for( int y = 0 ; y < src_img.rows-30 ; ++y ){
    for( int x = 0 ; x < src_img.cols-30 ; ++x ) //画像の端からサブセット分引いた領域

    でしょうか・・・

    初歩的な事でお手数かとは存じますがよろしくお願い致します。

    キャンセル

  • 2016/06/29 00:00

    > 最初のフレームでのテンプレートを保持したまま次のフレームを処理するにはどのようにすればよいでしょうか。

    単純に最初の画像を残しておけばよいと思います。

    しかし、一番最初のフレームをテンプレートとしていると、時間が経つうちに画像がかなり変わるのでマッチしなくなると思います。常に連続する2枚のフレームで変形検知することをお勧めします。
    この場合、常に2枚の画像を残しておき、新しく1枚取得した時にトコロテンのように押し出す感じで2枚の画像を切り替えます。

    > としますと、観測領域は
    > for( int y = 0 ; y < src_img.rows-30 ; ++y ){
    > for( int x = 0 ; x < src_img.cols-30 ; ++x ) //画像の端からサブセット分引いた領域
    > でしょうか・・・

    おしいっ。
    getRectSubPix()の仕様をよく見てください。切り取る矩形の【中心座標】を指定するよう記述されています。(x, y)=(0, 0)を中心とするサイズ30の矩形は、はみ出しますよ。

    キャンセル

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

  • C++

    4188questions

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

  • OpenCV

    1432questions

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