Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

PNG encoding performance difference between 3.1 and 3.2

Encoding a PNG using OpenCV 3.2.0 takes about 2x longer than OpenCV 3.1.0 on an ARM Cortex A9 system, and about 1.4x longer on an x64 system. Does anyone know what causes the difference and whether it can be reduced through build settings? I'll try git bisect between 3.1 and 3.2 to see what caused the difference but wanted to check if anyone already knows. Thanks

Test code (cv.cpp):

#include <iostream>
#include <opencv2/opencv.hpp>

#include <sys/time.h>


int height = 1600;
int width = 1200;

void loadFrame(cv::Mat& frame)
{
    srand (time(NULL));
    printf("generating random image\n");
    int image_format = CV_8U;
    frame.create(height, width, image_format);
    uint8_t* image_ptr = frame.ptr<uint8_t>(0);
    for (int pixel = 0; pixel < int(frame.total()); ++pixel)
    {
        image_ptr[pixel] = rand();
    }
}

bool writeImageToString(const cv::Mat& image, const std::string& extension, std::vector<uint8_t>& buffer)
{
    if (image.empty() || (image.cols == 0 && image.rows == 0))
        return false;

    bool success = true;

    // Set the image compression parameters.
    std::vector<int> params;
    if (extension == ".png")
    {
        params.push_back(cv::IMWRITE_PNG_COMPRESSION);
        params.push_back(6);     // MAX_MEM_LEVEL = 9
        success = cv::imencode(extension, image, buffer, params);
    }
    else if (extension == ".jpg")
    {
        params.push_back(cv::IMWRITE_JPEG_QUALITY);
        params.push_back(90);     // 0...100 (higher is better)
        success = cv::imencode(extension, image, buffer, params);
    }

    return success;
}

void encodeTest(int argc, const char** argv)
{
    int frame_tests = 10;
    int write_tests = 5;
    size_t png_size = 0;
    size_t jpg_size = 0;
    double png_time = 0;
    double jpg_time = 0;
    struct timeval start, end;

    for ( int frame_count = 0; frame_count < frame_tests; frame_count++ )
    {
        cv::Mat frame;
        loadFrame(frame);
        std::vector<uint8_t> buffer;
        gettimeofday(&start, NULL);

        for ( int test_count = 0; test_count < write_tests; test_count++ )
        {
            writeImageToString(frame, ".png", buffer);
        }
        gettimeofday(&end, NULL);
        png_time += ((end.tv_sec - start.tv_sec) * 1000) 
            + (end.tv_usec / 1000 - start.tv_usec / 1000);

        png_size += buffer.size();
        gettimeofday(&start, NULL);

        for ( int test_count = 0; test_count < write_tests; test_count++ )
        {
            writeImageToString(frame, ".jpg", buffer);
        }
        jpg_size += buffer.size();
        gettimeofday(&end, NULL);
        jpg_time += ((end.tv_sec - start.tv_sec) * 1000) 
            + (end.tv_usec / 1000 - start.tv_usec / 1000);

    }
    std::cout << "Avg time PNG: " << png_time / frame_tests / write_tests / 1000 << "sec  JPG: " << jpg_time / frame_tests / write_tests / 1000 << "sec" << std::endl;

    printf("Avg size PNG: %zu     JPG: %zu\n", png_size / 10, jpg_size / 10);
}

int main(int argc, const char** argv)
{
    printf( "OpenCV version : %s\n" , CV_VERSION);

    try
    {
        encodeTest(argc, argv);
    }
    catch (cv::Exception& e)
    {
        printf("OpenCV test error\n");
        throw;
    }
    return 0;
}

This is the CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project( cv )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( cv cv.cpp )
target_link_libraries( cv ${OpenCV_LIBS} )

To generate cross-compile for ARM I used following cmake command:

cmake -DCMAKE_TOOLCHAIN_FILE=../platforms/linux/arm-gnueabi.toolchain.cmake -DGCC_COMPILER_VERSION=5 -DENABLE_NEON=ON -DWITH_OPENMP=1 -DCMAKE_INSTALL_PREFIX=/usr/local ..

For intel x64 system (Ubuntu 14.04) I just used:

cmake .

