OpenCV 圖像遍歷與顏色縮減

圖像處理的基礎(chǔ)是對圖像每一個像素點的遍歷,即圖像掃描百匆。在本節(jié)中砌些,將介紹幾種不同的圖像遍歷方式,為了對比不同方法的效率加匈,我們不是單純的遍歷存璃,而是對圖像做更多的處理。在此矩动,我們測試的是一種簡單的顏色縮減方法有巧。為了比較不同遍歷算法的運行時間,你還將看到 OpenCV 中計時函數(shù)的用法悲没。

1. 概述

圖像處理的基礎(chǔ)是對圖像每一個像素點的遍歷篮迎,即圖像掃描男图。在本節(jié)中,將介紹幾種不同的圖像遍歷方式甜橱,為了對比不同方法的效率逊笆,我們不是單純的遍歷,而是對圖像做更多的處理岂傲。在此难裆,我們測試的是一種簡單的顏色縮減方法。為了比較不同遍歷算法的運行時間镊掖,你還將看到 OpenCV 中計時函數(shù)的用法乃戈。

2. 圖像存儲方式

在進行下面的論述之前,先對圖像矩陣在內(nèi)存中的存儲方式簡單介紹亩进。對于單通道灰度圖像:

而對于多通道圖像來說症虑,矩陣中的列會包含多個子列,子列數(shù)與通道數(shù)相等归薛,如 BGR 顏色模型的矩陣為:

3. 顏色縮減

何謂顏色縮減谍憔?對于元素類型為 uchar 的單通道圖像矩陣,每個像素點有 256 個灰度值主籍,但是對于三通道圖像习贫,每個像素點的顏色種類達(dá) 16777216 種(256 的三次方)。如此多的顏色可能會對算法性能造成嚴(yán)重影響千元,我們往往只需要顏色的一部分苫昌,也能滿足要求,因此引入了顏色縮減诅炉。

如上圖所示蜡歹,左側(cè)為顏色縮減前,右側(cè)為顏色縮減后涕烧,數(shù)字表示灰度值月而。可以看出议纯,灰度值 92 到 114 映射為 92父款;115 到 137 映射為 115,以此類推瞻凤,左側(cè) 164 種顏色縮減為右側(cè)的 7 種顏色憨攒。實現(xiàn)方法也很簡單:

//color1輸入,color2輸出 
color2 = (color1 / 23) * 23;

但是,如果直接對圖像的每個像素進行上述除法和乘法阀参,這樣效率是很低的肝集。一個較好的辦法是事先生成一張顏色縮減的查找表,表中縮減前后的值都明確給定蛛壳,這樣遍歷圖像時杏瞻,利用查找表直接對相應(yīng)像素點進行賦值即可所刀。其優(yōu)勢在于只需讀取、無需計算捞挥。以下代碼生成顏色查找表 color_table:

// 生成顏色查找表
vector<int> color_table;
int width = 20;
for (int i = 0; i < 256; i++)
{
    color_table.push_back(i / width * width);
}

4. 圖像遍歷

有了顏色查找表后浮创,我們便可以對圖像進行遍歷并對像素點進行顏色縮減了。我們采用了幾種不同的圖像遍歷方法砌函,為了對比它們的效率斩披,采用 OpenCV 提供的兩個簡單的計時器函數(shù) getTickCount() 和 getTickFrequency(), 它們分別返回 CPU 走過的時鐘周期數(shù)和 CPU 一秒的時鐘周期數(shù)。因此讹俊,可以這樣來計時(單位:秒):

double time_begin = (double)getTickCount();
// do something
double time_end = (double)getTickCount();
double time = (time_end - time_begin) / getTickFrequency();

4.1 利用指針遍歷

Mat& ScanImageAndReduceC(Mat& I, vector<int> color_table)
{
     //只接收字符型矩陣
     CV_Assert(I.depth() != sizeof(uchar));
     int channels = I.channels(); //獲取圖像通道數(shù)
     int row = I.rows * channels;
     int col = I.cols;
     uchar* p;
     if (I.isContinuous()) //判斷像素是否連續(xù)存儲
     {
           col *= row;
           row = 1;
     }
     for (int i = 0; i < row; i++)
     {
           p = I.ptr<uchar>(i);
           for (int j = 0; j < col; j++)
           {
                p[j] = color_table[p[j]];
           }
     }
     return I;
}

顏色縮減結(jié)果(根據(jù)查找表的width設(shè)置縮減的程度垦沉,在此 width = 20)

算法執(zhí)行時間為 0.0134007 秒。

4.2 利用迭代器遍歷

