opencv4 学习 03 像素的遍历方法

#include "pch.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;

// 效率高,使用行指针的遍历方式
Mat& scanImageAndReduce(Mat& I, const uchar* const table)
{
    CV_Assert(I.depth() == CV_8U);
    int channels = I.channels();

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

    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;
}
// 使用 iterator,更稳定
Mat& scanImageAndReduceIterator(Mat& I, const uchar* const table)
{
    CV_Assert(I.depth() == CV_8U);

    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;
}
// 使用 cv::Mat::at() 函数, 耗时,效率低
Mat& scanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
    CV_Assert(I.depth() == CV_8U);

    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.at<Vec3b>(i, j)[0] = table[I.at<Vec3b>(i, j)[0]];
                    I.at<Vec3b>(i, j)[1] = table[I.at<Vec3b>(i, j)[1]];
                    I.at<Vec3b>(i, j)[2] = table[I.at<Vec3b>(i, j)[2]];
                }
            I = _I;
            break;
        }
    }
    return I;
}
// cv::LUT() 函数的使用
Mat coreFunction(Mat& I, const uchar* const table)
{    
    Mat output;
    Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.ptr();
    for (int i = 0; i < 256; ++i)
        p[i] = table[i];
    LUT(I, lookUpTable, output);
    return output;
}

int main(int argc, char** argv)
{    
    Mat image = imread("G:\\tools\\opencv4\\workspace\\opencv01\\001.jpg");
    Mat I = image.clone();
    // 对图像的像素范围做reduce操作,(0~9)->0; (10~19)->10; (20~29)->20;...
    // 1、定义查找表
    uchar table[256];
    for (int i = 0; i < 256; ++i)
        table[i] = (char)(10 * (i / 10));

    int runNum = 1;
    Mat I1, I2, I3, I4;
    // 2、遍历像素的方法
    double t = (double)getTickCount();
    for (int i = 0; i < runNum; ++i)
    {
        I1 = scanImageAndReduce(I, table);
    }
    t = ((double)getTickCount() - t) / getTickFrequency();
    cout << "Times passed in seconds: " << t << endl;

    t = (double)getTickCount();
    for (int i = 0; i < runNum; ++i)
    {
        I2 = scanImageAndReduceIterator(I, table);
    }
    t = ((double)getTickCount() - t) / getTickFrequency();
    cout << "Times passed in seconds: " << t << endl;

    t = (double)getTickCount();
    for (int i = 0; i < runNum; ++i)
    {
        I3 = scanImageAndReduceRandomAccess(I, table);
    }
    t = ((double)getTickCount() - t) / getTickFrequency();
    cout << "Times passed in seconds: " << t << endl;

    t = (double)getTickCount();
    for (int i = 0; i < runNum; ++i)
    {
        I4 = coreFunction(I, table);
    }
    t = ((double)getTickCount() - t) / getTickFrequency();
    cout << "Times passed in seconds: " << t << endl;

    imshow("image", image);
    imshow("I1", I1);
    imshow("I2", I2);
    imshow("I3", I3);
    imshow("I4", I4);
    cout << image.at<Vec3b>(0, 0) << I1.at<Vec3b>(0, 0) << I2.at<Vec3b>(0, 0) << I3.at<Vec3b>(0, 0) << I4.at<Vec3b>(0, 0) << endl;
    waitKey(0); // Wait for a keystroke in the window
    return 0;
}

当 runNum = 1 时;

MethodTime
Efficient Way 0.0029501
Iterator 0.005117
On-The-Fly RA 0.0066011
LUT function 0.0079816

 

 

 

 

 

 

 

当 runNum = 100 时;

MethodTime
Efficient Way 0.285074
Iterator 0.503359
On-The-Fly RA 0.542601
LUT function 0.202836

 

 

 

 

 

 


注意:cv::LUT()方法使用了多线程,当数据量很大时使用该方法速度最快;但相反的,当数据量比较小时使用该方法速度可能会变成最慢的,上述时间单位为秒。

参考:
https://docs.opencv.org/4.4.0/db/da5/tutorial_how_to_scan_images.html
posted @ 2020-08-08 21:54  blackx  阅读(137)  评论(0编辑  收藏  举报