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

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

新規登録して質問してみよう
ただいま回答率
85.50%
OpenCV

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

C++

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

Q&A

2回答

9514閲覧

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

TTR470000

総合スコア8

OpenCV

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

C++

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

1グッド

0クリップ

投稿2016/06/27 06:25

###前提・実現したいこと
現在、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

mpyw👍を押しています

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

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

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

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

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

guest

回答2

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/27 08:31

Chironian

総合スコア23272

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

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

TTR470000

2016/06/28 06: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 ) //画像の端からサブセット分引いた領域 でしょうか・・・ 初歩的な事でお手数かとは存じますがよろしくお願い致します。
Chironian

2016/06/28 15: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の矩形は、はみ出しますよ。
guest

0

内側のloopなんですが:

C++

1 for( int x = 0 ; x < src_img.cols ; ++x ){ 2 ... 3 ++x; 4 }

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

投稿2016/06/27 07:57

episteme

総合スコア16614

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

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

TTR470000

2016/06/28 06:20

お疲れ様です。お返事をありがとうございます。 なるほど、文末の ++x; は要らないですね。 意図とずれていました。 また、仮になのですが画素へのアクセスをひとつずつではなく、飛び飛びにすることは可能でしょうか。飛び飛びとは、画素へのアクセス→すぐ一つ隣の画素ではなくサブセット分(30pixel飛ばして)アクセスしていき画像全体を網羅するにはどのようにすればよいでしょうか・・・。 ご教授頂けますと幸いです。 よろしくお願い致します。
episteme

2016/06/28 08:19

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問