何が起こっているのかを理解するには、 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);
ことがわかっています。これは、 のコンテンツを にコピーしようとすることを意味しますが、この手順ではコピー コンストラクターがアクティブになり、先ほど説明したようにデータのハード コピーは作成されません。orig
src
cv::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 になったことを意味します。システムを設計するときは、このことを念頭に置いてください。幸運を。