1. 程式人生 > >影象去霧之何凱明暗通道先驗去霧演算法原理及c++程式碼實現

影象去霧之何凱明暗通道先驗去霧演算法原理及c++程式碼實現

http://blog.csdn.net/s12244315/article/details/50292049

何凱明博士,2007年清華大學畢業,2011年香港中文大學博士畢業,可謂是功力深厚,感嘆於國內一些所謂博士的水平,何這樣的博士才可以真正叫做

Doctor。

     本文主要上是對《Single Image Haze Removal Using Dark Channel Prior》的翻譯、整理、及部分解釋、程式碼實現。如果您的英文水平好,建議看原

文可能來的更爽些。

    一、論文思想的簡單描述 

     首先看看暗通道先驗是什麼:

       在絕大多數非天空的區域性區域裡,某一些畫素總會有至少一個顏色通道具有很低的值。換言之,該區域光強度的最小值是個很小的數。

  我們給暗通道一個數學定義,對於任意的輸入影象J,其暗通道可以用下式表達:

                                    

      式中Jc表示彩色影象的每個通道 ,Ω(x)表示以畫素X為中心的一個視窗。 

    式(5)的意義用程式碼表達也很簡單,首先求出每個畫素RGB分量中的最小值,存入一副和原始影象大小相同的灰度圖中,然後再對這幅灰度圖進行最小值

濾波,濾波的半徑由視窗大小決定,一般有WindowSize = 2 * Radius + 1;          

      暗通道先驗的理論指出:

                                                            

           

     實際生活中造成暗原色中低通道值主要有三個因素:a)汽車、建築物和城市中玻璃窗戶的陰影,或者是樹葉、樹與岩石等自然景觀的投影;b)色彩鮮豔的物

體或表面,在RGB的三個通道中有些通道的值很低(比如綠色的草地/樹/植物,紅色或黃色的花朵/葉子,或者藍色的水面);c)顏色較暗的物體或者表面,

例如灰暗色的樹幹和石頭。總之,自然景物中到處都是陰影或者彩色,這些景物的影象的暗原色總是很灰暗的。

     在作者的論文中,統計了5000多副影象的特徵,也都基本符合這個先驗,因此,我們可以認為其實一條定理。

      有了這個先驗,接著就需要進行一些數學方面的推導來最終解決問題。

  首先,在計算機視覺和計算機圖形中,下述方程所描述的霧圖形成模型被廣泛使用:

                                                   

   其中,I(X)就是我們現在已經有的影象(待去霧的影象),J(x)是我們要恢復的無霧的影象,A是全球大氣光成分, t(x)為透射率。現在的已知條件就是

I(X),要求目標值J(x),顯然,這是個有無數解的方程,因此,就需要一些先驗了。

  將式(1)稍作處理,變形為下式:

                                                    

    如上所述,上標C表示R/G/B三個通道的意思。

    首先假設在每一個視窗內透射率t(x)為常數,定義他為,並且A值已經給定,然後對式(7)兩邊求兩次最小值運算,得到下式:

                                  

    上式中,J是待求的無霧的影象,根據前述的暗原色先驗理論有:

                                               

     因此,可推匯出:

                                                         

    把式(10)帶入式(8)中,得到:

                                                 

    這就是透射率的預估值。

    在現實生活中,即使是晴天白雲,空氣中也存在著一些顆粒,因此,看遠處的物體還是能感覺到霧的影響,另外,霧的存在讓人類感到景深的存在,因此,有

必要在去霧的時候保留一定程度的霧,這可以通過在式(11)中引入一個在[0,1] 之間的因子,則式(11)修正為:

                                               

     本文中所有的測試結果依賴於:  ω=0.95。

     上述推論中都是假設全球達氣光A值時已知的,在實際中,我們可以藉助於暗通道圖來從有霧影象中獲取該值。具體步驟如下:

      1) 從暗通道圖中按照亮度的大小取前0.1%的畫素。

          2) 在這些位置中,在原始有霧影象I中尋找對應的具有最高亮度的點的值,作為A值。

     到這一步,我們就可以進行無霧影象的恢復了。由式(1)可知:  J = ( I - A)/t + A  

     現在I,A,t都已經求得了,因此,完全可以進行J的計算。

     當投射圖t 的值很小時,會導致J的值偏大,從而使淂影象整體向白場過度,因此一般可設定一閾值T0,當t值小於T0時,令t=T0,本文中所有效果圖均以

