??歡迎訂閱《從實戰學python》專欄,用python實作爬蟲、辦公自動化、資料可視化、人工智能等各個方向的實戰案例,有趣又有用!??
更多精品專欄簡介點這里
治愈生活的良方 就是保持對生活的熱愛
前言
哈嘍,大家好,我是一條,
每次和女朋友出去玩,拍照是必須的,天氣好還行,天氣要是不好,加上我這破手機,那拍的簡直慘不忍睹,自己都不過去,
但是沒什么能難倒程式員的,為了不挨罵,連夜寫出去霧演算法,女朋友更崇拜我了!
??本文高能,專業知識繁多,小白可以直接文末拿代碼運行(每行都有注釋),
??想深入研究的同學,萬字詳解包教包會!
??總之,收藏護體!
最終效果圖
話不多說,先看看效果強不強,
自己寫的演算法,不調百度api,nb克拉斯,

應用:車牌識別

應用:霧天預警

應用:景物識別
文章目錄
- 前言
- 最終效果圖
- 概要
- 影像的相關知識
- 像素
- 通道
- 二值影像
- 灰度影像
- 暗通道
- 大氣散射模型
- 暗通道先驗去霧演算法原理
- 演算法公式
- 未知引數的計算
- 大氣光
- 透射率
- 代碼實作
- OpenCV簡介
- 影像的形態學處理
- 腐蝕
- 膨脹
- 開運算
- 閉運算
- 獲取大氣光
- 計算透射率
- 恢復影像
- 導向濾波優化
- 代碼
- 效果
- 針對天空部分的優化
- 設定大氣光的閾值
- 增加可控引數K
- 最終優化效果
- 各引數對去霧效果的影響
- 視窗的大小
- ω的大小
- 導向濾波半徑的大小
- 完整原始碼
- 🌈尋寶
概要
目前影像處理技術已非常火熱,應用也非常廣泛,
影像處理的難度不僅在于成像技術,更在于外界的天氣條件,遇到霧、雨、雪等能見度低的惡劣天氣時,成像會受到很大影響,其中霧霾天氣屢見不鮮,還使采集到的圖片辨識度、對比度、色彩飽和度都大大降低,
霧氣的消除可以從物理去霧和數字去霧兩個方向考慮,物理去霧即在成像鏡頭上優化,高清去霧的鏡頭成本昂貴,不能廣泛應用,所以研究重點在數字去霧上,即通過后期處理對影像進行優化,從去霧演算法提出至今,可用的去霧演算法大致可分為基于影像增強的去霧演算法和基于影像復原的去霧演算法,
本演算法基于影像復原的暗通道先驗去霧演算法,在大氣成像模型的基礎上,得出影像恢復的基本公式,
暗通道理論指出:在大多數非空區域區域中,始終至少有一個顏色通道的某些像素值較低甚至為0,
公式的關鍵點在于透射率的計算,為了改進演算法,用導向濾波對透射率進行優化,
又因為該演算法本身對天空部分并不適用,所以考慮對公式增加引數,二次計算透射率,完成對演算法的再一次優化,
最后再用OpenCV-Python對去霧演算法進行具體實作以及運行速度的優化,最終能夠實作對絕大多數的有霧圖片快速去霧,
影像的相關知識
為了讓領域小白理解接下來我要講的內容,需要普及一些基礎知識,
像素
像素是影像的基本要素,也是影像的最小單位,
一張圖片實際是由很多個小方格組成,每個小方格有固定的位置和顏色數值,這決定了圖片最終呈現的樣子,像素的多少決定了在螢屏上顯示的大小,
如果是黑白圖片,用0-255之間的一個數字來表示顏色的深淺明暗,0表示最暗(黑色),255表示最亮(白色),
如果是彩色圖片,用三個0-255之間的數字組成的數字序列來表示紅綠藍三種顏色所占的比例,則某一個位置的像素就可以用數字序串列示為[24,180,50],
比如一個5*4像素的彩色影像就可以這樣存在計算機中,

