[c++][opencv]cv::hconcatでの例外

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
purin52002
記事: 235
登録日時: 2年前
連絡を取る:

[c++][opencv]cv::hconcatでの例外

#1

投稿記事 by purin52002 » 2年前

こんにちは

opencvで画像と画像を水平方向に連結しようと思い、cv::hconcatという関数を使ったところ、例外が発生してしまいました。

コード:

cv::Mat Combine(const cv::Mat &x, const cv::Mat &y)
{
    cv::Mat ret;
    cv::hconcat(x, y, ret);//ここでハンドルされない例外が発生する
    return ret;
}
cv::hconcat関数を呼んでいる行で

0xC0000005: 場所 0x000001572172E000 への書き込み中にアクセス違反が発生しました。

という例外が発生します。

調べてみたところ、 0xC0000005 の主な原因が
メモリ領域外にアクセス、メモリ不足
らしく、

コード:

struct MatPair
{ 
    cv::Mat a,b;
};

std::vector<MatPair> array;

void Func()
{
    for(auto &i : array)
    {
        auto combined = Combine(i.a, i.b);
    }
    array.clear();
}

int main()
{
    arrayにMatPairを1追加
    Func();//例外なし

    arrayにMatPairを10追加
    Func();//例外でる

    arrayにMatPairを100追加
    Func();//例外でる
}
のようなコードを書くと、
arrayにMatPairをひとつだけ追加してhconcatを行っても例外は出ず、
arrayにMatPairを10個ほど追加してhconcatを行うと例外がでました。

このことから、メモリ不足が原因かと思われましたが、
arrayにMatPairを100個ほど追加してhconcatを行っても例外がでました。

メモリ不足が原因ならMatPairを追加している時点で例外が出るような気がします。

だから原因は範囲外アクセス、、、?いやけど、メモリ不足、、、、?

というわけでわからなくなってしまいました^p^

[hr]
配列にcv::Matのペアを保持し、そのMatのペアにcv::hconcatを使うとアクセス違反の例外が出ます。
原因がわかる方おりましたらお教えください<(_ _)>
オフトピック
合わせてこちらも確認してもらえるとうれしいです^p^
http://dixq.net/forum/viewtopic.php?f=3 ... 24#p146224
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^

アバター
usao
記事: 1547
登録日時: 6年前

Re: [c++][opencv]cv::hconcatでの例外

#2

投稿記事 by usao » 2年前

提示していない
> arrayにMatPairを10追加
等の部分が問題だったりしませんか?

↓で特に問題は起きないようなのですが.

コード:

int main()
{
	for( int i=0; i<10; ++i )
	{
		MatPair P;
		P.a.create( 10,10,CV_8UC1 );
		P.b.create( 10,10,CV_8UC1 );
		array.push_back( P );
	}

	std::cout << array.size() << std::endl;
	Func();
	std::cout << "finished" << std::endl;
	std::cin.ignore();
	return 0;
}

アバター
purin52002
記事: 235
登録日時: 2年前
連絡を取る:

Re: [c++][opencv]cv::hconcatでの例外

#3

投稿記事 by purin52002 » 2年前

返信ありがとうございます。

arrayに追加する部分が問題という可能性は大いにあります(既存の関数より、自作の関数を疑うほうが早いですよね^^;)

arrayに追加する部分は大まかに書いて以下のようになります。

コード:

struct MatPairPlus
{
    cv::Mat a, b;
    UTextureRendertarget2D *c, *d;
    MatPairPlus(const UTextureRendertarget2D *x, const UTextureRendertarget2D *y)
    {
        xからaを作る
        yからbを作る
    }
};

struct MyStruct
{
    MatPairPlus e, f;
}

void Add(MatPairPlus original_state, MatPairPlus transition_state)
{
    MatPairPlus original(original_state.c, original_state.d);
    MatPairPlus transition(transition_state.c, transition_state.d);
	
    array.push_back(MyStruct{original, transition});
}
最初の質問文で定義したMatPairをMatPairPlusと定義し直します。

今回ue4のテクスチャからcv::Matの画像を作成しようと思っています。
しかし、cv::hconcatの例外とは関係ない情報かと思いまして勝手に省きました。
混乱させてしまったら申し訳ないですorz

また、arrayに追加するのもMatPairPlusを更に構造体にしたMyStructになります。
arrayの方が変わることで、Func関数の中身も変わります。

コード:

void Func()
{
    for(auto &i : array)
    {
        auto e = i.e;
        auto f = i.f;
        auto combined_e = Combine(e.a, e.b);
        auto combined_f = Combine(f.a, f.b);
    }
    array.clear();
}
こちらが結構重要で、 e で Combine を行うと例外が出ることを確認できました。(もしかして f でも出るのかもしれないけど^p^)

私が真っ先に疑ったのがMatPairPlusのコンストラクタです。
しかし、こちらは正常(?)なようで、Add関数内で

コード:

void Add(MatPairPlus original_state, MatPairPlus transition_state)
{
    MatPairPlus original(original_state.c, original_state.d);
    MatPairPlus transition(transition_state.c, transition_state.d);
	
    array.push_back(MyStruct{original, transition});

    auto im_o = Combine(original.a, original.b);
    auto im_t = Combine(transition.a, transition.b);
    cv::imshow("o", im_o);
    cv::imshow("t", im_t);
    cv::waitKey();
}
のようにして画像が壊れていないかを確認したところ、例外が出ずにすべて表示されました。

しかし、Func関数内で e をCombineしようとすると例外が出てしまいます。

他に原因として何がありそうですか?^^;
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^

アバター
usao
記事: 1547
登録日時: 6年前