Sample runs on ARM:

OpenCV version : 3.1.0
Avg time PNG: 0.26792sec  JPG: 0.35374sec
Avg size PNG: 1925061     JPG: 1509208

OpenCV version : 3.1.0
Avg time PNG: 0.26778sec  JPG: 0.35472sec
Avg size PNG: 1925061     JPG: 1509038

OpenCV version : 3.2.0
Avg time PNG: 0.54376sec  JPG: 0.34756sec
Avg size PNG: 1925061     JPG: 1509276

OpenCV version : 3.2.0
Avg time PNG: 0.55598sec  JPG: 0.35302sec
Avg size PNG: 1925061     JPG: 1509296

Sample run times on x64 (Ubuntu 14.04 running in Parallels Desktop)

OpenCV version : 3.1.0
Avg time PNG: 0.07736sec  JPG: 0.01686sec
Avg size PNG: 1925061     JPG: 1509035

OpenCV version : 3.1.0
Avg time PNG: 0.07764sec  JPG: 0.01704sec
Avg size PNG: 1925061     JPG: 1509303

OpenCV version : 3.2.0
Avg time PNG: 0.11122sec  JPG: 0.0168sec
Avg size PNG: 1925061     JPG: 1509319

OpenCV version : 3.2.0
Avg time PNG: 0.10988sec  JPG: 0.0171sec
Avg size PNG: 1925061     JPG: 1509391

PNG encoding performance difference between 3.1 and 3.2

Encoding a PNG using OpenCV 3.2.0 takes about 2x longer than OpenCV 3.1.0 on an ARM Cortex A9 system, and about 1.4x longer on an x64 system. Does anyone know what causes the difference and whether it can be reduced through build settings? I'll try git bisect between 3.1 and 3.2 to see what caused the difference but wanted to check if anyone already knows. Thanks

Test code (cv.cpp):

#include <iostream>
#include <opencv2/opencv.hpp>

#include <sys/time.h>


int height = 1600;
int width = 1200;

void loadFrame(cv::Mat& frame)
{
    srand (time(NULL));
    printf("generating random image\n");
    int image_format = CV_8U;
    frame.create(height, width, image_format);
    uint8_t* image_ptr = frame.ptr<uint8_t>(0);
    for (int pixel = 0; pixel < int(frame.total()); ++pixel)
    {
        image_ptr[pixel] = rand();
    }
}

bool writeImageToString(const cv::Mat& image, const std::string& extension, std::vector<uint8_t>& buffer)
{
    if (image.empty() || (image.cols == 0 && image.rows == 0))
        return false;

    bool success = true;

    // Set the image compression parameters.
    std::vector<int> params;
    if (extension == ".png")
    {
        params.push_back(cv::IMWRITE_PNG_COMPRESSION);
        params.push_back(6);     // MAX_MEM_LEVEL = 9
        success = cv::imencode(extension, image, buffer, params);
    }
    else if (extension == ".jpg")
    {
        params.push_back(cv::IMWRITE_JPEG_QUALITY);
        params.push_back(90);     // 0...100 (higher is better)
        success = cv::imencode(extension, image, buffer, params);
    }

    return success;
}

void encodeTest(int argc, const char** argv)
{
    int frame_tests = 10;
    int write_tests = 5;
    size_t png_size = 0;
    size_t jpg_size = 0;
    double png_time = 0;
    double jpg_time = 0;
    struct timeval start, end;

    for ( int frame_count = 0; frame_count < frame_tests; frame_count++ )
    {
        cv::Mat frame;
        loadFrame(frame);
        std::vector<uint8_t> buffer;
        gettimeofday(&start, NULL);

        for ( int test_count = 0; test_count < write_tests; test_count++ )
        {
            writeImageToString(frame, ".png", buffer);
        }
        gettimeofday(&end, NULL);
        png_time += ((end.tv_sec - start.tv_sec) * 1000) 
            + (end.tv_usec / 1000 - start.tv_usec / 1000);

        png_size += buffer.size();
        gettimeofday(&start, NULL);

        for ( int test_count = 0; test_count < write_tests; test_count++ )
        {
            writeImageToString(frame, ".jpg", buffer);
        }
        jpg_size += buffer.size();
        gettimeofday(&end, NULL);
        jpg_time += ((end.tv_sec - start.tv_sec) * 1000) 
            + (end.tv_usec / 1000 - start.tv_usec / 1000);

    }
    std::cout << "Avg time PNG: " << png_time / frame_tests / write_tests / 1000 << "sec  JPG: " << jpg_time / frame_tests / write_tests / 1000 << "sec" << std::endl;

    printf("Avg size PNG: %zu     JPG: %zu\n", png_size / 10, jpg_size / 10);
}

