opencv(C++)四種不同訪問(wèn)方式及速度對(duì)比

摘要:

比較一下opencv四種不同的訪問(wèn)方式的效率,多次測(cè)試的結(jié)論就是用指針的方式是最快的喜命,方法2沟沙、3、4都是指針的方式壁榕,在release模式下矛紫,方法2、方法3牌里、方法4很接近颊咬,沒(méi)多少差別,在不同尺度下稍微各有一點(diǎn)點(diǎn)優(yōu)劣牡辽,我個(gè)人常用方法3喳篇,因?yàn)樗?jiǎn)潔高效,方法2看起來(lái)似乎也不錯(cuò)态辛,方法4需要圖像數(shù)據(jù)是連續(xù)的才能用麸澜。

假設(shè):圖像image為3通道8bit的圖像,現(xiàn)在要訪問(wèn)它的第row行奏黑,第col列的r,g,b值

1. 方法一:Mat.at<vec>(row,col)

//Mat.at<vec>(i,j)方式訪問(wèn)
cv::Vec3b bgr = image.at<cv::Vec3b>(row, col);
blue  = bgr[0];
green = bgr[1];
red   = bgr[2];

2. 方法二:Mat.ptr<vec>(row)

//Mat.at<vec>(i,j)方式訪問(wèn)
cv::Vec3b *bgr = image.ptr<cv::Vec3b>(row);
blue  = bgr[col][0];
green = bgr[col][1];
red   = bgr[col][2];

3. 方法三:Mat.ptr<uchar>(row)

uchar *ptr = image.ptr<uchar>(row);//獲得圖像第row行的首地址
blue  = *(ptr + col*3 );
green = *(ptr + col*3 + 1);
red   = *(ptr + col*3 + 2);

4. 方法四:Mat.data + 偏移量

//image.data是圖像矩陣的首地址
uchar *ptr = image.data + row * image.cols * 3 +  col*3;
blue  = *(ptr);
green = *(ptr + 1);
red   = *(ptr + 2);

注:其他數(shù)據(jù)類型的訪問(wèn)可參考http://www.reibang.com/p/cfe373dc8c95

測(cè)試

圖片尺寸427 * 640 * 3炊邦,重復(fù)顏色反轉(zhuǎn)操作99次,顯示平均時(shí)間在圖片上

  • debug模式下


    debug.png
  • release模式下


    image.png

完整源碼

#include "opencv.hpp"
#include "imageProcess.h"

#define TIMES 1

//Mat.at<vec>(i,j)方式訪問(wèn)
void method_1(cv::Mat image)
{
    //cv::Mat image = image_.clone();
    double startTime = cv::getTickCount();
    int w = image.cols;
    int h = image.rows;
    for (int times = 0; times < TIMES; times++)
    {
        for (int row = 0; row < h; row++)
        {
            for (int col = 0; col < w; col++)
            {
                image.at<cv::Vec3b>(row, col)[0] = 255 - image.at<cv::Vec3b>(row, col)[0];
                image.at<cv::Vec3b>(row, col)[1] = 255 - image.at<cv::Vec3b>(row, col)[1];
                image.at<cv::Vec3b>(row, col)[2] = 255 - image.at<cv::Vec3b>(row, col)[2];
            }
        }
    }
    double endTime = cv::getTickCount();
    double t = ((endTime - startTime) / cv::getTickFrequency()) * 1000 / TIMES;
    std::ostringstream ss;
    ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
    putText(image, ss.str(), cv::Point(20, 20), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 255), 2, 8);
    imshow("method1", image);
}

//Mat.ptr<vec3b>(row);
void method_2(cv::Mat image)
{
    //cv::Mat image = image_.clone();
    //cv::imshow("2", image);
    double startTime = cv::getTickCount();
    int w = image.cols;
    int h = image.rows;
    cv::Vec3b* curr=NULL;
    for (int times = 0; times < TIMES; times++)
    {
        for (int row = 0; row < h; row++) 
        {
            curr = image.ptr<cv::Vec3b>(row);
            for (int col = 0; col < w; col++) 
            {
                curr[col][0] = 255 - curr[col][0];
                curr[col][1] = 255 - curr[col][1];
                curr[col][2] = 255 - curr[col][2];
            }
        }
    }
    
    double endTime = cv::getTickCount();
    double t = ((endTime - startTime) / cv::getTickFrequency()) * 1000 / TIMES;
    std::ostringstream ss;
    ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
    putText(image, ss.str(), cv::Point(20, 20), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 255), 2, 8);
    imshow("method2", image);
}


