Speed-Up JPEG Encode/Decode Processing for OpenCV using libjpeg-turbo

Defoult JPEG Encoder/Decoder

OpenCVのJPEGのエンコード/デコード処理はlibjpegを利用して実装されています。
3rdpartyフォルダに外部ライブラリとしてlibjpegを含んでおり、通常このlibjpegをビルドして静的リンクしています。*1

*1 OpenCV 3.1ではlibjpeg ver.9が含まれています。

What is libjpeg-turbo?

libjpeg-turboは、libjpegの内部をSIMD命令で高速化したライブラリです。
通常のlibjpegに比べ2-6倍高速に動作、高度に最適化されているIntel IPP (Integrated Performance Primitives)ともほぼ同等の速度で動作します。
libjpeg-turboのAPIはlibjpeg互換のため、リンクするライブラリをlibjpeg-turboに差し替えるだけで、エンコード/デコード処理の高速化が狙えます。

How to build OpenCV with libjpeg-turbo

OpenCVにlibjpeg-turboを組み込むにはソースコードからビルドする必要があります。

1. How to build libjpeg-turbo

  1. アセンブラをインストールする
  2. libjpeg-turboは最適化されたアセンブリをアセンブルするためにNASMアセンブラを要求します。
    以下から最新のNASMをダウンロード、インストールします。

  3. ソースコードをダウンロードする
  4. GitHubからlibjpeg-turboの最新リリースのソースコードをダウンロードします。

  5. libjpeg-turboのプロジェクトを生成する
  6. CMakeでlibjpeg-turboのプロジェクトを生成します。
    [Ungrouped Entries]>[NASM]にNASMの実行ファイルのパスを指定します。
    (e.g. C:/Users/UserName/AppData/Local/bin/NASM/nasm.exe)

  7. libjpeg-turboをビルドする
  8. CMakeで生成されたソリューションをVisual Studioで開き、[ALL_BUILD]プロジェクトをReleaseビルドします。
    ビルドが成功すると「jpeg-static.lib」が生成されます。

  9. libjpeg-turboをインストールする
  10. [INSTALL]プロジェクトをビルドします。
    「C:/libjpeg-turbo64 (または、C:/libjpeg-turbo)」に必要なファイルがインストールされます。

2. How to build OpenCV with libjpeg-turbo

  1. ソースコードをダウンロードする
  2. GitHubからOpenCVのソースコードをダウンロードします。

  3. OpenCVのプロジェクトを生成する
  4. CMakeでOpenCVのプロジェクトを生成します。
    CMakeでは以下の設定をします。

    「JPEG_INCLUDE_DIR」「JPEG_LIBRARY」の項目は[Add Entry]ボタンを押して新規に追加します。「JPEG_INCLUDE_DIR」のタイプはPATH、「JPEG_LIBRARY」のタイプはFILEPATHです。
    「BUILD_JPEG」は3rdpartyに含まれるlibjpegをビルドして利用するオプションのため、ここではチェックを外します。
    「WITH_JPEG」はJPEGのサポートを有効にするオプションのため、チェックを入れます。

    • JPEG_INCLUDE_DIR C:/libjpeg-turbo64/include (または、C:/libjpeg-turbo/include)
    • JPEG_LIBRARY C:/libjpeg-turbo64/lib/jpeg-static.lib (または、C:/libjpeg-turbo/lib/jpeg-static.lib)
    • BUILD_JPEG ☐(uncheck)
    • WITH_JPEG ☑(check)
  5. OpenCVをビルドする
  6. CMakeで生成されたソリューションをVisual Studioで開き、[ALL_BUILD]プロジェクトをDebug、Releaseビルドします。

  7. OpenCVをインストールする
  8. [INSTALL]プロジェクトをビルドします。

Performance Test

OpenCVのJPEGバックエンドをlibjpegからlibjpeg-turboに差し替えることで、どれくらい高速化できるのかテストします。
lena(opencv\samples\data\lena.jpg)の画像を読み込み、メモリ上でJPEG形式にエンコードしたときの1枚あたりの処理速度を計測します。

Test Environment

以下の環境でテストしました。

  • Intel Core i7 4790 (3.60GHz)
  • DDR3-1600(PC3-12800) SDRAM (4GB*4 Dual-Channel)
  • Visual Studio 2015 (x64)
  • OpenCV 3.1.0
  • libjpeg-turbo 1.4.2

Test Code

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
 
// opencv-3.1.0/samples/gpu
#include "tick_meter.hpp"
 
#define TEST_COUNT 1000
 
int main( int argc, char *argv[] )
{
    // Build Information
    std::cout << cv::getBuildInformation() << std::endl;
 
    // Read Image (opencv\samples\data\lena.jpg)
    cv::Mat img = cv::imread( "lena.jpg", cv::IMREAD_UNCHANGED );
    if( img.empty() ){
        return -1;
    }
 
    // Destination Buffer and JPEG Encode Parameter
    std::vector<uchar> buf( img.rows * img.cols );
    std::vector<int> params = { cv::IMWRITE_JPEG_QUALITY, 95 };
 
    // Timer
    TickMeter tm;

    // Test
    for( int i = 0; i < TEST_COUNT; i++ ){
        tm.start();

        cv::imencode( ".jpg", img, buf, params );

        tm.stop();
    }
     
    std::cout << tm.getTimeMilli() / tm.getCounter() << "[ms]" << std::endl;
 
    return 0;
}

Test Result

libjpeg-turboを組み込んだOpenCVはだいたい3.5倍高速に処理できています。
これは、libjpeg-turboのパフォーマンスレポートからみても妥当な結果だと思います。
今回はcv::imencode()でメモリ上で処理しましたが、cv::imwrite()でファイルに書き出すときも同様に高速化が期待できます。
また、デコード処理も高速化できると思われます。

Backend Time
libjpeg v9 8.27762[ms]
libjpeg-turbo v1.4.2 2.36519[ms]

Reference

 


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です