通道
通道簡單來說就是表示通道表示每個點能存放多少個數,
例如彩色影像中每個像素點存放三個值,即3通道的,黑白影像每個像素點存放一個數字,即單通道,
二值影像
影像的像素點不是0就是1(影像不是黑色就是白色),影像像素點占的位數就是1位,影像的深度就是1,也稱作位圖,
灰度影像
影像中的像素介于0-255之間,0表示完全黑色,255表示完全白色,并且在0-255之間插入了255級灰度,
當查看單個通道時,每個通道都顯示為灰度影像而不是黑白影像,
在通道的灰度影像中,對比度應與通道顏色的對比度匹配,它代表了彩色光在整個影像上的分布,
因為有3個通道,所以也有3個灰度影像,
暗通道
暗通道是一個基本假設,即在大多數非空區域區域中,始終至少有一個顏色通道的某些像素值較低,
形成這種現象的原因很多,比如色彩鮮艷的物體的表面,汽車,建筑物或城市的陰影,較暗的物體表面的陰影,這些場景的暗通道始終較暗,
暗通道實際上使用三個RGB通道中的最小通道來形成灰度影像,
作者計算大量沒有霧的影像,并找到規則:
每個影像中三個RGB其中一個顏色通道具有一個灰色通道,階值非常低,幾乎接近零,
如果有霧,則有一定的灰色;
如果沒有霧,則有很多黑色(像素接近0),
共計算了5,000多個影像屬性,基本上都滿足這樣的先驗定理,
所以只需分別計算出三個通道中RGB的最小值即可,
大氣散射模型
大氣顆粒的散射是霧霾的主要原因,
無論是用肉眼觀察還是從拍攝的影像中觀察,有很多霧的場景總是會受到對比度降低和視野降低的困擾,
在1925年,Keim和Nemnich等人提出霧影像的低可見性是由于大氣中空氣中的微粒吸收和散射了光,
1976年,約翰·威利(JohnWiley)等人提出,粒子散射會導致光在傳輸程序中在目標和相機之間衰減,并增加了一層大氣散射光,
為了解決1999年大霧天能見度差的問題,SrinivasaG和Narasimhan等人建立了數學模型來改善霧像的成像程序以及霧像中包含的各種元素,
該模型認為,在強散射介質中,檢測系統的成像結果劣化的主要原因有兩個:
- 首先,目標的反射光被空氣中的粒子吸收和散射,使系統的成像結果是導致反射光能量的衰減并導致檢測,亮度和對比度降低,
- 第二,諸如太陽光的環境光被大氣中的散射介質散射而形成背景光,通常,該區域中的背景光強度高于目標光,導致檢測系統的成像結果模糊,
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UrrwKMG3-1630474072464)(file:private/var/folders/j0/jf6_lq_s2wjcqpt53gnd88b80000gn/T/com.kingsoft.wpsoffice.mac/wps-libiao/ksohtml/wps6EBduQ.jpg)]
圖中顯示探測系統成像時接收到的光源主要來自兩個部分,
- 一是目標反射光經粒子衰減到達探測系統的光,
- 二是來自于光源經粒子散射形成的大氣光,
通過此物理模型建立得到霧天成像的數學模型為:

該公式的物理意義為經過粒子衰減能夠達到探測系統的那部分光的比例,
大多數團隊和學者在通過探測系統獲得含霧影像并對其進行去霧影像處理時均以上述大氣散射模型作為霧天成像的理論模型,
其主要思路是根據各種先驗知識或者影像處理手段,從含霧影像中估計傳輸函式或大氣光,將求解得到的參量代入到大氣散射模型中,即可恢復出目標影像,

在強分散介質中,檢測系統成像質量的下降主要包括以下兩個原因:
- 目標的反射光在光的程序中被懸浮在介質中的顆粒吸收和擴散,通常,影像的亮度會降低,從而導致影像的對比度下降;周圍的光(例如日光和天光)會被粒子散射,在中間形成散射光,通常會模糊影像并使影像的顏色不自然,以在多云環境下對目標成像為例,成像系統獲得的影像主要由兩部分組成,一是目標反射光被大氣的色散和吸收所衰減.
- 另一個是由大氣散射形成的大氣光,反射光在傳播的程序中,隨著傳輸距離的增加光強逐漸衰減,
暗通道先驗去霧演算法原理
暗通道先驗去霧演算法最早由何凱明博士中提出,先驗與經驗相對,就是基于某種經驗所得出的結論去研究解決問題的方法,此處就是指何凱明博士統計了5000多副影像后得出的先驗定理:
在每一幅影像的RGB三個顏色通道中,總有一個通道的灰度值很低,幾乎趨向于0,
可以發現,有霧的時候會呈現一定的灰色,而無霧的時候咋會呈現大量的黑色(像素為接近0),如圖:有霧圖片的灰度圖整體呈灰色,無霧圖片的非天空部分呈黑色,

在現實生活中產生這種現象的原因的有很多且很普遍,例如汽車,建筑物等城市中的陰影,有色物體的表面,比如綠葉,各種鮮艷的花朵,較暗的物體表面,這些場景影像的RGB顏色通道中,總有一個通道的灰度值很低,
演算法公式
此處省去推導程序,直接上公式,