void method_3(cv::Mat image)
{
    //cv::Mat image = image_.clone();
    double startTime = cv::getTickCount();
    int w = image.cols;
    int h = image.rows;
    uchar * ptr=NULL;//指針定義應(yīng)該放在這里熟史,如果放在for循環(huán)中定義會(huì)消耗一部分變量分配時(shí)間馁害;
    for (int times = 0; times < TIMES; times++)
    {
        for (int row = 0; row < h; row++) 
        {
            ptr = image.ptr<uchar>(row);
            for (int col = 0; col < w; col++)
            {
                *(ptr + 3 * col) = 255 - *(ptr + 3 * col);
                *(ptr + 3 * col + 1) = 255 - *(ptr + 3 * col + 1);
                *(ptr + 3 * col + 2) = 255 - *(ptr + 3 * col + 2);
            }
        }
    }
    
    double endTime = cv::getTickCount();
    double t = ((endTime - startTime) / cv::getTickFrequency()) * 1000 / TIMES;
    std::ostringstream ss;
    ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
    putText(image, ss.str(), cv::Point(20, 20), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 255), 2, 8);
    imshow("method3", image);
}

//當(dāng)圖像數(shù)據(jù)是連續(xù)的,就可以從矩陣的第一個(gè)元素開始
//按相對(duì)位置訪問(wèn)整個(gè)矩陣
void method_4(cv::Mat image)
{
    //assert(image.isContinuous());
    //std::cout <<"image.isContinuous():"<< image.isContinuous()<< std::endl;

    double startTime = cv::getTickCount();
    int w = image.cols;
    int h = image.rows;
    uchar * imgPtr = NULL;
    for (int times = 0; times < TIMES; times++)
    {
        //image.data與image.ptr<uchar>(0)等價(jià)蹂匹;
        for (int row = 0; row < h; row++) {
            imgPtr = image.data + row * image.step;
            for (int col = 0; col < w; col++) {
                //以下三種方式都是等價(jià)的碘菜,
                *(imgPtr + col*3) = 255 - *(imgPtr + col * 3);
                *(imgPtr + col * 3 + 1) = 255 - *(imgPtr + col * 3 + 1);
                *(imgPtr + col * 3 + 2) = 255 - *(imgPtr + col * 3 + 2);

                /*imgPtr[col * 3] = 255 - imgPtr[col * 3];
                imgPtr[col * 3 + 1] = 255 - imgPtr[col * 3 + 1];
                imgPtr[col * 3 + 2] = 255 - imgPtr[col * 3 + 2];*/

                /**(imgPtr++) = 255 - *(imgPtr);
                *(imgPtr++) = 255 - *(imgPtr);
                *(imgPtr++) = 255 - *(imgPtr);*/
            }
        }
    }
    double endTime = cv::getTickCount();
    double t = ((endTime - startTime) / cv::getTickFrequency()) * 1000 / TIMES;
    std::ostringstream ss;
    ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
    putText(image, ss.str(), cv::Point(20, 20), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 255), 2, 8);
    imshow("method4", image);
}


int main()
{
    std::string imagePath = "K:\\deepImage\\building.jpg";
    cv::Mat m1 = cv::imread(imagePath);
    //cv::resize(m1, m1, cv::Size(1000, 1000));
    method_1(m1.clone());
    method_2(m1.clone());
    method_3(m1.clone());
    method_4(m1.clone());
    cv::waitKey(0);

    return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子炉媒,更是在濱河造成了極大的恐慌,老刑警劉巖昆烁,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吊骤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡静尼,警方通過(guò)查閱死者的電腦和手機(jī)白粉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鼠渺,“玉大人鸭巴,你說(shuō)我怎么就攤上這事±鬼铮” “怎么了鹃祖?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)普舆。 經(jīng)常有香客問(wèn)我恬口,道長(zhǎng),這世上最難降的妖魔是什么沼侣? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任祖能,我火速辦了婚禮,結(jié)果婚禮上蛾洛,老公的妹妹穿的比我還像新娘养铸。我一直安慰自己,他們只是感情好轧膘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布钞螟。 她就那樣靜靜地躺著,像睡著了一般扶供。 火紅的嫁衣襯著肌膚如雪筛圆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天椿浓,我揣著相機(jī)與錄音太援,去河邊找鬼。 笑死扳碍,一個(gè)胖子當(dāng)著我的面吹牛提岔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播笋敞,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼碱蒙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起赛惩,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哀墓,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后喷兼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體篮绰,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年季惯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吠各。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勉抓,死狀恐怖贾漏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情藕筋,我是刑警寧澤纵散,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站念逞,受9級(jí)特大地震影響困食,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翎承,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一硕盹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叨咖,春花似錦瘩例、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至趣倾,卻和暖如春聘惦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背儒恋。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工善绎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诫尽。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓禀酱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親牧嫉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剂跟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容