Mat& ScanImageAndReduceIterator(Mat& I, vector<int> color_table)
{
     //只接收字符型矩陣
     CV_Assert(I.depth() != sizeof(uchar));
     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 = color_table[*it];
           break;
     }
     case 3:
     {
           MatIterator_<Vec3b> it, end;
           for (it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; it++)
           {
                (*it)[0] = color_table[(*it)[0]];
                (*it)[1] = color_table[(*it)[1]];
                (*it)[2] = color_table[(*it)[2]];
           }
           break;
     }
     }
     return I;
}

算法執(zhí)行時間 0.0693951 秒劣像。用迭代器遍歷速度稍慢乡话,但是更加安全摧玫。上述代碼中耳奕,我們首先對圖像的通道數(shù)進行判斷,通道數(shù)為 1 時诬像,直接對灰度值賦值屋群;對于三通道彩色圖像,每個像素可以看做一個包含三個 uchar 元素的 vector, 在 OpenCV 中用 Vec3b 命名坏挠。對于彩色圖像衅胀,如果我們僅僅使用 uchar 而不是 Vec3b 迭代的話就只能獲得藍(lán)色通道的值(BGR模型中的第一個通道)墅冷。

4.3 通過相關(guān)返回值的 On-the-fly 地址遍歷

Mat& ScanImageAndReduceRadomAccess(Mat& I, vector<int> color_table)
{
     //只接收字符型矩陣
     CV_Assert(I.depth() != sizeof(uchar));
     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) = color_table[I.at<uchar>(i, j)];
                }
           }
           break;
     }
     case 3:
     {
           for (int i = 0; i < I.rows; i++)
           {
                for (int j = 0; j < I.cols; j++)
                {
                      I.at<Vec3b>(i, j)[0] = color_table[I.at<Vec3b>(i, j)[0]];
                      I.at<Vec3b>(i, j)[1] = color_table[I.at<Vec3b>(i, j)[1]];
                      I.at<Vec3b>(i, j)[2] = color_table[I.at<Vec3b>(i, j)[2]];
                }
           }
           break;
     }
     }
     return I;
}

通過 at() 函數(shù)獲取并更改圖像中的元素。事實上,這種方法并不推薦唄用來進行圖像掃描寒屯。

4.4 核心函數(shù) LUT (The Core Function)

核心函數(shù) LUT 是最被推薦用于實現(xiàn)批量圖像元素查找和更改的方法,它并不需要你自己去掃描圖像逗栽。我們先建立一個查找表:

Mat table(1, 256, CV_8U);
uchar* p = table.data;
for(int i = 0; i < 256; i++)
    p[i] = color_table[i];

然后調(diào)用函數(shù):

//image是輸入慈格,image_reduce是輸出
LUT(image, table, image_reduce);

4.5 結(jié)論

盡量使用 OpenCV 內(nèi)置函數(shù),調(diào)用 LUT 函數(shù)可以獲得最快的速度蛋褥,這是因為 OpenCV 庫可以通過英特爾線程架構(gòu)啟用多線程临燃,當(dāng)然,迭代器也是一個不錯的選擇烙心,優(yōu)點是安全膜廊,缺點是速度較慢,on-the-fly方法不推薦使用淫茵。


More

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爪瓜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子匙瘪,更是在濱河造成了極大的恐慌铆铆,老刑警劉巖炬转,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異算灸,居然都是意外死亡扼劈,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門菲驴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荐吵,“玉大人,你說我怎么就攤上這事赊瞬∠燃澹” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵巧涧,是天一觀的道長薯蝎。 經(jīng)常有香客問我,道長谤绳,這世上最難降的妖魔是什么占锯? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮缩筛,結(jié)果婚禮上消略,老公的妹妹穿的比我還像新娘。我一直安慰自己瞎抛,他們只是感情好艺演,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著桐臊,像睡著了一般胎撤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上断凶,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天伤提,我揣著相機與錄音,去河邊找鬼懒浮。 笑死飘弧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的砚著。 我是一名探鬼主播次伶,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼稽穆!你這毒婦竟也來了冠王?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤舌镶,失蹤者是張志新(化名)和其女友劉穎柱彻,沒想到半個月后豪娜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡哟楷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年瘤载,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卖擅。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸣奔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惩阶,到底是詐尸還是另有隱情挎狸,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布断楷,位于F島的核電站锨匆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏冬筒。R本人自食惡果不足惜恐锣,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望账千。 院中可真熱鬧侥蒙,春花似錦、人聲如沸匀奏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娃善。三九已至,卻和暖如春瑞佩,著一層夾襖步出監(jiān)牢的瞬間聚磺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工炬丸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瘫寝,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓稠炬,卻偏偏與公主長得像焕阿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子首启,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

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