圖像處理之vImage(一)

vImage學(xué)習(xí)筆記(一)——概述

一、關(guān)于圖像格式 Image Formats

圖像格式(Image Formats)規(guī)定了像素數(shù)據(jù)如何在內(nèi)存中存儲莉测。圖像文件格式(比如JPG、PNG唧喉、GIF等)用來在程序中轉(zhuǎn)換圖像數(shù)據(jù)捣卤,并將數(shù)據(jù)存儲在硬盤上忍抽。諸如Image I/O等框架可以從硬盤加載各種格式的圖像文件,并且在內(nèi)存中使用董朝。在內(nèi)存中鸠项,圖像是通過二維數(shù)組來存儲像素數(shù)據(jù)的,圖像中的每個像素都對應(yīng)數(shù)組中的一個元素子姜。

圖像格式(Image Formats)包含兩種類型:二維平面型(planar)和交叉型(interleaved)祟绊。二維平面型圖像把不同通道的數(shù)據(jù)存儲在不同的緩沖區(qū)內(nèi),一個典型的平面型圖像通常包括red闲询、green久免、blue和alpha四個通道浅辙。交叉型圖像把不同通道的數(shù)據(jù)輪換著存儲:ARGBARGBARGB……

圖像數(shù)據(jù)可以是整型(integer)和浮點型(float)扭弧。在vImage中,通過一個8位(bit)的無符號整型數(shù)值表示色飽和度等級记舆。數(shù)值范圍0255鸽捻,255表示最大色飽和度,0表示無色飽和度泽腮。浮點型數(shù)值通常從0.01.0表示色飽和度御蒲。

以下是核心操作使用到的圖像格式:

  • Planar8  單通道(顏色或alpha)圖像。每個像素都是一個8bit的無符號整數(shù)诊赊,數(shù)據(jù)類型是Pixel_8
  • PlanarF  單通道(顏色)圖像厚满。每個像素都是一個32bit的浮點數(shù),數(shù)據(jù)類型是Pixel_F
  • ARGB8888  圖像包含四個交叉通道碧磅,alpha碘箍、red、green鲸郊、blue丰榴,順序固定。每個像素都是一個32位的數(shù)組(包含四個8位無符號整數(shù))秆撮。數(shù)據(jù)類型是Pixel_8888
  • ARGBFFFF  圖像包含四個交叉通道四濒,alpha、red职辨、green盗蟆、blue,順序固定舒裤。每個像素都是一個包含四個浮點數(shù)的數(shù)組姆涩。數(shù)據(jù)類型是Pixel_FFFF
  • RGBA8888  圖像包含四個交叉通道,red惭每、green骨饿、blue亏栈、alpha,順序固定宏赘。每個像素都是一個32位的數(shù)組(包含四個8位無符號整數(shù))绒北。數(shù)據(jù)類型是Pixel_8888
  • RGBAFFFF  圖像包含四個交叉通道,red察署、green闷游、blue、alpha贴汪,順序固定脐往。每個像素都是一個包含四個浮點數(shù)的數(shù)組。數(shù)據(jù)類型是Pixel_FFFF

