圖像增強與圖像修復二者之間有一定交叉,盡管它們一個強調客觀標准,一個強調主觀標准,但畢竟最終的結果都改善了圖像的質量。圖像去霧就是這兩種技術彼此交叉領域中最典型的代表。如果將霧霾看作是一種噪聲,那么去除霧霾的標准顯然是非常客觀的,也就是要將圖像恢復至沒有霧霾下所獲取的情況。但是如果將在霧霾環境下拍攝的照片就看作是一種圖像本來的面貌,那么去霧顯然就是人們為了改善主觀視覺質量而對圖像所進行的一種增強。早期圖像去霧的研究並沒有得到應有的重視,很多人認為它的實際意義不大,甚至覺得所謂的去霧算法多是些華而不實的花拳綉腿,缺乏學術上的價值。然而,斗轉星移,時易世變。一方面隨着大氣污染的日益嚴重,設法改善自動獲取的圖像質量其意義不言而喻。另一方面,隨着數碼設備的普及,消費類電子產品的市場也催生出許多新的需求,其中人們對所拍照片質量的修正和優化就是一個顯而易見的需求。說到圖像去霧,就不得不提到由何愷明博士等人提出的基於暗通道的圖像去霧算法。這個算法因其新穎的思路和理想的效果而廣受關注,相關論文也曾於2009年榮獲CVPR最佳論文獎,同時也是該獎設立以來,首次由亞洲學者獲頒此殊榮。
現在結果已經比較細膩了,但是顯然圖像有些暗。何博士在論文中也有提及直接暗通道算法的結果會是比較暗的。下一篇文章中,我們將給出在MATLAB中實現的源代碼,並對過暗的圖像增加曝光和自動色階,從而得到完美的去霧圖像。
我們已經了解了暗通道圖像去霧算法的基本原理,下面我們來編程實現,然后對結果再做一些討論。
上述代碼中調用了幾個函數,限於篇幅這里僅給出其中的暗通道處理函數,其余函數讀者可以嘗試自己寫寫看,當然其中最關鍵的就是暗通道處理函數,這也是算法的核心內容。
1 %darkchannel.m 2 %求一幅圖像的暗通道圖像,窗口大小為15*15 3 imageRGB = imread('D:\\tmppic\\1.jpg'); 4 imageRGB = double(imageRGB); 5 imageRGB = imageRGB./255; 6 dark = darkfunction(imageRGB); 7 imshow(dark); 8 %選取通道中最亮的0.1%像素,從而求得大氣光 9 [m, n, ~] = size(imageRGB); 10 imsize = m*n; 11 numpx = floor(imsize/1000); 12 JDarkVec = reshape(dark, imsize,1); 13 ImVec = reshape(imageRGB, imsize, 3); 14 imshow(ImVec); 15 [JDarkVec, indices] = sort(JDarkVec); 16 indices = indices(imsize-numpx+1:end); 17 18 atmSum = zeros(1, 3); 19 for ind = 1:numpx 20 atmSum = atmSum + ImVec(indices(ind),:); 21 end 22 atmospheric = atmSum / numpx; 23 %求解透射率,並通過omega參數來選擇保留一定程度霧霾,一面損壞真實感 24 omega = 0.95; 25 im = zeros(size(imageRGB)); 26 27 for ind = 1:3 28 im(:,:,ind) = imageRGB(:,:,ind)./atmospheric(ind); 29 end 30 31 dark_2 = darkfunction(im); 32 t = 1- omega*dark_2; 33 34 %通過導向濾波來獲得更為精細的投射率圖 35 % r = 60; 36 % eps = 10^-6; 37 % refined_t = guidedfilter_color(imageRGB, t, r, eps); 38 % 39 % refinedRadiance = getRadiance(atmospheric, imageRGB, refined_t); 40 disp(atmospheric); 41 %disp(t); 42 43 for i = 1:m; 44 for j = 1:n; 45 for c = 1:3 46 imageRGB(i,j,c) = (imageRGB(i,j,c) - atmospheric(c))/max(t(i,j),0.1) + atmospheric(c); 47 end 48 end 49 end 50 51 imshow(imageRGB);
1 %函數 2 function [dark] = darkfunction(imRGB) 3 4 r = imRGB(:,:,1); 5 g = imRGB(:,:,2); 6 b = imRGB(:,:,3); 7 8 [m n] = size(r); 9 a = zeros(m,n); 10 for i = 1:m; 11 for j = 1:n; 12 a(i,j) = min(r(i,j),g(i,j)); 13 a(i,j) = min(a(i,j),b(i,j)); 14 end 15 end 16 17 d = ones(15,15); 18 fun = @(block_struct)min(min(block_struct.data))*d; 19 dark = blockproc(a, [15 15], fun); 20 dark = dark(1:m, 1:n); 21 22 end
另外,代碼里我們使用了導向濾波函數,導向濾波代碼來自何愷明博士,讀者可以訪問他的網頁獲得源碼,已經論文的原文,鏈接如下:
http://research.microsoft.com/en-us/um/people/kahe/
另外,下面這個博客里有一些關於導向濾波的比較通俗的討論,可以作為閱讀論文原文時的輔助材料:
http://blog.csdn.net/aichipmunk/article/details/20704681
最后一個小討論,我們所采用的方法英文叫 Dark Channel Prior,很多人困惑 Prior該怎么翻譯,我標題里采用了優先這個叫法,這個是一個比較常見的叫法,我也隨世流俗了,因為Prior在英文里確實有這個意思。但是這個通常的叫法其實欠妥,最好翻成 “先驗”。在上一篇文章中,我們討論過這個算法的原理,其實算法是把 暗通道的有關結論作為一個先驗條件來使用的,就像我們以前做 數學證明題,會有一些 結論或者定理 即使題目中沒給我們也可以直接用,那些結論或者定理就是 先驗的 條件,是不需要直接給出也可以使用的。