T0=0.1為標準計算。

     因此,最終的恢復公式如下:

                                

     當直接用上述理論進行恢復時,去霧的效果其實也是很明顯的,比如下面一些例子:

       

                 有霧圖                                             去霧圖

      注意到第一幅圖的原圖兩個字的周圍明顯有一塊不協調的地方,而第二圖頂部水平方向似乎有一塊沒有進行去霧處理,這些都是由於我們的透射率圖過於粗

糙了。

      要獲得更為精細的透射率圖,何博士在文章中提出了了soft matting方法,能得到非常細膩的結果。但是他的一個致命的弱點就是速度特慢,不使用於實際

使用。在2011年,何博士又除了一片論文,其中提到了導向濾波的方式來獲得較好的透射率圖。該方法的主要過程集中於簡單的方框模糊,而方框模糊有多重和

半徑無關的快速演算法。因此,演算法的實用性特強,關於這個導向濾波演算法大家在何博士的網站可以自己去研習下,除了在去霧方面外,還有著其他多方面的應

用,這部分本文不多述。

     使用了導向濾波後的去霧效果:

     

  二、各引數對去霧結果的影響

  第一:視窗的大小。這個對結果來說是個關鍵的引數,視窗越大,其包含暗通道的概率越大,暗通道也就越黑。我們不去從理論角度分析,從實踐的效果來

看,似乎視窗越大,去霧的效果越不明顯,如下圖所示:

        

                              (a) 原始影象                            (b) 視窗大小=11

      

              (c) 視窗大小=21                         (d) 視窗大小=101 

  我的建議是視窗大小在11-51之間,即半徑在5-25之間。

     式(12)中的ω具有著明顯的意義,其值越小,去霧效果越不明顯,舉例如下:

      

                                    (a) 原始影象                                   (b)    ω=0.5

          

                                       (c)    ω=0.8                                                                       (d)    ω=1 

    三:編碼的步驟

  如果你仔細的分析了原文的細路,加上適當的參考,編碼其實並不是很困難。

  1)根據原始影象求暗通道。

      2)按文中所描述的演算法自動獲得全球大氣光的值。

     這裡說明一點,原始論文中的A最終是取原始畫素中的某一個點的畫素,我實際上是取的符合條件的所有點的平均值作為A的值,我這樣做是因為,如果是取

一個點,則各通道的A值很有可能全部很接近255,這樣的話會造成處理後的影象偏色和出現大量色斑。原文作者說這個演算法對天空部分不需特備處理,我實際發

現該演算法對有天空的影象的效果一般都不好。天空會出現明顯的過渡區域。作為解決方案,我增加了一個引數,最大全球大氣光值,當計算的值大於該值時,則

就取該值。  

           

                        原圖                                                         未對A值做限定                  最大A值限定為220

       3) 按式(12)計算預估的透射率圖。

  在式(12)中,每個通道的資料都需要除以對應的A值,即歸一化,這樣做,還存在一個問題,由於A的選取過程,並不能保證每個畫素分量值除以A值後都

小於1,從而導致t的值可能小於0,而這是不容許的,原文作者並沒有交代這一點是如何處理的。我在實際的編碼中發現,如果真的這樣做了,其效果也並不是很

理想 ,因此,我最後的辦法是在式(12)中,不考慮A的計算。

        4)計算導向濾波圖。

   這裡可以直接用原始的影象做導向圖,當然也可以用其灰度圖,但是用RGB導向圖在下一步的計算中會佔用比較大的時間。

        5)按照《Guided Image Filtering》論文中的公式(5)、(6)、(8)編碼計算獲得精細的透射率圖。c++程式碼見上一篇文章。

還有一點就是,上述計算需要在[0,1]範圍內進行,也就是說導向圖和預估的透射率圖都必須從[0,255]先對映到[0,1]在進行計算。

      關於guidedfilter中的半徑r值,因為在前面進行最小值後暗通道的影象成一塊一塊的,為了使透射率圖更加精細,建議這個r的取值不小於進行最小值濾波的

半徑的4倍,如下圖所示:

          (a)  r=最小值濾波半徑的2倍                        (b) r=最小值濾波半徑的8倍

      可以看到,當r比較小的時候,在透射率圖中基本看不到什麼細節資訊,因此恢復處的影象邊緣處不明顯。

      引數eps的取值也有所講究,他主要是為了防止計算中除以0的錯誤以及為了使得某些計算結果不至於過大,一般建議取值0.001或者更小。

      如果使用的彩色RGB圖做導向圖,計算時間上會增加不少,所的到的透射率圖的邊緣會比灰度圖所處理的保留了更多的細節,效果上略微比灰度圖好。

       以RGB圖為導向圖的計算中,涉及到3*3部分矩陣求逆的過程,如果用非matlab語言寫,可以先借助於matlab的符號計算功能,以及其中的符號計算命令

