15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

OpenCVAdvent Calendar 2015

Day 12

OpenCVの初期化処理,終了処理

Last updated at Posted at 2015-12-11

この記事はOpenCV Advent Calendar 2015の12日目の記事です.

はじめに

この記事では,OpenCVの初期化処理,終了処理時に内部的に行われている処理について解説します.
以降,モジュール毎の初期化処理,終了処理時についてまとめます.
※筆者はWindowsをメインに確認しているため他のプラットフォームでは多少異なる可能性があります.

初期化処理

coreモジュール

全般

coreモジュールでは以下のような初期化処理が行われます.

  • CvType::CvTypeメソッドによる型情報登録(内部的にcvRegisterType関数がコールされる)
  • cv::__terminationの初期化(falseがセットされる)

後者は具体的にmodules/core/src/system.cppの下記処理で初期化が行われます.
cv::__terminationについては後述する終了処理の説明にてもう少し触れます.

namespace cv {
bool __termination = false;
}

並列処理フレームワーク関連

coreモジュールでは並列処理フレームワークの初期化も行われます.
OpenCVライブラリのビルド時に選択した並列処理フレームワークによって以下のような初期化が行われます.

| 並列処理フレームワーク | 処理 |
|:--|:--|:--|
| TBB | tbb::task_schedulerクラスのインスタンス生成 |
| Concurrency | SchedPtrクラスのインスタンス生成 |
| OpenMP | omp_get_max_threads関数の実行 |

imgcodecsモジュール

imgcodecsモジュールmodules/imgcodecs/src/loadsave.cppに下記のコードがあることからImageCodecInitializerで各種コーデックのデコーダー,エンコーダー初期化が行われます.

static ImageCodecInitializer codecs;
`
ImageCodecInitializerによるコーデックの初期化処理はmodules/imgcodecs/src/loadsave.cppにて実装されています.以下にその処理を抜粋します.

struct ImageCodecInitializer
{
    /**
     * Default Constructor for the ImageCodeInitializer
    */
    ImageCodecInitializer()
    {
        /// BMP Support
        decoders.push_back( makePtr<BmpDecoder>() );
        encoders.push_back( makePtr<BmpEncoder>() );

        decoders.push_back( makePtr<HdrDecoder>() );
        encoders.push_back( makePtr<HdrEncoder>() );
    #ifdef HAVE_JPEG
        decoders.push_back( makePtr<JpegDecoder>() );
        encoders.push_back( makePtr<JpegEncoder>() );
    #endif
    #ifdef HAVE_WEBP
        decoders.push_back( makePtr<WebPDecoder>() );
        encoders.push_back( makePtr<WebPEncoder>() );
    #endif

    // 中略

    std::vector<ImageDecoder> decoders;
    std::vector<ImageEncoder> encoders;
};

変数decodersには,現在使用しているOpenCVライブラリがサポートしているフォーマット(デコード処理)がvector配列として格納されます.vector配列への格納は上記コードのdecoders.push_backにあたります.

同様に変数encodersには,現在使用しているOpenCVライブラリがサポートしているフォーマット(エンコード処理)がvector配列として格納されます.vector配列への格納は上記コードのencoders.push_backにあたります.

デコード/エンコード処理

前述のdecodersencodersというvector配列が実際どのタイミングで使われるかというと,cv::imwrite,cv::imread関数の内部で参照されます.

具体的にはcv::imwrite,cv::imreadの内部で呼ばれるcv::findDecoder,cv::findEncoderにて目的のコーデックを処理できるDecoder,Encoderを検索する際に参照され,目的のDecoder,Encoderが見付かると後段の処理でこれらを用いてデコード/エンコード処理が行われます.

videoioモジュール

WITH_DSHOWWITH_MSMFを有効にした場合は,OpenCV初期化時にvideoInputクラスのインスタンスが生成され,videoInput libraryによってDirectShowもしくはMSMFの初期化が行われます.

また,WITH_FFMPEGを有効にした場合は,以下のシーケンスでFFMPEGの初期化が行われます.icvInitFFMPEGメソッドではopencv_ffmpeg.dll(64bitビルドの場合はopencv_ffmpeg_64.dll)をロードして,各種コールバック関数のセットも行います.


cv::VideoCapture::VideoCapture
 cv::VideoCapture::open
  cvCreateFileCapture
   cvCreateFileCapture_FFMPEG_proxy
    icvInitFFMPEG::Init
     icvInitFFMPEG::icvInitFFMPEG

highguiモジュール

cv::namedWindow関数を呼び出した場合,ウィンドウ描画に関する初期化処理が実行されます.

WITH_WIN32UIを有効にした場合は,以下のシーケンスでWNDCLASS初期化が行われます.


cv::namedWindow
 cvNamedWindow
  cvInitSystem
   RegisterClass

WITH_QTを有効にした場合は,以下のシーケンスでQtの初期化が行われます.


cv::namedWindow
 cvNamedWindow
  GuiReceiver::GuiReceiver
   icvInitSystem
    QApplication::instance

終了処理

coreモジュール

DLLオプションのエントリポイントであるDllMain関数にて,変数fdwReasonがDLL_THREAD_DETACHもしくはDLL_PROCESS_DETACHの場合に終了処理が行われます.DllMain関数については,MSDNを参照ください.

以下にOpenCVに実装されているDllMain関数を引用します.

extern "C"
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID lpReserved)
{
    if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
    {
        if (lpReserved != NULL) // called after ExitProcess() call
        {
            cv::__termination = true;
        }
        else
        {
            // Not allowed to free resources if lpReserved is non-null
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583.aspx
            cv::deleteThreadAllocData();
            cv::deleteThreadData();
        }
    }
    return TRUE;
}
#endif

上記の実装からもわかるように変数lpReservedが非NULLの場合は前述のcv::__terminationをtrueに設定することで二重解放を防止しています.一方で変数lpReservedがNULLの場合にはcv::deleteThreadAllocData,cv::deleteThreadDataを呼び出してリソースの解放を行います.

videoioモジュール

デストラクタ実行時にビデオキャプチャの終了処理が行われます.また,WITH_FFMPEGを有効にした場合はFFMPEGの終了処理が行われます.

おわりに

OpenCVの初期化処理,終了処理時に内部的に行われている処理について解説しました.
これらの振る舞いを頭の片隅に入れておくとデバッグ時に活用できるかもしれません.

備考

筆者は以下の環境で動作確認しました.

  • OpenCV 3.0.0
  • Windows 8.1 Pro(64bit)
  • Visual Studio 2013 Update5
15
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?