暗通道先验去雾实现过程分析
? ? ? ? 經(jīng)典去霧算法-何凱明09年提出暗通道先驗(yàn)去霧(Single Image Haze Removal Using Dark Channel Prior)
? ? ? ? 暗通道去霧公式:I(x) = f(x)*t(x) + (1 – t(x))*A
? ? ? ??I(x)為待去霧圖像,f(x)為去霧后圖像,t(x)為透射率(0,1),A為大氣光成分。
? ? ? ??根據(jù)公式,去霧算法可解釋為:有霧時(shí),相機(jī)獲取到的圖像為兩部分組成,一部分為被拍攝物體發(fā)射光線穿過(guò)霧霾后的光線,另一部分為大氣光被霧霾反射后的光線。被拍攝物體發(fā)射光線f(x)通過(guò)霧霾,霧霾透射率為t(x),那么被攝物體光線到達(dá)相機(jī)后值為?f(x)*t(x)。原始大氣光值為A,大氣光的方向可看做與被拍攝物體光線完全相反,大氣光一部分穿過(guò)霧霾,一部分被霧霾反射,被反射后的光線值即為A - A*t(x))。
? ? ? ??整個(gè)去霧流程如下圖:
? ? ? ??有了算法模型,接下來(lái)對(duì)各個(gè)部分進(jìn)行細(xì)化實(shí)現(xiàn),首先計(jì)算透射率。暗通道先驗(yàn)法指出,根據(jù)大量圖像統(tǒng)計(jì),無(wú)霧圖像RGB通道總有一個(gè)通道值趨近于0,也就是說(shuō)在該像素上透射率t(x)趨近于1,f(x)與I(x)幾乎相等。而有霧圖像,由于霧霾反射的大氣光干擾,RGB通道上的最低值,也就是被反射后的大氣光值,通過(guò)這個(gè)值即可計(jì)算出該像素上的透射率,當(dāng)然實(shí)際情況下需要考慮其他因素造成的干擾,一般情況下需要對(duì)原始圖像通過(guò)RGB最低值計(jì)算的灰度圖進(jìn)行最低值濾波,根據(jù)某個(gè)像素相鄰范圍的最低值計(jì)算透射率。
? ? ? ??整個(gè)計(jì)算透射率過(guò)程分為三個(gè)步驟:第一步為原始圖像通過(guò)RGB最低值轉(zhuǎn)灰度圖;第二步對(duì)灰度圖進(jìn)行最低通道濾波,濾波器半徑可選,取濾波器內(nèi)最低值作為中心像素值;第三部對(duì)低通濾波后的灰度圖進(jìn)行高斯低通濾波,主要作用為平滑圖像,讓邊緣過(guò)度平緩。
? ? ? ??透射率計(jì)算流程如下:
? ? ? ??計(jì)算大氣光成分值則比較簡(jiǎn)單,大氣光成分A可以看做一個(gè)獨(dú)立的RGB像素,包含三個(gè)值。一般是對(duì)原始圖像RGB通道統(tǒng)計(jì)0~255概率分布,分別從各個(gè)通道最大值開(kāi)始取占比大于萬(wàn)分之一的值作為A中對(duì)應(yīng)值。
? ? ? ??完成透射率和大氣光成分計(jì)算后,接下來(lái)就是根據(jù)公式計(jì)算去霧圖像。實(shí)際上還需要計(jì)算透射率圖像,透射率圖像通過(guò)高斯低通濾波后圖像進(jìn)行反轉(zhuǎn)得到,在實(shí)際應(yīng)用開(kāi)發(fā)上,這一步可以省略,直接通過(guò)濾波后灰度圖實(shí)際上可以看做霧霾反射率圖T(x),那么透射率即t(x)=1-T(x)。去霧處理后的圖像一般會(huì)比較暗,可以通過(guò)自動(dòng)對(duì)比度或自動(dòng)色階進(jìn)行優(yōu)化。
? ? ? ??基于暗通道的去霧對(duì)于濃度不均勻的霧霾去霧效果比較好,但計(jì)算透射率過(guò)程由于最低值濾波和高斯低通濾波隨著卷積核增大,消耗計(jì)算量也越大,處理單張影像還好,如果用于批量處理影像,顯然不太實(shí)用。當(dāng)然在實(shí)際應(yīng)用中,可以考慮減少濾波核半徑,犧牲一些效果,提升處理速度。把最低值通濾波和高斯低通濾波核半徑都設(shè)置為1進(jìn)行測(cè)試。
測(cè)試圖像:
去霧效果圖:
附上代碼,java版的實(shí)現(xiàn):
package tools;import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List;public class AutoHazeRemoval {//自動(dòng)去霧public BufferedImage hazeRemoval(BufferedImage image) {BufferedImage tempImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());BufferedImage grayImage = new ImageGray().transferGrayImageByLowest(image);grayImage = new LowestFilter().lowestFilter(grayImage, 1);grayImage = new GaussianBlur().gaussBlur(grayImage, 1, 1);int[] A = extractA(image);for (int i = 0; i < image.getWidth(); i++) {for (int j = 0; j < image.getHeight(); j++) {int rgb = image.getRGB(i, j);double R = (rgb >> 16) & 0xff;double G = (rgb >> 8) & 0xff;double B = rgb & 0xff;//計(jì)算透射率int transmissionValue = grayImage.getRGB(i, j) & 0xff;double transmission = 0.95 * (double)transmissionValue / 255;R = (R - A[0] * transmission) / (1 - transmission); G = (G - A[1] * transmission) / (1 - transmission); B = (B - A[2] * transmission) / (1 - transmission); rgb = (255 & 0xff) << 24 | (clamp((int)R) & 0xff) << 16| (clamp((int)G) & 0xff) << 8 | (clamp((int)B) & 0xff);tempImage.setRGB(i, j, rgb);}}return tempImage;}/*** 通過(guò)RGB在0~255頻率分布計(jì)算全局大氣光成分* * @param image* @return*/public int[] extractA(BufferedImage image) {List<Integer[]> list = generateBinary(image);int[] result = new int[3];result[0] = getValue(image,list.get(0));result[1] = getValue(image,list.get(1));result[2] = getValue(image,list.get(2));return result;}private int getValue(BufferedImage image,Integer[] list) {double temp = 0.0;int result = 0;for(int i = 255; i > 0; i--) {double num = list[i] / (double)(image.getWidth()*image.getHeight());temp += num;if (temp >= 0.0001) {result = i;break;}}return result;}/*** 圖像二值化 計(jì)算圖像RGB值從0~255之間分布* * @return*/public List<Integer[]> generateBinary(BufferedImage image) {List<Integer[]> list = new ArrayList<>();Integer[] rlist = new Integer[256];Integer[] glist = new Integer[256];Integer[] blist = new Integer[256];// 通過(guò)循環(huán),往集合里面填充0~255個(gè)位置,初始值都為0for (int i = 0; i < 256; i++) {rlist[i] = 0;glist[i] = 0;blist[i] = 0;}for (int i = 0; i < image.getWidth(); i++) {for (int j = 0; j < image.getHeight(); j++) {int rgb = image.getRGB(i, j);int r = (rgb >> 16) & 0xff;int g = (rgb >> 8) & 0xff;int b = rgb & 0xff;rlist[r] = rlist[r] + 1;glist[g] = rlist[g] + 1;blist[b] = rlist[b] + 1;}}list.add(rlist);list.add(glist);list.add(blist);return list;}// 判斷a,r,g,b值,大于256返回256,小于0則返回0,0到256之間則直接返回原始值private int clamp(int rgb) {if (rgb > 255)return 255;if (rgb < 0)return 0;return rgb;} }?
總結(jié)
以上是生活随笔為你收集整理的暗通道先验去雾实现过程分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python离线安装国内镜像OpenCV
- 下一篇: 无人机图像处理工具-亮度、对比度、饱和度