在日常生活中,即使是晴空萬里,霧也不是完全不存在的,只是濃度比較低,依然會影響人們看遠處的物體;
另外,人眼能感到景深的存在也是因為霧,
所以,去霧時也不能做到絕對,應該保留一定程度的霧,通過在式中加入一個在[0,1]之間的系數來實作,
未知引數的計算
明確需要計算哪些值,
大氣光
在實際中,可以借助于暗通道圖來從有霧影像中獲取該值,
首先根據亮度從暗通道圖中獲取前0.1%的像素,
然后在這些位置中,在原始有霧影像I中尋找對應的具有最高亮度的點的值,作為A值,
最后計算A的平均值,
透射率
大氣光計算出之后,根據如下公式,可得到透射率,

代碼實作
理論已經完成,咱們直接代碼實作,
OpenCV簡介
OpenCV主要提供一組通用的基礎結構,
用于開發人工視覺程式,并改善商業產品中機器的感知,
OpenCV庫具有2500多種優化演算法,包括經典和最先進的機器視覺以及機器學習演算法,
這些演算法可用于檢測和識別面部,跟蹤移動的物件,提取物件的三維模型,從立體相機生成3D點云并組合影像以生成高解析度全景影像,從影像資料庫中查找相似影像等等,
使用OpenCV的專案已植入街景影像,在監視期間檢測入侵,監視采礦設備,幫助機器人導航和收集物體,并檢測泳池中的溺水事件等很多,
OpenCV支持各種編程語言,如C++,Python,Java等,OpenCV-Python是OpenCV的PythonAPI,結合了C++和Python語言的最佳特性,
綜上所述,OpenCV-Python的功能非常強大,所以本文用它來實作去霧演算法,
影像的形態學處理
OpenCV在很多領域都有應用,比如影像分割、物體識別、動作識別、人臉識別、結構分析等眾多領域,功能復雜繁多,在暗通道先驗去霧演算法中,除去一些計算函式,最關鍵的就是OpenCV的形態學處理,
形態變換是對影像形狀進行的簡單操作,通常是指對二值影像進行的操作,常見的形態變換包括腐蝕,膨脹和張開操作,

腐蝕
腐蝕是對前景中物體邊緣的腐蝕,其腐蝕效果與現實相同,
其原理為卷積核沿著影像滾動,如果相應區域的影像的像素值是1,則對應于卷積核中心的像素值保持不變,否則將全部變為0,
在卷積核中,影像的邊緣,部分為0,則該區域的部分將全變為0并保持不變,
膨脹
膨脹是腐蝕的逆程序,與腐蝕相對,
其原理同樣為卷積核沿著影像流動,如與卷積核對應的影像像素值之一為1,該區域將全部變為1,否則保持不變,
開運算
進行腐蝕操作后再進行膨脹操作就是開運算
閉運算
閉與開相對,所以開運算的逆程序就是閉運算,進行膨脹操作后再進行腐蝕造作,原理和開運算一樣,可以用于去除二值化影像的背景色噪點,

獲取大氣光
首先計算影像的總像素點數,取其前0.1%,
再按像素值從小到大的順序獲取像素所在位置的下標,按按照下標從霧圖中找到對應位置的三通道值,
這樣就完成了從暗通道圖中按照亮度的大小取前0.1%的像素,然后取這些值的平均值作為大氣光A的值,
代碼如下:
def AtmLight(im,dark):
[h,w]=im.shape[:2] #獲取影像的長寬
imsz=h*w #長*寬得到總像素點個數
numpx=int(max(math.floor(imsz/1000),1)) #取總個數的前0.1%
darkvec=dark.reshape(imsz,1); #復制原圖
imvec=im.reshape(imsz,3); #復制暗通道圖
darkvec1=np.transpose(darkvec) #橫縱坐標互換
indices=darkvec1.argsort(); #按像素值從小到大的順序獲取像素所在位置的下標
indices=indices[0][imsz-numpx::] #取前0.1%大的
atmsum=np.zeros([1,3]) #一行三列以0填充的矩陣
for ind in range(0,numpx): #按下標到原圖找到對應位置的像素值并求和
atmsum=atmsum+imvec[indices[ind]]
A=atmsum/numpx; #計算平均值
return A
計算透射率
依據公式粗略得到透射率的值,該值有待優化,后續會處理,
def TransmissionEstimate(im,A,sz):
omega=0.95; #宣告引數
im3=np.empty(im.shape,im.dtype); #復制原圖
for ind in range(0,3): #按公式計算
im3[:,:,ind]=im[:,:,ind]/A[0,ind]
transmission=1-omega*DarkChannel(im3,sz);
return transmission
恢復影像
根據前面得出的恢復公式進行計算,
def Recover(im, t, A, tx=0.1):
res = np.empty(im.shape, im.dtype);
t = cv2.max(t, tx); #如果t小于tx,取tx
for ind in range(0, 3): #按公式計算
res[:, :, ind] = (im[:, :, ind] - A[0, ind]) / t + A[0, ind]
return res