可以將其他格式的圖像轉(zhuǎn)換為vImage的圖像格式扳埂。例如业簿,可以通過vImageConvert_16SToF函數(shù)將一個16位像素的圖像轉(zhuǎn)換為vImage支持的32位像素。下面這些函數(shù)可以幫助你在vImage圖像格式之間進(jìn)行轉(zhuǎn)換阳懂,也可以把vImage不支持的圖像格式轉(zhuǎn)換為vImage格式梅尤。

  • vImageConvert_16SToF    將一個16位符號整型planar圖像格式(或 vImage_Buffer.width=4的interleaved-multiply)緩沖區(qū)( vImage_Buffer )轉(zhuǎn)換為浮點型數(shù)值緩沖區(qū)
  • vImageConvert_16UToF   將一個16位無符號整型planar圖像格式(或 vImage_Buffer.width=4的interleaved-multiply)緩沖區(qū)( vImage_Buffer )轉(zhuǎn)換為浮點型數(shù)值緩沖區(qū)
  • ImageConvert_FTo16S   將一個浮點型planar圖像格式(或 vImage_Buffer.width=4的interleaved-multiply)緩沖區(qū)( vImage_Buffer )轉(zhuǎn)換為16位符號整型緩沖區(qū)
  • vImageConvert_FTo16U   將一個浮點型planar圖像格式(或 vImage_Buffer.width=4的interleaved-multiply)緩沖區(qū)( vImage_Buffer )轉(zhuǎn)換為16位無符號整型緩沖區(qū)
  • vImageConvert_16UtoPlanar8   將一個16位無符號整型planar圖像格式(或 vImage_Buffer.width=4的interleaved-multiply)緩沖區(qū)( vImage_Buffer )轉(zhuǎn)換為8位整型緩沖區(qū)
  • vImageConvert_Planar8to16U   將一個8位整型planar圖像格式(或 vImage_Buffer.width=4的interleaved-multiply)緩沖區(qū)( vImage_Buffer )轉(zhuǎn)換為16位無符號整型緩沖區(qū)
  • vImageConvert_ARGB1555toPlanar8   將16位/像素圖像(alpha通道1bit,red/green/blue通道5bit)轉(zhuǎn)換為Planar8格式岩调。
  • vImageConvert_ARGB1555toARGB8888   將16位/像素圖像(alpha通道1bit巷燥,red/green/blue通道5bit)轉(zhuǎn)換為ARGB8888格式。
  • vImageConvert_Planar8toARGB1555   將Planar8格式圖像轉(zhuǎn)換為包含1bit alpha号枕,5bit red缰揪,5bit green,5bit blue的16位/像素圖像葱淳。
  • vImageConvert_ARGB8888toARGB1555   將ARGB8888格式圖像轉(zhuǎn)換為包含1bit alpha钝腺,5bit red,5bit green蛙紫,5bit blue的16位/像素圖像拍屑。
  • vImageConvert_RGB565toPlanar8   將5bit red,6bit green坑傅,5bit blue的16位/像素圖像轉(zhuǎn)換為Planar8
  • vImageConvert_RGB565toARGB8888   將5bit red僵驰,6bit green,5bit blue的16位/像素圖像轉(zhuǎn)換為ARGB8888
  • vImageConvert_Planar8toRGB565   將Planar8圖像轉(zhuǎn)換為5-6-6圖像
  • vImageConvert_ARGB8888toRGB565   將ARGB8888圖像轉(zhuǎn)換為5-6-5圖像
  • vImageConvert_Planar16FtoPlanarF   將16位浮點型planar圖像轉(zhuǎn)換為32位浮點型

二唁毒、vImage練習(xí)

Loading Image Data

要將vImage集成到你的應(yīng)用中蒜茴,首先要把raw圖像數(shù)據(jù)加載到內(nèi)存〗鳎可以使用Image I/O框架把任何主流的圖像文件(JPG粉私、PNG、GIF等)加載到C類型緩沖池中(void *arrays)近零。

以下是從本地文件提取raw圖像數(shù)據(jù)的例子:

NSURL* url = [NSURL fileURLWithPath:filename];
//Create the image source with the options left null for now
//Keep in mind since we created it, we're responsible for getting rid of it
CGImageSourceRef image_source = CGImageSourceCreateWithURL( (CFURLRef)url, NULL);
if(image_source == NULL)
{
    //Something went wrong
    fprintf(stderr, "VImage error: Couldn't create image source from URL\n");
    return false;
}
//Now that we got the source, let's create an image from the first image in the CGImageSource
CGImageRef image = CGImageSourceCreateImageAtIndex(image_source, 0, NULL);
 
//We created our image, and that's all we needed the source for, so let's release it
CFRelease(image_source);
 
if(image == NULL)
{
    //something went wrong
    fprintf(stderr, "VImage error: Couldn't create image source from URL\n");
    return false;
}

把圖像加載到內(nèi)存之后诺核,就可以通過vImage函數(shù)進(jìn)行各種處理了抄肖。請密切注意函數(shù)下劃線之后的字符,那代表了像素數(shù)據(jù)的格式窖杀。vImage函數(shù)既可以在源緩沖區(qū)中直接處理漓摩,也可以在提供的目標(biāo)緩沖區(qū)中處理。

由于vImage只負(fù)責(zé)處理圖像入客,你還需要想辦法把圖像顯示出來管毙。根據(jù)你的應(yīng)用開發(fā)環(huán)境(Carbon or Cocoa),你需要找到一個方法(例如Quartz)去顯示合成后的像素數(shù)據(jù)桌硫,或?qū)D像數(shù)據(jù)存儲到磁盤(Image I/O)夭咬。

使用二維圖像格式

大多數(shù)vImage函數(shù)是從四種圖像格式開始的。二維圖像每次編碼一個通道(先存儲所有的紅色通道數(shù)據(jù)铆隘,然后是綠色卓舵,藍(lán)色,alpha)咖驮,而交叉圖像在內(nèi)存是混合存儲所有通道的边器。

注意:有時候你可能并不需要處理所有的通道训枢。比如托修,你知道你要處理的圖像中是不需要alpha通道的,或可能你的圖像是灰度圖恒界,因此你只需要一個通道睦刃。這種情況下,使用二維圖像格式可以讓你把需要的通道隔離出來十酣。

拼貼(Tiles)技術(shù)

