15

私はopencvを初めて使用しますが、コーディングで最も簡単な操作の1つである関数への値の受け渡しに疑問があります。

これが私がやりたいことです、

  1. cv:Matたとえば、0から50までの値を使用してmain関数のaを初期化します。
  2. この行列を引数として関数に渡します。関数foo()は、行列内の各要素の値を単純に出力します。それでおしまい。

これらの行列が渡されるとき、渡されるのはヘッダーのみであり、実際のデータではないことを複数の場所で読んだことがあります。それでは、行列全体が渡されたかのように、呼び出された関数でこの行列の値を読み取るにはどうすればよいですか?

4

1 に答える 1

33

何が起こっているのかを理解するには、 C++ コンストラクター、より具体的にはコピー コンストラクターを調べる必要があります。

cv::Mat次のように、別の からを作成する場合cv::Mat:

cv::Mat a = cv::imread("huge.png", 1);
cv::Mat b = a;

オブジェクトのコピーを実行するために、のコピー コンストラクター(関数)cv::Matが呼び出されます。コピー手順で何が起こるかについて説明する前に、cv::Mat画像を格納するために使用されるため、より大きな画像はメモリ内で数百メガバイトを占有する可能性があることを認識しておく必要があります。したがって、上記の例で のコピー コンストラクターcv::Mat行うことは、 のヘッダー全体 (高さ、幅、深さ情報など) をaにコピーすることですが、 (数百 MB になる可能性がある)bのデータ/ピクセル全体をコピーする代わりに、aの元のデータを (ポインタを使用して) ポイントしますa

つまり、画像データ全体をコピーしないことは、最適化/パフォーマンスの決定です。

cv::Matここで、関数を呼び出してパラメーターとして渡す次のコードを考えてみましょう。

void do_something(cv::Mat src)
{
    // changing src pixels will be the same as changing orig pixels
}

int main()
{
    cv::Mat orig = cv::imread("huge.png", 1);
    do_something(orig);
    return 0;
}

関数にパラメーターを渡す方法を学習したことがある場合は、呼び出し によってパラメーターが値で渡されるdo_something(a);ことがわかっています。これは、 のコンテンツを にコピーしようとすることを意味しますが、この手順ではコピー コンストラクターがアクティブになり、先ほど説明したようにデータのハード コピーは作成されません。origsrccv::Mat

この問題の解決策は? あなたが書いていdo_something()て、の本当のコピーを作りたいだけならorig、新しいものを作成しcv::Matてメソッドを呼び出してcopyTo()ください:

void do_something(cv::Mat src)
{
    cv::Mat real_copy = src.copyTo();
    // operating on the data of real_copy will not affect orig
}

srcただし、実際のコピーを作成するために最大 100MB の呼び出しを行うと、別の最大 100MB のメモリが占​​有されることを覚えておいてcopyTo()ください。つまり、1 回の関数呼び出しで、プログラムが 100MB から 200MB になったことを意味します。システムを設計するときは、このことを念頭に置いてください。幸運を。

于 2012-06-13T16:49:20.793 に答える