int main(int argc, const char** argv)
{
    printf( "OpenCV version : %s\n" , CV_VERSION);

    try
    {
        encodeTest(argc, argv);
    }
    catch (cv::Exception& e)
    {
        printf("OpenCV test error\n");
        throw;
    }
    return 0;
}

This is the CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project( cv )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( cv cv.cpp )
target_link_libraries( cv ${OpenCV_LIBS} )

To generate cross-compile for ARM I used following cmake command:

cmake -DCMAKE_TOOLCHAIN_FILE=../platforms/linux/arm-gnueabi.toolchain.cmake -DGCC_COMPILER_VERSION=5 -DENABLE_NEON=ON -DWITH_OPENMP=1 -DCMAKE_INSTALL_PREFIX=/usr/local ..

For intel x64 system (Ubuntu 14.04) I just used:

cmake .

Sample runs on ARM:

OpenCV version : 3.1.0
Avg time PNG: 0.26792sec  JPG: 0.35374sec
Avg size PNG: 1925061     JPG: 1509208

OpenCV version : 3.1.0
Avg time PNG: 0.26778sec  JPG: 0.35472sec
Avg size PNG: 1925061     JPG: 1509038

OpenCV version : 3.2.0
Avg time PNG: 0.54376sec  JPG: 0.34756sec
Avg size PNG: 1925061     JPG: 1509276

OpenCV version : 3.2.0
Avg time PNG: 0.55598sec  JPG: 0.35302sec
Avg size PNG: 1925061     JPG: 1509296

Sample run times on x64 (Ubuntu 14.04 running in Parallels Desktop)

OpenCV version : 3.1.0
Avg time PNG: 0.07736sec  JPG: 0.01686sec
Avg size PNG: 1925061     JPG: 1509035

OpenCV version : 3.1.0
Avg time PNG: 0.07764sec  JPG: 0.01704sec
Avg size PNG: 1925061     JPG: 1509303

OpenCV version : 3.2.0
Avg time PNG: 0.11122sec  JPG: 0.0168sec
Avg size PNG: 1925061     JPG: 1509319

OpenCV version : 3.2.0
Avg time PNG: 0.10988sec  JPG: 0.0171sec
Avg size PNG: 1925061     JPG: 1509391

PNG encoding performance difference between 3.1 and 3.2master

Encoding a PNG using OpenCV 3.2.0 takes about 2x longer than OpenCV 3.1.0 on an ARM Cortex A9 system, and about 1.4x longer on an x64 system. Does anyone know what causes the difference and whether it can be reduced through build settings? I'll try git bisect between 3.1 and 3.2 to see what caused the difference but wanted to check if anyone already knows. Thanks

Test code (cv.cpp):

#include <iostream>
#include <opencv2/opencv.hpp>

#include <sys/time.h>


int height = 1600;
int width = 1200;

void loadFrame(cv::Mat& frame)
{
    srand (time(NULL));
    printf("generating random image\n");
    int image_format = CV_8U;
    frame.create(height, width, image_format);
    uint8_t* image_ptr = frame.ptr<uint8_t>(0);
    for (int pixel = 0; pixel < int(frame.total()); ++pixel)
    {
        image_ptr[pixel] = rand();
    }
}

bool writeImageToString(const cv::Mat& image, const std::string& extension, std::vector<uint8_t>& buffer)
{
    if (image.empty() || (image.cols == 0 && image.rows == 0))
        return false;

    bool success = true;

    // Set the image compression parameters.
    std::vector<int> params;
    if (extension == ".png")
    {
        params.push_back(cv::IMWRITE_PNG_COMPRESSION);
        params.push_back(6);     // MAX_MEM_LEVEL = 9
        success = cv::imencode(extension, image, buffer, params);
    }
    else if (extension == ".jpg")
    {
        params.push_back(cv::IMWRITE_JPEG_QUALITY);
        params.push_back(90);     // 0...100 (higher is better)
        success = cv::imencode(extension, image, buffer, params);
    }

    return success;
}

