opencv中访问Mat的三种方法

本文探讨了使用OpenCV库处理图像时不同访问方法的效率,包括通过Mat的ptr指针、迭代器和直接访问Mat的随机访问方式,并通过实验对比了这些方法的性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自官方教程 https://docs.opencv.org/master/db/da5/tutorial_how_to_scan_images.html

官方给出的代码: https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp

分为三种不同的访问方式:

1. 通过Mat的ptr指针的[]操作符号,按照数组的方式遍历--->效率最高

2. 通过迭代器 cv::MatIterator_进行访问--->效率次之,但是是安全的

3. 不通过ptr指针,直接通过Mat进行访问--->效率最低, 不适合遍历操作,常用于随机位置的访问, "The final method isn't recommended for scanning. It was made to acquire or modify somehow random elements in the image."


#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <iostream>
#include <sstream>

cv::Mat& ScanImageAndReduceC(cv::Mat& I, const uchar* const table);
cv::Mat& ScanImageAndReduceIterator(cv::Mat& I, const uchar* const table);
cv::Mat& ScanImageAndReduceRandomAccess(cv::Mat& I, const uchar* const table);


int main(int argc, char** argv)
{
    std::string imageName( "../data/lei.jpeg" ); // by default

    //cv::imread(imageName, cv::IMREAD_COLOR);
    cv::Mat I = cv::imread(imageName, cv::IMREAD_GRAYSCALE);
    cv::Mat J;

    int dividewith = 8;
    uchar table[256];

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

    const int times = 100;

    double t;

    t = (double)cv::getTickCount();

    for(int i=0; i<times; ++i)
    {
        cv::Mat clone_i = I.clone();
        J = ScanImageAndReduceC(clone_i, table);
    }

    t = 1000*((double)cv::getTickCount() - t)/cv::getTickFrequency();
    t /= times;

    std::cout << "Time of reducing with the c operator [] (averaged for "
              << times << " runs):" << t << " milliseconds." << std::endl;


    /***************************************/

    t = (double)cv::getTickCount();
    for(int i=0; i<times; ++i)
    {
        cv::Mat clone_i = I.clone();
        J = ScanImageAndReduceIterator(clone_i, table);
    }

    t = 1000*((double)cv::getTickCount() - t)/cv::getTickFrequency();
    t /= times;

    std::cout << "Time of reducing with the iterator (averaged for "
              << times << " runs): " << t << " millseconds." << std::endl;

    /***********************************************/
    t = (double)cv::getTickCount();
    for(int i=0; i<times; ++i)
    {
        cv::Mat clone_i = I.clone();
        ScanImageAndReduceRandomAccess(clone_i, table);
    }

    t = 1000*((double)cv::getTickCount() - t)/cv::getTickFrequency();
    t /= times;

    std::cout << "Time of reducing with the random access (averagd for "
              << times << " runs): " << t << " millseconds" << std::endl;

    cv::Mat lookUpTable(1,256, CV_8U);
    uchar *p = lookUpTable.ptr();
    for(int i=0; i<256; ++i)
    {
        p[i] = table[i];
    }

    t = (double)cv::getTickCount();
    for(int i=0; i<times; ++i)
    {
        //调用LUT函数并通过查找表来进行"color space reduction"
        cv::LUT(I, lookUpTable, J);
    }

    t = 1000 * ((double)cv::getTickCount() - t)/cv::getTickFrequency();
    t /= times;
    std::cout << "Time of reducing with the LUT function (averaged for "
              << times << " runs): " << t << " millseconds" << std::endl;

    return 0;
}


cv::Mat& ScanImageAndReduceC(cv::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;
}



cv::Mat& ScanImageAndReduceIterator(cv::Mat& I, const uchar* const table)
{
    CV_Assert(I.depth() == CV_8U);

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

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

        }

    }

    return I;
}


cv::Mat& ScanImageAndReduceRandomAccess(cv::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:
    {
        cv::Mat_<cv::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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值