Re: [c++][opencv]cv::hconcatでの例外

#4

投稿記事 by usao » 2年前

> 今回ue4のテクスチャからcv::Matの画像を作成しようと思っています。
> しかし、cv::hconcatの例外とは関係ない情報かと思いまして勝手に省きました。

ue4のテクスチャの事はわかりませんが,
まず,このことが本当に関係ないのかどうかを切り分けてみてはいかがでしょうか?

MatPairPlusのコンストラクタの中で,引数テクスチャを無視してMatを適当にでっちあげたらどうなりますか?
(例えば,私のコードのように,適当に10x10サイズでcreateするとか)



・MatPairPlusにはメンバ変数にポインタc,dがあり,これはAdd()で参照されていますが,
 Addで参照されるタイミングにおいて,常に有効な値でしょうか?
 →無効な値である場合に,「xからaを作る」の処理がそのことを握りつぶしたりはしていませんか?

・「xからaを作る」という処理が
 テクスチャの画像データの内容をMatにコピーせずにメモリを共用する形になっていて,
 且つ,その後でテクスチャ側に解放的な処理が行われている とかそういうことは無いのでしょうか.

・cv::hconcat関数 の中までステップ実行して,例外の理由を特定できませんか?
 あるいは,OpenCVは「この引数だとあかん」とかいう場合にはその旨をコンソールに何か出力してたりしますが
 そういうのが出てないかどうかを見れませんか?
 (xとyが{同じデータタイプじゃないとか,画像の高さが同じではない,サポートしていないデータタイプだ}とかで失敗しているとか)

結城紬
記事: 42
登録日時: 2年前

Re: [c++][opencv]cv::hconcatでの例外

#5

投稿記事 by 結城紬 » 2年前

purin52002 さん
Unreal Engine は使ったことがないのですが、 TArray が任意のクラスを要素にすることに対応していないのではないでしょうか。
下の記事にそのような記述がありました。
http://historia.co.jp/archives/678
3-3.クラス型
TArrayは要素毎にサイズが違う場合には対応出来ません。また、メモリコピーによってデータの移動が行われるため、コンストラクタやデストラクタも呼び出されません。
C++ では、コンテナクラスは実装によって挙動が大きく異なる(そのためにたくさん実装がある)ので、選び方にはよほど慎重にならなければなりません。

アバター
purin52002
記事: 235
登録日時: 2年前
連絡を取る:

Re: [c++][opencv]cv::hconcatでの例外

#6

投稿記事 by purin52002 » 2年前

返信が遅れてしまい申し訳ありません。

usaoさん
  • MatPairPlusにはメンバ変数にポインタc,dがあり,これはAdd()で参照されていますが,Addで参照されるタイミングにおいて,常に有効な値でしょうか?
    一応常に有効になるように設計したつもりです。(あくまでつもりです^^;)
    c,dはMatPairPlusのコンストラクタを呼ぶために使用しています。
    コンストラクタの中ではNULLチェックをしているので、無効なポインタから画像は作られないはず、、、
    また、hconcatにて例外が発生した時点で変数をウォッチしたところ、正しい画像サイズは得られていました。(正しい画像かはわからないのですが、、、)
  • 「xからaを作る」という処理が、、、
    処理の一部を抜粋

    コード:

    テクスチャからカラーデータのポインタ FormatedImageData を作成
    
    テクスチャから縦のサイズ height を作成
    テクスチャから横のサイズ width を作成
    cv::Mat mat(height, width, CV_8UC3);
    
    for (int y = 0; y < height; ++y)
    {
        auto ptr = mat.ptr<cv::Vec3b>(y);
        for (int x = 0; x < width; ++x)
        {
            auto color = FormatedImageData[y * width + x];
    	ptr[x][0] = color.B;
    	ptr[x][1] = color.G;
    	ptr[x][2] = color.R;
        }
    }
    
    このようなコードなので、メモリを共有しているわけではなく、値をコピーしていると思います。
他にも幾つか提示されたアイデアが有りましたが実は解決できてしまいました^^;

usaoさんと結城紬さんに指摘されたところをまとめていじってからデバッグしたので、
確実に「お前が悪い!」という処理はちょっとわからなかったのですが、
おそらくTArrayが原因だと思われます。

調子こいてTArrayなんて使った私が悪かったようです^p^

[hr]
usaoさん
cv::hconcatに原因がある->提示するコードはopencv周りの処理+標準コンテナを使った疑似コードでいいかな、
と思ってしまった私が浅はかでしたorz
最初からちゃんと問題を説明したほうがよかったですね^^;
わざわざエラーチェックだったりなんだったりしてもらってすみません。
丁寧なアドバイスありがとうございました^^

結城紬さん
Unreal Engine 使ったことがないとのことでしたが、わざわざ調べてくれたんですね^^
ありがとうございます<(_ _)>
こちらのトピックではTArrayの話はしていなかったと思うので、別トピの方も確認してもらえたんですかね?
TArrayからstd::vectorに変更たところ、例外は出なくなりました。
また、(おそらくですが)デストラクタでの例外も出なくなりました。
重ねてお礼申し上げます<(_ _)>
c++初心者を自負しています。
質問者さんには今後私にプログラミングを教えてくれるようにやさしく丁寧に教えるつもりです。ぎぶあんどていく^p^
回答者さんには精一杯感謝します。ぎぶおんりー^p^

アバター
usao
記事: 1547
登録日時: 6年前

Re: [c++][opencv]cv::hconcatでの例外

#7

投稿記事 by usao » 2年前

オフトピック
提示コードで既に問題が起きない というのは想定外

返信

“C言語何でも質問掲示板” へ戻る