

OpenCVとアナログカメラを使用したプログラムを作成している際に「アクセス違反」のエラーが発生してしまいます．  
マルチスレッドでプログラミングをしており，1つ目のスレッドでカメラから取得した画像をcv::Matに変換しています．この画像を2つ目のスレッドで画像処理を行おうとしています．

<画像を取得しているスレッド>

[code]

    cv::Mat frame;
    DWORD WINAPI ImageThread(LPVOID lpData)
    {   
        while (!lpd->bEnd){
    
            if (mJpegData != nullptr&&mJpegSize > 0) {
                std::vector<unsigned char> tmp(mJpegData, mJpegData + mJpegSize);
                frame = cv::imdecode(tmp, cv::IMREAD_COLOR);
                cv::imwrite("img_debug.bmp", frame);
            }
        }
        return 0;
    }
    
[/code]

<画像をコピーしているスレッド>

[code]

    DWORD WINAPI ConThread(LPVOID lpData)
    {
        cv::Mat img;
    
        while (!lpd->bEnd){
            if (!frame.empty) {
                img = frame.clone();  //ここをコメントアウトするとエラーは発生しない
            }
        }
    }
    
[/code]

OpenCVのバージョンは3.3を使用しております．  
どなたか解決法を教えていただけないでしょうか．


CC BY-SA 3.0
2018-03-26T07:59:19.253
42657
2018-03-27T12:53:18.730
2018-03-26T12:55:20.737
4236
19825
question
c++ opencv マルチスレッド
OpenCVのcloneについて


>
[code]

>     frame = cv::imdecode(tmp, cv::IMREAD_COLOR);
>  
[/code]

この行で[cv::Mat::operator=()](https://docs.opencv.org/3.3.0/d3/d63/classcv_1_1Mat.html#aed1f81fe7efaacc2bd95149cdfa34302)が呼ばれます。

> Before assigning new data, the old data is de-referenced via Mat::release.

と説明されている通り、`frame`の保持していたデータは解放されます。別スレッドで`frame.clone()`により読み出していればエラーになるのも当然です。

排他処理を挿入することで解決できますが、ロック範囲をどうするか、また`frame`変数以外にも排他すべき項目がないか、検討することをお勧めします。

<画像を取得しているスレッド>

[code]

    cv::Mat frame;
    cv::Mutex mutex;
    DWORD WINAPI ImageThread(LPVOID lpData)
    {   
        while (!lpd->bEnd){
    
            if (mJpegData != nullptr&&mJpegSize > 0) {
                std::vector<unsigned char> tmp(mJpegData, mJpegData + mJpegSize);
                cv::AutoLock lock(mutex);
                frame = cv::imdecode(tmp, cv::IMREAD_COLOR);
                cv::imwrite("img_debug.bmp", frame);
            }
        }
        return 0;
    }
    
[/code]

<画像をコピーしているスレッド>

[code]

    DWORD WINAPI ConThread(LPVOID lpData)
    {
        cv::Mat img;
    
        while (!lpd->bEnd){
            cv::AutoLock lock(mutex);
            if (!frame.empty) {
                img = frame.clone();
            }
        }
    }
    
[/code]

* * *

>
> 画像をコピーしているスレッドで「if(!frame.empty())」を行っているのですが，このif文と「img=frame.clone()」の間でframeに定義されない（不定の）タイミングが発生する可能性がある（発生してしまった）ためにエラーが出てしまうという認識でよろしいでしょうか．

「間」のみならず`frame.clone()`実行中でも、別スレッドで`Mat::release`によりメモリ解放されてしまえばアクセス違反が発生します。C++言語ではオブジェクトがGC管理されているわけではないので、他言語によくある「実行中だから解放されない」といった保証はありません。


CC BY-SA 3.0
2018-03-26T12:54:53.867
42660
2018-03-27T12:53:18.730
2018-03-27T12:53:18.730
4236
4236
42657
answer