OPENCV學習筆記2-4_編寫高效的圖像掃描循環

  When you write an image-processing function, efficiency is often a concern(涉及). When you design your function, you will frequently need to check the computational efficiency of your code in order to detect(發現) any bottleneck(瓶頸) in your processing that might slow down(變慢) your program.

1.1 實現方法

  爲了衡量函數或代碼段的運行時間,OpenCV有一個非常實用的函數,即cv::getTickCount(),該函數返回從最近一次電腦開機到當前的時鐘週期數。如希望得到以秒爲單位的代碼運行時間,要使用另一個方法,即cv::getTickFrequency(),返回每秒的時鐘週期數。

  const int64 start = cv::getTickCount();

  colorReduce(image);

  // elapsed (經過的時間) time in seconds

  double duration = (cv::getTickCount() - start) /

  cv::getTickFrequency();

1.2 四種存取像素方式效率對比

  查看.at、pointers、reshape及iterators四種遍歷圖像方式所消耗時間

//Test running time,edited by yunfung
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;

void colorReduce1(Mat& image, int div = 64)
{
    for (int i = 0; i < image.rows; i++)
    {
         for (int j = 0; j < image.cols; j++)
        {
            image.at<Vec3b>(i, j)[0] = image.at<Vec3b>(i, j)[0] / div*div + div / 2;
            image.at<Vec3b>(i, j)[1] = image.at<Vec3b>(i, j)[1] / div*div + div / 2;
            image.at<Vec3b>(i, j)[2] = image.at<Vec3b>(i, j)[2] / div*div + div / 2;
        }
    }
}

void colorReduce2(cv::Mat image, int div = 64) {
    int nl = image.rows;
    int nc = image.cols * image.channels();
    for (int j = 0; j < nl; j++) {
        uchar* data = image.ptr<uchar>(j);
        for (int i = 0; i < nc; i++) {
            data[i] = data[i] / div*div + div / 2;

        }
    }
}

void colorReduce3(cv::Mat &image, int div = 64) {
    if (image.isContinuous()){
        image.reshape(1, 1);
    }
    int nl = image.rows;
    int nc = image.cols * image.channels();
    for (int j = 0; j < nl; j++) {
        uchar* data = image.ptr<uchar>(j);
        for (int i = 0; i < nc; i++) {
            data[i] = data[i] / div*div + div / 2;
        }
    }
}

void colorReduce4(cv::Mat &image, int div = 64) {
    cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
    cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();
    for (; it != itend; ++it) {
        (*it)[0] = (*it)[0] / div * div + div / 2;
        (*it)[1] = (*it)[1] / div * div + div / 2;
        (*it)[2] = (*it)[2] / div * div + div / 2;
    }
}

void calrunTime(int v, Mat&image)
{
    double duration;
    duration = static_cast<double>(getTickCount()); //強制轉化爲double
    for (int i = 0; i < 10; i++)
    {
        switch (v)
        {
        case 1:
            colorReduce1(image);   //at
            break;
        case 2:
            colorReduce2(image);   //pointers
            break;
        case 3:
            colorReduce3(image);   //reshape(continuous)
            break;
        case 4:
            colorReduce4(image);   //iterators
            break;
        default:
            break;
        }
    }
    duration = static_cast<double>(getTickCount()) - duration;
    duration /= getTickFrequency();
    duration *= (1000/10); //average
    cout << "duration" << v << " : " << duration << "mS"<< endl;
}

int main()
{
    Mat image = imread("test.jpg");
    Mat imageClone = image.clone();
    cout << "yunfung_opencv_learn_test:" <<"\n\n";
    calrunTime(1, image);

    image = imread("test.jpg");
    imageClone = image.clone();
    calrunTime(2, image);
    image = imread("test.jpg");
    imageClone = image.clone();
    calrunTime(3, image);
    image = imread("test.jpg");
    imageClone = image.clone();
    calrunTime(4, image);

    namedWindow("Image Result");
    imshow("Image Result", imageClone);
    waitKey();
    return 0;
}

  可見用at的方式讀取像素效率最低,用迭代器速度也比較慢,效率最高的方式還是使用指針讀取。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章