在圖像應(yīng)用中涩拙,通常要使用Tiles將一個圖像分割成幾個小圖。之所以稱為tiling技術(shù)耸采,是因為這看起來很像是把多個地板瓷磚拼接成一大塊兒的過程兴泥,圖像中多個小的單位拼貼在一起,形成一個大的圖像虾宇。這個技術(shù)的優(yōu)勢在于搓彻,把數(shù)據(jù)分散成N個小的單位后,可以分散填充到高速緩存中嘱朽,這使CPU的處理速度加快了許多旭贬。

通常來說,當(dāng)被處理的數(shù)據(jù)(包括輸入數(shù)據(jù)和輸出數(shù)據(jù))放在處理器的數(shù)據(jù)緩存中時搪泳,vImage具有更好的性能稀轨。訪問處理器緩存中的數(shù)據(jù)比訪問內(nèi)存數(shù)據(jù)要快很多。然而CPU緩存是很快岸军,但是它在空間上是有限制的奋刽。不同的CPU緩存大小不一樣瓦侮,但總的來說,在Intel處理器中保存少于2MB的tile圖像佣谐,還有在PowerPC處理器中保存少于512KB的tile還是很有優(yōu)勢的脏榆。

  • 以下是Tiles技術(shù)的一些技巧:

    • 有些CPU緩存一次只能保存很少量的數(shù)據(jù)(通常是512KB或更少)
      • 128KB - 512KB的tile數(shù)據(jù)吞吐量最優(yōu)
    • 很多vImage函數(shù)內(nèi)部可以使用tile技術(shù)(還有多線程)。如果你想自己控制tiling台谍,可以在調(diào)用函數(shù)時在flags參數(shù)中添加kvImageDoNotTile標(biāo)記须喂,這樣可以避免函數(shù)在內(nèi)部使用tiling或多線程技術(shù)。
    • 對于平方形tile趁蕊,128KB-256KB的tile大小具有最好的吞吐率坞生。
    • 不同函數(shù)的最優(yōu)tile大小也是不同的。具有少量字節(jié)計算的函數(shù)(大多數(shù)是轉(zhuǎn)換函數(shù))在file size 小于16KB時是最快的掷伙,典型的vImage函數(shù)在256KB tile size下是最快的是己。

數(shù)據(jù)緩沖排列

當(dāng)分配圖像的浮點型數(shù)據(jù)時,保持4個字節(jié)的排列是很重要的任柜。這說明你分配的字節(jié)數(shù)應(yīng)該是4的整數(shù)倍卒废。

以下是數(shù)據(jù)排列和緩沖區(qū)大小的一些技巧:

  • 盡管vImage默認(rèn)可以有更少的數(shù)據(jù)排列,但為了性能最優(yōu)化宙地,所有數(shù)據(jù)都應(yīng)該是16字節(jié)排列摔认,且rowbytes應(yīng)該是16的整數(shù)倍。
  • 浮點型數(shù)據(jù)必須至少是4字節(jié)宅粥,否則某些函數(shù)可能會報錯参袱。
  • 函數(shù)的rowBytes參數(shù)不能傳入2的冪次方。

緩沖區(qū)(buffer)重用機(jī)制

很多函數(shù)在執(zhí)行任務(wù)時秽梅,會使用臨時緩沖區(qū)來存儲中間值抹蚀。在一開始只需創(chuàng)建一次buffer,就可以在多個函數(shù)中使用企垦,這樣可以節(jié)省時間环壤。

如果你沒有提供buffer,這些函數(shù)會自行創(chuàng)建buffer(當(dāng)然钞诡,使用完后釋放)郑现。

如果你只需要調(diào)用幾次該函數(shù),并且不在意短暫的阻塞臭增,那么讓函數(shù)自行創(chuàng)建buffer是個明智的選擇懂酱。

每個使用到臨時buffer的函數(shù)都有一個src和desc參數(shù)(數(shù)據(jù)類型都是vImage_Buffer)。函數(shù)只使用了這些參數(shù)的height和width域誊抛;忽略data和rowBytes域列牺。

可能的話淹冰,應(yīng)用也應(yīng)該嘗試重用vImage_Buffer數(shù)據(jù)的data域指向的圖像緩沖區(qū)脖苏。這樣可以節(jié)省時間,否則還要重新分配并且把原來的buffer抹平。

在實際應(yīng)用中很钓,要盡可能的避免使用堆和其他可能引起阻塞的操作(比如內(nèi)存分配)旁赊。

適當(dāng)?shù)氖褂镁€程

vImage是線程安全的并且可重入蒸殿。如果你分割了你的圖像比默,你可以使用多線程處理不同的tiles。如果你使用不同的處理器處理不同的tiles驼修,你應(yīng)選擇那些水平方向上不相鄰的tiles殿遂。否則tile的邊緣可能會共享到cache,這有可能導(dǎo)致兩個處理器之間耗時的干擾乙各。