void encodeTest(int argc, const char** argv)
{
    int frame_tests = 10;
    int write_tests = 5;
    size_t png_size = 0;
    size_t jpg_size = 0;
    double png_time = 0;
    double jpg_time = 0;
    struct timeval start, end;

    for ( int frame_count = 0; frame_count < frame_tests; frame_count++ )
    {
        cv::Mat frame;
        loadFrame(frame);
        std::vector<uint8_t> buffer;
        gettimeofday(&start, NULL);

        for ( int test_count = 0; test_count < write_tests; test_count++ )
        {
            writeImageToString(frame, ".png", buffer);
        }
        gettimeofday(&end, NULL);
        png_time += ((end.tv_sec - start.tv_sec) * 1000) 
            + (end.tv_usec / 1000 - start.tv_usec / 1000);

        png_size += buffer.size();
        gettimeofday(&start, NULL);

        for ( int test_count = 0; test_count < write_tests; test_count++ )
        {
            writeImageToString(frame, ".jpg", buffer);
        }
        jpg_size += buffer.size();
        gettimeofday(&end, NULL);
        jpg_time += ((end.tv_sec - start.tv_sec) * 1000) 
            + (end.tv_usec / 1000 - start.tv_usec / 1000);

    }
    std::cout << "Avg time PNG: " << png_time / frame_tests / write_tests / 1000 << "sec  JPG: " << jpg_time / frame_tests / write_tests / 1000 << "sec" << std::endl;

    printf("Avg size PNG: %zu     JPG: %zu\n", png_size / 10, jpg_size / 10);
}

int main(int argc, const char** argv)
{
    printf( "OpenCV version : %s\n" , CV_VERSION);

    try
    {
        encodeTest(argc, argv);
    }
    catch (cv::Exception& e)
    {
        printf("OpenCV test error\n");
        throw;
    }
    return 0;
}

This is the CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project( cv )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( cv cv.cpp )
target_link_libraries( cv ${OpenCV_LIBS} )

To generate cross-compile for ARM I used following cmake command:

cmake -DCMAKE_TOOLCHAIN_FILE=../platforms/linux/arm-gnueabi.toolchain.cmake -DGCC_COMPILER_VERSION=5 -DENABLE_NEON=ON -DWITH_OPENMP=1 -DCMAKE_INSTALL_PREFIX=/usr/local ..

For intel x64 system (Ubuntu 14.04) I just used:

cmake .

Sample runs on ARM:

OpenCV version : 3.1.0
Avg time PNG: 0.26792sec  JPG: 0.35374sec
Avg size PNG: 1925061     JPG: 1509208

OpenCV version : 3.1.0
Avg time PNG: 0.26778sec  JPG: 0.35472sec
Avg size PNG: 1925061     JPG: 1509038

OpenCV version : 3.2.0
Avg time PNG: 0.54376sec  JPG: 0.34756sec
Avg size PNG: 1925061     JPG: 1509276

OpenCV version : 3.2.0
Avg time PNG: 0.55598sec  JPG: 0.35302sec
Avg size PNG: 1925061     JPG: 1509296

Sample run times on x64 (Ubuntu 14.04 running in Parallels Desktop)

OpenCV version : 3.1.0
Avg time PNG: 0.07736sec  JPG: 0.01686sec
Avg size PNG: 1925061     JPG: 1509035

OpenCV version : 3.1.0
Avg time PNG: 0.07764sec  JPG: 0.01704sec
Avg size PNG: 1925061     JPG: 1509303

OpenCV version : 3.2.0
Avg time PNG: 0.11122sec  JPG: 0.0168sec
Avg size PNG: 1925061     JPG: 1509319

OpenCV version : 3.2.0
Avg time PNG: 0.10988sec  JPG: 0.0171sec
Avg size PNG: 1925061     JPG: 1509391