含天空部分的影像去霧之后只能觀察到少許的去霧效果,影像亮度大大降低,且天空部分過度曝光,去霧效果并不理想,
說明此演算法本身確實對大面積天空部分并不適用,
導向濾波優化
針對上文得到的較為粗略的透射率,在本章對其進行優化,
何凱明曾提出過軟遮光的方法,該方法雖然獲得的透射率非常精細,但是運行速度極慢,成為致命弱點,
在實際使用中,效果并不理想,所以在本文中使用引導濾波的方法獲得更精準的透射率,
該方法的核心在于正方形的簡單模糊,而有很多個快速且獨立于半徑的演算法都可以用于正方形的簡單模糊,使演算法的運行速度大大提高,可以實際使用,
原理部分略過,因過于晦澀,需要深入了解的同學,
代碼
def Guidedfilter(im, p, r, eps):
mean_I = cv2.boxFilter(im, cv2.CV_64F, (r, r));
mean_p = cv2.boxFilter(p, cv2.CV_64F, (r, r));
mean_Ip = cv2.boxFilter(im * p, cv2.CV_64F, (r, r));
cov_Ip = mean_Ip - mean_I * mean_p;
mean_II = cv2.boxFilter(im * im, cv2.CV_64F, (r, r));
var_I = mean_II - mean_I * mean_I;
a = cov_Ip / (var_I + eps);
b = mean_p - a * mean_I;
mean_a = cv2.boxFilter(a, cv2.CV_64F, (r, r));
mean_b = cv2.boxFilter(b, cv2.CV_64F, (r, r));
q = mean_a * im + mean_b;
return q;
效果

針對天空部分的優化
演算法對天空部分的處理效果并不理想,天空部分被和非天空部分會出現明顯的過渡區域和過度曝光現象,
這是演算法從提出就存在的問題,為了解決這跟問題,從以下兩種思路進行優化,
設定大氣光的閾值
在計算大氣光值時提到,A是所有按亮度取前0.1%像素點的平局值,由于天空部分的大氣光過大,影響了最后的平均值,
所以考慮設定一個最大全球大氣光值作為所有像素點的閾值,如果有像素點的值大于閾值,該值就等于閾值,
這里將閾值設定為220,
因為這種直接取閾值的方法有些絕對,所以多次實驗之后發現結果并無較大改變,
增加可控引數K
考慮到上面直接取閾值的方法有些絕對,所以想到設定一個引數來重新計算透射率,
正常情況下,天空部分的大氣光值和A使比較接近的,而只有遠離天空的地方才能用暗通道先驗演算法去霧,
所以將符合條件的像素點的值與A相減,如果結果小于某個值,認為這個區域可能是天空,就需要重新計算透射率,
如果結果小于某個值,則認為該區域不是天空,不用重新計算透射率,
這里的某個值,設定為k,每個像素處的透射率用它來調節,則改良后的透射率計算公式為

經過實驗,該方法對去霧校果有非常大的改善,
最終優化效果

各引數對去霧效果的影響
視窗的大小
視窗的大小對去霧效果來說是個關鍵的引數,
從理論角度分析,視窗更大,就有更大的概率包含暗通道,暗通道也就越暗,與無霧影像的對比越不明顯,去霧效果也就不好,
實驗得到:視窗越大,去霧的效果越不好,視窗大小在11-51之間去霧效果最好,
ω的大小
ω最初是為考慮維持景深,所以保留一定程度的霧,所以其值越小,保留的霧越多,當然去霧效果越不好,
實驗后發現,取0.95最佳,
導向濾波半徑的大小
關于導向濾波中的半徑r值,因為在前面進行形態學處理暗通道的影像成一塊一塊的,
為了使透射率率更加精準,實驗后發現,r的取值大于等于視窗大小的4倍最好,
完整原始碼
原始碼下載地址:待審核
完整論文下載地址:待審核
免費地址
🌈尋寶
?今天是堅持刷題更文的第48/100天
?各位的點贊、關注、收藏、評論、訂閱就是一條創作的最大動力
為了回饋各位粉絲,禮尚往來,給大家準備了一條多年積累下來的優質資源,包括 學習視頻、面試資料、珍藏電子書等
大家可以點這里領取
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/296789.html
標籤:其他
上一篇:【游戲開發創新】使用Unity制作方陣編隊,CSDN方陣迎面走來,感謝CSDN的中秋禮物(影像采樣 | 點陣 | 方陣 | 隊形 | 變換 | 影片)

