一种可实时处理 O(1)复杂度图像去雾算法的实现。
在我博文的一系列的文章,有不少算法都于去霧有關(guān),比如限制對(duì)比度自適應(yīng)直方圖均衡化算法原理、實(shí)現(xiàn)及效果、局部自適應(yīng)自動(dòng)色階/對(duì)比度算法在圖像增強(qiáng)上的應(yīng)用這兩個(gè)增強(qiáng)算法都有一定的去霧能力,而最直接的就是《Single Image Haze Removal Using Dark Channel Prior》一文中圖像去霧算法的原理、實(shí)現(xiàn)、效果及其他?一文,描述了暗通道去霧這一state-of-the-art algorithms的過程和實(shí)現(xiàn),雖幾經(jīng)優(yōu)化,對(duì)于常用的視頻1024*768大小的圖片,算法處理部分還是需要70MS的時(shí)間(I3 筆記本CPU),因此,這一算法用于實(shí)時(shí)要求時(shí)還有一定的難度,并且優(yōu)化后的算法基本無法并行,而可并行的算法重復(fù)計(jì)算大,由于不熟悉GPU方面的理念,不曉得使用不優(yōu)化的算法靠GPU是否能有多大速度的提升。
?????為此,我一直在找尋相關(guān)的論文,這種找尋的蹤跡一般就是看到一篇好論文--》看其參考文獻(xiàn)--》再看參考文獻(xiàn)的參考文獻(xiàn),這樣循環(huán)下去。 然后有某種機(jī)會(huì)或巧合,又看到一篇好論文,重復(fù)前面的過程,你就會(huì)發(fā)現(xiàn)很多交集,慢慢的就會(huì)有一些好運(yùn)向你招手。 話說我原本只看英文的文獻(xiàn),所以一直忽略了國(guó)內(nèi)的文章,前幾日,一個(gè)QQ朋友推薦了一篇清華大學(xué)的論文,下載后稍微看了下,覺得其描述的結(jié)果還是比較吸引人的,于是就實(shí)現(xiàn)了下,實(shí)時(shí)的效果應(yīng)該說很不錯(cuò),這里就簡(jiǎn)單的介紹并推薦給大家。
????? 原始論文下載:基于單幅圖像的快速去霧.pdf? ,作者劉倩,陳茂銀,周東華,感謝他們(她們)。
????? 算法原理沒有什么復(fù)雜的地方,其實(shí)說原理,還不如說經(jīng)驗(yàn)或?qū)嶒?yàn),因?yàn)檎撐闹锌梢杂美碚搧硗茖?dǎo)的公式確實(shí)不多。不過這也沒關(guān)系,有用的東西就應(yīng)該拿來用。
??????算法的執(zhí)行流程直接貼用原圖的文字來說明吧:
?????
?????先挑點(diǎn)小瑕疵,比如步驟5中的L有個(gè)下標(biāo),而其他涉及到L的地方去沒有,這叫前后不一致。論文中也還有一些其他的地方有些小錯(cuò)誤,所以看啊,即使是清華的文章,在編輯審核這一塊還是相當(dāng)?shù)牟粐?yán)謹(jǐn)。
???? 我們先來看看算法,1、2、3、4步都沒有什么說的,第五步是求大氣透射率的過程,這里ρ是一個(gè)用來調(diào)節(jié)的參數(shù),當(dāng)ρ值越大時(shí),結(jié)果圖像整體越暗,去霧的效果更明顯,ρ較小時(shí),圖像偏白,有明顯的霧氣。第六步求全局大氣光A值,用了很簡(jiǎn)單的方式,即求原始圖像的RGB所有像素分量的最大值(這個(gè)估計(jì)99%都為255了)何暗通道的最大值的平均值,并且注意到RGB三個(gè)通道用的A值都為同一個(gè)數(shù)字。這個(gè)和我在何凱明的文章的分析也有相似的地方。 第七步用了標(biāo)準(zhǔn)的去霧模型來求結(jié)果值。
???? 在來看看算法的效率問題,?從算法的初步分析來看,算法的效率取決于第3步和第7步,第三步中,使用了均值模糊,目前已經(jīng)存在大量的O(1)均值模糊算法,可是O(1)只能表示算法的執(zhí)行速度和參數(shù)的大小無關(guān)系,并不表示算法就很快。比如基于積分圖的模糊算法是廣為認(rèn)知的O(1)算法,但是他也存在很多問題,最嚴(yán)重的就是數(shù)據(jù)的溢出,當(dāng)圖像較大和偏白時(shí),對(duì)圖像積分圖的累加和存在超出int.Maxvalue所能表達(dá)的范圍的問題,解決辦法就是積分圖內(nèi)的數(shù)據(jù)全部使用long類型表示,這將導(dǎo)致程序多占用Width*Height*4字節(jié)的大小的內(nèi)存,且在32位系統(tǒng)還流行的情況進(jìn)一步降低程序的速度(32位系統(tǒng)64位整數(shù)的計(jì)算速度要比32位整數(shù)慢)。積分圖的另外一個(gè)問題就是計(jì)算積分圖的過程難以并行化,因?yàn)橐粋€(gè)像素的積分值是依賴于其前面一系列像素的相關(guān)結(jié)果值的。另外一種優(yōu)化方式就是先計(jì)算行方向的平均值,然后再計(jì)算列方向的值。這種方式在同一行(列)內(nèi),算法依舊必行順序執(zhí)行,這也是因?yàn)榍昂笥绊懙脑颉5遣煌?#xff08;列)之間的計(jì)算是沒有任何關(guān)系,因此非常適合GPU這種可大規(guī)模并行計(jì)算的場(chǎng)合,但不適于CPU這種重量級(jí)的線程并發(fā)(反而會(huì)慢)。這種算法如果為了精度會(huì)需要一個(gè)和原圖一樣大小,占用字節(jié)Width*Height*4字節(jié)大小的的中轉(zhuǎn)區(qū)用來保存中間計(jì)算的結(jié)果。在彩色圖像高速模糊之懶惰算法一文中,我采用了另外一種處理方法,利用列直方圖相關(guān)的技術(shù),只需對(duì)每個(gè)循環(huán)的起始位置處的像素做特殊處理,其他位置的利用簡(jiǎn)單的一加一簡(jiǎn)即可獲得累加和,從而快速的實(shí)現(xiàn)模糊,我實(shí)際的編碼表明,這種方式比其他的方式都要快。但是有一個(gè)缺點(diǎn),不適合于并行計(jì)算,不過在CPU上這個(gè)很有優(yōu)勢(shì)。
????? 再觀察下第七步。第七步存在兩個(gè)需要優(yōu)化的地方,第一,存在除法;第二,有浮點(diǎn)運(yùn)算。如果直接編碼必然會(huì)帶來性能損失,但是,觀察下在第七步的公式中,只有兩個(gè)自變量,H(X)和L(X),并且自變量的取值都為[0,255]之間的整數(shù),因此,如果事先建議一個(gè)查找表,由于這個(gè)查找表的計(jì)算量只有 256*256次,要遠(yuǎn)遠(yuǎn)的小于直接計(jì)算的次數(shù),必然能提高程序的速度。256這個(gè)數(shù)字還有個(gè)好處,就是可以用移位來輔助計(jì)算查表表的下標(biāo),部分參考代碼如下所示:
unsigned char * Table = (unsigned char *) malloc (256*256*sizeof(unsigned char)); for (Y = 0; Y < 256; Y++) {Index=Y<<8;for (X = 0; X < 256; X++){Value = (Y-X) /(1-X*InvA);if (Value > 255)Value = 255;else if (Value < 0)Value = 0;Table[Index++]= Value;} }其中InvA = 1 / A;A為全局大氣光值。 Value需為double類型的變量。
???? 當(dāng)我們需要計(jì)算F(x)時(shí),查表的方式為 F(X)=Table[(H[X]<<8 )+ L[X]];
?????實(shí)際的效果表明,這樣的方式對(duì)于1024*768的圖,可以提速10ms。
?????那么對(duì)于其他步驟也有很多優(yōu)化的注意事項(xiàng),比如計(jì)算M(X)中所有元素的平均值Mav這一塊,完全沒有必要在開一個(gè)循環(huán),而是可以在進(jìn)行步驟3的時(shí)候同步進(jìn)行,大家知道,循環(huán)楚了要計(jì)算循環(huán)體內(nèi)部的東西外,還要有個(gè)循環(huán)計(jì)數(shù)器的更新的,何必浪費(fèi)這個(gè)時(shí)間呢。
for (Y = 0, DarkPt = DarkChannel; Y < Height; Y++) {ImgPt = Src + Y * Stride;for (X = 0; X < Width; X++){Min = *ImgPt;if (Min > *(ImgPt + 1)) Min = *(ImgPt + 1);if (Min > *(ImgPt + 2)) Min = *(ImgPt + 2);*DarkPt = Min; // 三通道的最小值Sum += Min; // 累積以方便后面求平均值ImgPt += 3;DarkPt++;} } Mean =(double)Sum /(Width*Height*255);??? 還有比如第6步中,分別求原圖RGB三像素最大值以及安通道中的最大值的過程,傳統(tǒng)的過程如下代碼:
int Max1 =0 ; for (Y = 0; Y < Height; Y++) {ImgPt = Src + Y * Stride;for (X = 0; X < Width; X++){if (Max1 < *(ImgPt)) Max1 = *(ImgPt);if (Max1 < *(ImgPt + 1)) Max1 = *(ImgPt + 1);if (Max1 < *(ImgPt + 2)) Max1 = *(ImgPt + 2);ImgPt += 3;} }特別是對(duì)于求原圖的最大值,實(shí)際上很多情況下這個(gè)值都為255,因此如果Max1變量已經(jīng)是255,則循環(huán)完全沒有必要進(jìn)行下去了,因此,如果改為下述代碼,必然可以減少計(jì)算量:
for (Y = 0; Y < Height; Y++) {ImgPt = Src + Y * Stride;for (X = 0; X < Width; X++){if (Max1 < *(ImgPt)) Max1 = *(ImgPt);if (Max1 < *(ImgPt + 1)) Max1 = *(ImgPt + 1);if (Max1 < *(ImgPt + 2)) Max1 = *(ImgPt + 2);ImgPt += 3;}if (Max1==255) break; }????? 注意,這個(gè)break語句必須放在Y循環(huán)中,如果放在X循環(huán)中,雖然提前退出循環(huán)的可能性會(huì)增加,但是判斷的工作量帶來的損失更多。
??????綜合上述優(yōu)化,我用C++寫了個(gè)DLL,對(duì)于1024*768的圖像在我的I3的機(jī)器上平均能達(dá)到18ms每副圖像的計(jì)算速度,相當(dāng)于56fps,只占用了單核的資源,考慮解碼、顯示等等其他過程所占用的時(shí)間,應(yīng)該是能夠靠CPU實(shí)現(xiàn)20fps的實(shí)時(shí)速度的。
????? 在內(nèi)存占用上,約需要> 3*Width*Height+256*256字節(jié)的空間(不包括圖像本身的),如果用在連續(xù)的視頻處理上,這部分內(nèi)存就不需要頻繁的分配和釋放,可能也對(duì)速度的保證有好處。
???? 程序下載地址: http://files.cnblogs.com/Imageshop/FastHazeRemovalTest.rar
??
參數(shù)的選取:
?? 為了獲得好的效果,該算法需要選擇恰當(dāng)?shù)膮?shù),我們?yōu)榇俗隽艘恍y(cè)試。對(duì)于半徑參數(shù),我的個(gè)人建議是取值不要小于50或圖像寬度和高度最大值的的1/20,比如對(duì)下面的圖像(原圖大小不是下圖中的大小,這里是為了方便瀏覽縮小顯示的),ρ取1.28時(shí)(對(duì)于上圖中的去霧程序選擇為128),半徑取不同參數(shù)時(shí)的效果:
???
??? 原圖 ??? ?? r=16 ? r=50
?? 注意上面中間的圖,一群飛鳥的周邊明顯有格格不入的白色霧氣,而在右側(cè)的圖中,飛鳥則自然的融入了背景圖像中。
???另外,當(dāng)半徑足夠大時(shí),半徑的大小對(duì)輸出的結(jié)果的影響不大。
?? ρ參數(shù)的大小控制了圖像去霧能力的大小,越大,霧氣越少,圖像越顯得暗,越小,圖像偏白,霧氣越濃,下面給出了在半徑R=50,取不同ρ值的效果。
???
???
???
??? 原圖 ??? ?? ρ=0.75 ? ρ=1.3
???? ρ值如何取才能獲得最佳效果,這個(gè)沒有理論依據(jù),需要根據(jù)具體圖像進(jìn)行測(cè)試,不過一般在1.2到1.5之間的效果能綜合去霧和保持圖像清晰的能力。
???? 從更多的測(cè)試圖看,該去霧算法的效果都是較為理想的,而且對(duì)于填充部位出現(xiàn)瑕疵的情況也出現(xiàn)的很少,速度上更是沒的說,因此,作為一種實(shí)時(shí)去霧工業(yè)化也應(yīng)該是可行的。
???? 試過將過程中的均值模糊更改為高斯模糊,在速度上會(huì)稍有下降,也能達(dá)到實(shí)時(shí)要求,但去霧的效果似乎還沒有均值好。
????
?
*****************************基本上我不提供源代碼,但是我會(huì)盡量用文字把對(duì)應(yīng)的算法描述清楚或提供參考文檔*********************
*************************************因?yàn)榭孔约旱呐蛯?shí)踐寫出來的效果才真正是自己的東西,人一定要靠自己****************************
*********************************作者: laviewpbt ? 時(shí)間: 2013.11.4???聯(lián)系QQ: ?33184777 ?轉(zhuǎn)載請(qǐng)保留本行信息************************
轉(zhuǎn)載于:https://my.oschina.net/abcijkxyz/blog/792280
總結(jié)
以上是生活随笔為你收集整理的一种可实时处理 O(1)复杂度图像去雾算法的实现。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tensorflow2.0实现对抗生成网
- 下一篇: arcgis快速生成图框_ArcGIS中