Saturday, March 3, 2012

Compare image scan method

Original Image Link

In this section I will try to compare performance from some scanning method using OpenCV, the compare is about performance image scanning for manipulate per color data.

What will be compare on this section:
  • Classic C style operator scanning method
  • Iterator safe method scanning method
  • On-the-fly address calculation with reference returning scanning method
  • Use LUT() core function from OpenCV



this program is simple and will take 2 argument, first argument is image to be load and to be scan then second argument is number of reduced color to be apply to current loaded image.

The program I created using QT Creator,  this program contain 3 file base:
  • imagescanningcompare.h (this is class declaration and method declaration for current program)
  • imagescanningcompare.cpp (this is method declaration from imagescanningcompare.h)
  • TestOpenCV.cpp (this is main program main())
 code snippet for imagescanningcompare.h
#ifndef IMAGESCANNINGCOMPARE_H
#define IMAGESCANNINGCOMPARE_H

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

using namespace std;
using namespace cv;

class ImageScanningCompare
{
public:
    ImageScanningCompare(string filename, int reduction);
    Mat& ScanImageAndReduceC(Mat& I, const uchar *const table);
    Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table);
    Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table);
    Mat& LookUpTable(Mat& I, const uchar* const table);
};

#endif // IMAGESCANNINGCOMPARE_H

code snippet for imagescanningcompare.cpp

#include "imagescanningcompare.h"

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

using namespace std;
using namespace cv;

ImageScanningCompare::ImageScanningCompare(string filename, int reduction)
{
    int devideWidth;
    devideWidth = reduction;

    Mat img, img2, img3, img4;
    img = imread(filename, CV_LOAD_IMAGE_COLOR);

    img2 = img.clone();
    img3 = img.clone();
    img4 = img.clone();

    uchar table[256];

    for(int i = 0; i < 256; ++i) {
        table[i] = devideWidth * (i*devideWidth);
    }

    //time calculation
    cout << "======================== compare performace =====================" << endl;
    cout << "Classic C style operator: ";
    double t = (double)getTickCount();
    this->ScanImageAndReduceC(img, table);
    t = ((double)getTickCount() - t)/getTickFrequency();
    cout << "Times Passed in second " << t << endl;

    cout << "=================================================================" << endl;
    cout << "Iterator safe method: ";
    t = (double)getTickCount();
    this->ScanImageAndReduceIterator(img2, table);
    t = ((double)getTickCount() - t)/getTickFrequency();
    cout << "Times Passed in second " << t << endl;

    cout << "=================================================================" << endl;
    cout << "On-the-fly address calculation with reference returning: ";
    t = (double)getTickCount();
    this->ScanImageAndReduceRandomAccess(img3, table);
    t = ((double)getTickCount() - t)/getTickFrequency();
    cout << "Times Passed in second " << t << endl;

    cout << "=================================================================" << endl;
    cout << "Use LUT() core function: ";
    t = (double)getTickCount();
    this->LookUpTable(img4, table);
    t = ((double)getTickCount() - t)/getTickFrequency();
    cout << "Times Passed in second " << t << endl;
    cout << "=================================================================" << endl;
}


Mat& ImageScanningCompare::ScanImageAndReduceC(Mat& I, const uchar *const table)
{
    int channels = I.channels();

    int nRows = I.rows * channels;
    int nCols = I.cols;

    if (I.isContinuous())
    {
        nCols *= nRows;
        nRows = 1;
    }

    int i,j;
    uchar* p;

    for( i = 0; i < nRows; ++i)
    {
        p = I.ptr<uchar>(i);

        for ( j = 0; j < nCols; ++j)
        {
            p[j] = table[p[j]];
        }
    }

    return I;
}

Mat& ImageScanningCompare::ScanImageAndReduceIterator(Mat& I, const uchar* const table)
{
    const int channels = I.channels();

    switch(channels)
    {
        case 1:
        {
            MatIterator_<uchar> it, end;
            for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
                *it = table[*it];
            break;
        }
        case 3:
        {
            MatIterator_<Vec3b> it, end;
            for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
            {
                (*it)[0] = table[(*it)[0]];
                (*it)[1] = table[(*it)[1]];
                (*it)[2] = table[(*it)[2]];
            }
        }
    }

    return I;
}

Mat& ImageScanningCompare::ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
    const int channels = I.channels();
    switch(channels)
    {
        case 1:
        {
            for( int i = 0; i < I.rows; ++i)
                for( int j = 0; j < I.cols; ++j )
                    I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
            break;
        }
        case 3:
        {
            Mat_<Vec3b> _I = I;
            for( int i = 0; i < I.rows; ++i)
                for( int j = 0; j < I.cols; ++j )
                {
                    _I(i,j)[0] = table[_I(i,j)[0]];
                    _I(i,j)[1] = table[_I(i,j)[1]];
                    _I(i,j)[2] = table[_I(i,j)[2]];
                }
            I = _I;
            break;
        }
    }

    return I;
}

Mat& ImageScanningCompare::LookUpTable(Mat& I, const uchar* const table)
{
    Mat lookUpTable(1, 256, CV_8U);
    Mat J;
    uchar* p = lookUpTable.data;
    for( int i = 0; i < 256; ++i)
        p[i] = table[i];

    LUT(I, lookUpTable, J);
}
code snippet for TestOpenCV.cpp

//#include <opencv2/opencv.hpp>
//#include "displayimage.h"
//#include "displayimage2.h"

#include "imagescanningcompare.h"
#include <iostream>
#include <string>

int main(int argc, char** argv)
{
    //DisplayImage di("/home/ar/Pictures/g4958.png");
    //DisplayImage2 di2("/home/ar/Pictures/g4958.png");

    int devideWidth;
    stringstream s;
    s << argv[2];
    s >> devideWidth;
    ImageScanningCompare isc(argv[1], devideWidth);

    return 0;
}

After build the code we will get execute able binary TestOpenCV, then we can run this with this way:

ar@dream:~/Projects/QT/OpenCV$ ./OpenCV /home/ar/Pictures/freedom1680x1050.jpg 50
======================== compare performace =====================
Classic C style operator: Times Passed in second 0.0636563
=================================================================
Iterator safe method: Times Passed in second 0.223594
=================================================================
On-the-?y address calculation with reference returning: Times Passed in second 0.214652
=================================================================
Use LUT() core function: Times Passed in second 0.0384888
=================================================================
from the result we can see that LUT() core function is more efficient then other method :)

this is the summary result:

Classic C style operator0.0636563
Iterator safe method0.223594
On-the-?y address calculation with reference returning0.214652
Use LUT() core function0.0384888

No comments:

Post a Comment