在vImage函數(shù)工作時墨礁,vImage的輸出buffer狀態(tài)是未知的。有可能buffer中的像素數(shù)據(jù)既不是起始數(shù)據(jù)也不是結(jié)束數(shù)據(jù)耳峦,而是計算過程中的一個中間值恩静。

在OS X 10.4之后,一些vImage函數(shù)在內(nèi)部使用了多線程技術(shù)蹲坷。他們自己做了參數(shù)檢查和多線程來提高性能驶乾。vImage維持了它延遲分配線程緩沖池的風(fēng)格去做這件事。這些線程一旦被創(chuàng)建就不會被銷毀循签,他們會被重用级乐。被調(diào)用的線程要等待上一個線程完成自己的任務(wù),在這之前會被阻塞懦底。使用內(nèi)部實現(xiàn)了多線程技術(shù)的函數(shù)是安全的唇牧。

線程安全的函數(shù)通過鎖來保持?jǐn)?shù)據(jù)一致性罕扎。如果你不希望函數(shù)使用鎖聚唐,你需要設(shè)置kvImageDoNotTile標(biāo)志位來阻止vImage使用多線程和tiling技術(shù)。如果你設(shè)置了該標(biāo)志位腔召,你的應(yīng)用需要自行處理數(shù)據(jù)tiling和多線程杆查。

把2D核分為1D核

如果你使用卷積方法對圖像添加濾鏡,你可以通過將2D核分裂為兩個1D核來提高性能臀蛛,這樣可以使用兩次卷積(一個維度可以使用一次)亲桦。

當(dāng)然,你可以將2D核傳給vImageConvolve函數(shù)浊仆。vImage使用2D核來完成9層8加的操作來計算每個像素結(jié)果客峭。為了更好的性能,對每個1D卷積濾鏡調(diào)用一次vImageConvolve函數(shù)抡柿。核分裂后舔琅,vImage通過每個卷積對每個像素執(zhí)行3層2加的操作,加起來是6層4加洲劣。我們注意到將核分裂成兩個后备蚓,算法復(fù)雜度在乘法上節(jié)省了1/3课蔬,在加法上節(jié)省了1/2。對于M×N的內(nèi)核郊尝,處理消耗從M*N驟減到M+N二跋。一個5×5的核分裂后的處理速度加快2.5倍,一個11×11的核分裂后可能加快超過5倍流昏。

注意這個技術(shù)在常規(guī)情況下是比較慢的扎即。一般在圖像特別大,或圖像無法存入內(nèi)存時使用這個技術(shù)况凉。

有幾種情況下铺遂,分裂特別大的濾鏡是執(zhí)行卷積操作的唯一方案。一個總計超過224的濾鏡茎刚,vImage使用8位的卷積操作下襟锐,運行起來會有內(nèi)存溢出的風(fēng)險。這個時候膛锭,可以采用分裂濾鏡來避免溢出粮坞,你甚至可以在放大濾鏡之前,通過分裂技術(shù)向濾鏡里添加更多的固定精度的點初狰。這種技術(shù)的中間值精度損失程度未知莫杈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市奢入,隨后出現(xiàn)的幾起案子筝闹,更是在濱河造成了極大的恐慌,老刑警劉巖腥光,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件关顷,死亡現(xiàn)場離奇詭異,居然都是意外死亡武福,警方通過查閱死者的電腦和手機(jī)议双,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捉片,“玉大人平痰,你說我怎么就攤上這事∥槿遥” “怎么了宗雇?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長莹规。 經(jīng)常有香客問我赔蒲,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任嘹履,我火速辦了婚禮腻扇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘砾嫉。我一直安慰自己幼苛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布焕刮。 她就那樣靜靜地躺著舶沿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪配并。 梳的紋絲不亂的頭發(fā)上括荡,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機(jī)與錄音溉旋,去河邊找鬼畸冲。 笑死,一個胖子當(dāng)著我的面吹牛观腊,可吹牛的內(nèi)容都是我干的邑闲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼梧油,長吁一口氣:“原來是場噩夢啊……” “哼苫耸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起儡陨,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤褪子,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后骗村,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫌褪,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年叙身,在試婚紗的時候發(fā)現(xiàn)自己被綠了渔扎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡信轿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出残吩,到底是詐尸還是另有隱情财忽,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布泣侮,位于F島的核電站即彪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜隶校,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一漏益、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧深胳,春花似錦绰疤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至敛劝,卻和暖如春余爆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背夸盟。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工蛾方, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人上陕。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓转捕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唆垃。 傳聞我的和親對象是個殘疾皇子五芝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

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