simple,把計算結果算出來,然後再再其他高階語言中實現。

       (6) 按式(22)進行無霧影象的恢復。

mfc標頭檔案:

  1. #pragma once
  2. #include "afxwin.h"
  3. #include <cv.h>
  4. #include "cxcore.h"  
  5. #include "math.h" 
  6. #include <highgui.h>
  7. #include<vector>
  8. #include <iostream>  
  9. #include "opencv2/core/core.hpp"    
  10. #include "opencv2/highgui/highgui.hpp"    
  11. #include "opencv2/imgproc/imgproc.hpp"    
  12. usingnamespace std;  
  13. usingnamespace cv;  
  14. class Ctry :  
  15.     public CCmdTarget  
  16. {  
  17. public:  
  18.     Ctry();  
  19.     virtual ~Ctry();  
  20.     DECLARE_MESSAGE_MAP()  
  21.     afx_msg void OnTryTyr1();  
  22.     afx_msg void OnTryPath();  
  23. public:  
  24.     Mat getimage(Mat &a);  
  25.     Mat guidedFilter2(cv::Mat I, cv::Mat p, int r, double eps);  
  26.     IplImage* getDarkChannel(IplImage* &src);  
  27.     IplImage* getMinIcy(IplImage* dark,int w);  
  28.     double getA(IplImage* dark, IplImage*hazeImage);  
  29.     IplImage* getTransmission(IplImage* Icy, double

    相關推薦

    影象通道先驗演算法原理c++程式碼實現

    http://blog.csdn.net/s12244315/article/details/50292049 何凱明博士,2007年清華大學畢業,2011年香港中文大學博士畢業,可謂是功力深厚,感嘆於國內一些所謂博士的水平,何這樣的博士才可以真正叫做

    增強影象對比度演算法原理matlab程式碼實現

    clc;   close all;   clear all;    % -------------Gamma Transformations-----------------     %f = imread('Fig0316(4)(bottom_left).tif');     

    關於通道先驗問題的小結

    前段日子導師甩給我一篇何博士的論文,叫做《Single Image Haze Removal Using Dark Channel Prior》,利用統計得來的暗通道先驗實現對有霧影象的去霧問題,現大概說說對論文中的幾個點。 1.去霧問題的數學模型: 其中,I為haze image

    資料結構圖文解析:陣列、單鏈表、雙鏈表介紹C++模板實現

    0. 資料結構圖文解析系列 1. 線性表簡介 線性表是一種線性結構,它是由零個或多個數據元素構成的有限序列。線性表的特徵是在一個序列中,除了頭尾元素,每個元素都有且只有一個直接前驅,有且只有一個直接後繼,而序列頭元素沒有直接前驅,序列尾元素沒有直接後繼。 資料結構中常見的線性結構有陣列、單鏈表、雙鏈表、迴圈

    資料探勘clara演算法原理例項(程式碼中有bug)

    繼上兩篇文章介紹聚類中基於劃分思想的k-means演算法和k-mediod演算法 本文將繼續介紹另外一種基於劃分思想的k-mediod演算法-----clara演算法 clara演算法可以說是對k-mediod演算法的一種改進,就如同k-mediod演算法對 k-m

    全面解讀Group Normbalization-(吳育昕- 重磅作)

       作者:劉威威           編輯:李雪冬           前  言Face bo

    】非區域性連線網路 Non-local Neural Network

    《Non-local Neural Network》 一、 主要貢獻 1.提出了一種非區域性連線(Non-local operations)的計算塊 (building block),用於處理視訊和影象的長程依賴關係(long-range dependency); 2.在視訊資料集Kinetics

    通道先驗+加權最小二乘 原理

    本文主要講解,何愷明暗通道先驗去霧以及加權最小二乘演算法的原理部分,對應程式碼可在資源處下載。1暗通道先驗去霧模型 公式(1)是常用的霧靄形成模型:                             (1)其中,I(x)為實際拍攝到的有霧視訊幀,J(x)為去霧後的原視訊

    c#程式碼實現排序演算法歸併排序

    歸併排序的平均時間複雜度為O(nlogn),最好時間複雜度為O(nlogn),最壞時間複雜度為O(nlogn),空間複雜度為O(n),是一種穩定的演算法。 1.將待排序序列r(1),r(2),…,r(n)劃分為兩個長度相等的子序列r(1),…r(n/2)和r(n/2+1),…,r

    c#程式碼實現排序演算法快速排序

    快速排序的平均時間複雜度為O(nlog2n),最好時間複雜度為O(nlog2n),最壞時間複雜度為O(n²),空間複雜度為O(log2n),是一種不穩定的演算法。 1.劃分:選定一個記錄作為軸值,以軸值為基準將整個序列劃分為兩個子序列r(1)…r(i-1)和r(i+1)…r(n)

    c#程式碼實現排序演算法氣泡排序

    氣泡排序的平均時間複雜度為O(n²),最好時間複雜度為O(n),最壞時間複雜度為O(n²),空間複雜度為O(1),是一種穩定的演算法。 1.將整個待排序的記錄序列劃分成有序區和無序區,初始時有序區為空,無序區包括所有待排序的記錄。 2.對無序區從前向後依次比較相鄰記錄,若反序則交

    c#程式碼實現排序演算法選擇排序

    選擇排序的平均時間複雜度為O(n²),最好時間複雜度為O(n²),最壞時間複雜度為O(n²),空間複雜度為O(1),是一種不穩定的演算法。 1.將整個記錄序列劃分為有序區和無序區,初始時有序區為空,無序區含有待排序的所有記錄。 2.在無序區查詢值最小的記錄,將它與無序區的第一個記

    c#程式碼實現排序演算法插入排序

    插入排序的平均時間複雜度為O(n²),最好時間複雜度為O(n),最壞時間複雜度為O(n²),空間複雜度為O(1),是一種穩定的演算法。 1.將整個待排序的記錄序列劃分成有序區和無序區,初始時有序區為待排序記錄序列的第一個記錄,無序區包括所有剩餘待排序的記錄。 2.將無序區的第一個

    影象插值演算法原理C++實現

    簡介: 在影象的處理過程中,經常需要對影象進行尺寸變換、旋轉或者扭曲等操作,在進行這些操作之後,原影象的尺寸往往就發生了改變,為了保持變換後的影象不失真,就需要對影象進行插值。 常見的插值方法有最近鄰插值和雙線性插值。 最近鄰插值: 最近鄰插值是最簡單的一種插值方式,

    深度學習(七)U-Net原理以及keras程式碼實現醫學影象眼球血管分割

    原文作者:aircraft 原文連結:https://www.cnblogs.com/DOMLX/p/9780786.html 全卷積神經網路 醫學影象分割框架 醫學影象分割主要有兩種框架,一個是基於CNN的,另一個就是基於FCN的。這裡都是通過網路來進行語義分割。 那麼什麼是語義分割?可

    .NET Core實戰專案CMS 第十二章 開發篇-Dapper封裝GURD倉儲程式碼生成器實現

    本篇我將帶著大家一起來對Dapper進行下封裝並實現基本的增刪改查、分頁操作的同步非同步方法的實現(已實現MSSQL,MySql,PgSQL)。同時我們再實現一下倉儲層的程式碼生成器,這樣的話,我們只需要結合業務來實現具體的業務部分的程式碼就可以了,可以大大減少我們重複而又繁瑣的增刪改查操作,多留點時間給生活

    排序系列(4)希爾排序C語言實現

    希爾排序(Shell Sort)也稱為遞減增量排序演算法,是插入排序的一種高速而安定的改良版。因希爾(Donald L. Shell)於1959年提出而得名。各種實現在如何進行遞減上有所不同。 希爾排序是基於插入排序的以下兩點性質而提出改進方法的: 插入排序在對幾乎已經排好序的資料操作時, 效率高, 即可以達

    .NET Core實戰專案CMS 第十二章 開發篇-Dapper封裝CURD倉儲程式碼生成器實現

    本篇我將帶著大家一起來對Dapper進行下封裝並實現基本的增刪改查、分頁操作的同步非同步方法的實現(已實現MSSQL,MySql,PgSQL)。同時我們再實現一下倉儲層的程式碼生成器,這樣的話,我們只需要結合業務來實現具體的業務部分的程式碼就可以了,可以大大減少我們重複而又繁瑣的增刪改查操作,多留點時間給生活

    資料結構:AVL樹詳解C++模板實現

    AVL樹簡介AVL樹的名字來源於它的發明作者G.M. Adelson-Velsky 和 E.M. Landis。AVL樹是最先發明的自平衡二叉查詢樹(Self-Balancing Binary Search Tree,簡稱平衡二叉樹)。一棵AVL樹有如下必要條件:條件一:它必

    資料結構(C語言)讀書筆記6:棧的應用括號匹配的C程式碼實現

    括號匹配的演算法思想: 初始化一個空棧,掃描表示式,依次讀入字元,知道掃描完或者出現錯誤匹配。對於讀入的每個字元,分以下情況處理: (1)、如果是‘’(“”或“【”,將其壓入棧。 (2)、如果是“)”,則根據當前棧頂元素的值分情況考慮。若棧頂元素是“(”,則匹配成功,否則為