柚子快報邀請碼778899分享:手把手教你暗通道先驗去霧算法
柚子快報邀請碼778899分享:手把手教你暗通道先驗去霧算法
0,流程
暗通道先驗去霧算法(Dark Channel Prior, DCP)是一種基于圖像的去霧技術(shù),由Kaiming He等人在2009年提出。這種算法利用了大氣散射模型,通過估計大氣光和圖像的傳輸圖來去除霧的影響。以下是暗通道先驗去霧算法的基本步驟:
暗通道提?。?/p>
對于一幅圖像,首先提取其暗通道。暗通道是指圖像中相對較暗的區(qū)域,這些區(qū)域在霧的影響下仍然保持一定的可見度。暗通道可以通過對圖像的每個像素點的RGB三個通道進行最小值操作來獲得。 大氣光估計:
利用暗通道,估計大氣光的值。大氣光是指由于大氣散射而進入相機的光??梢酝ㄟ^對暗通道的像素值進行閾值處理來估計大氣光的值。例如,可以選擇暗通道中大于某個閾值的像素點的像素值作為大氣光的估計值。 傳輸圖估計:
傳輸圖是指圖像中每個像素點的光透過霧的傳輸率。傳輸圖的估計需要結(jié)合大氣光和暗通道。傳輸圖可以通過以下公式估計:?
其中,I(x)?是原始圖像的像素值,Lmax??是大氣光的估計值。
圖像恢復:
利用傳輸圖和大氣光,恢復原始圖像。恢復過程可以通過以下公式進行:
??其中,I′(x)是恢復后的圖像,I(x)是原始圖像,L是大氣光的估計值,t(x)是傳輸圖。
細節(jié)增強:
為了增強恢復圖像的細節(jié),可以對恢復后的圖像進行一些細節(jié)增強處理,比如使用雙邊濾波等。
1,暗通道先驗理論內(nèi)容
?在大多數(shù)非天空區(qū)域,至少有一個通道的像素值是很低的并且接近于0,并且在一個小的區(qū)域內(nèi)最小的像素強度也接近于0.
暗通道先驗定義的數(shù)學公式:
公式中Jc表示彩色圖像的每個通道 ,Ω(x)表示以像素X為中心的一個窗口。首先求出每個像素RGB分量中的最小值,之后利用opencv的腐蝕操作求出以每個像素為中心的一個窗口的最小值,一般有WindowSize = 2 * Radius + 1。
1.1?暗通道先驗的理論依據(jù)
? ? ? ? 低強度的像素值通常由于以下幾個方面造成:首先是現(xiàn)實世界中物體的陰影,因為陰影本身具有較低的光強度。其次是色彩鮮艷的物體或表面,它們在 RGB 通道中的某些通道上具有較低的值,因此在圖像中呈現(xiàn)較暗的顏色,比如灰暗色的樹干和石頭等??偟膩碚f,自然景物中到處都存在陰影或色彩豐富的物體,這些因素都會導致圖像的暗通道具有較低的像素值,呈現(xiàn)出灰暗的色調(diào)。
獲取暗通道圖像算法代碼:
import cv2
import numpy as np
def dark_channel_prior(image, kernel_size=15):
# 分割圖像通道
b, g, r = cv2.split(image)
# 計算三個通道中的最小值
min_channel = cv2.min(cv2.min(r, g), b)
# 使用指定大小的矩形卷積核進行腐蝕操作
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))
dark_channel = cv2.erode(min_channel, kernel)
return dark_channel
# 讀取圖像
image = cv2.imread("4.jpg")
# 計算暗通道
dark_channel = dark_channel_prior(image)
# 顯示結(jié)果
cv2.imshow('Dark Channel', dark_channel)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果呈現(xiàn)圖:?
有霧暗通道
無霧暗通道
?3.去霧算法流程 ? ? ? ? 1.估計圖像透射率和大氣光:提供了有關(guān)圖像中光線衰減和背景光的重要信息,幫助去除大氣散射并恢復圖像的清晰度和真實感。
? ? ? ? 2.去霧處理:根據(jù)透射率和大氣光,對圖像中的每個像素進行修復,以減輕由于大氣散射引起的光線衰減效應??梢栽谔幚磉^程中對圖像進行進一步的優(yōu)化,以提高圖像的質(zhì)量和真實感。
? ? ? ? 3.評估去霧效果:使用PSNR(峰值信噪比)圖像質(zhì)量評估指標,評估去霧后圖像與原始圖像之間的相似度和質(zhì)量。
去霧效果圖展示:
?暗通道先驗去霧算法代碼:
pip install scikit-image
import cv2
import numpy as np
from skimage.metrics import peak_signal_noise_ratio as psnr
# 計算每個通道中的最小值,輸入Image圖像,輸出最小值img_min
def min_channel(img):
dst_channel = np.min(img, 2)
return dst_channel
def min_filter(image, r): # 暗通道
# 最小值濾波,輸入最小值圖像,在2*r+1的矩形窗口內(nèi)尋找最小
return cv2.erode(image, np.ones((2 * r + 1, 2 * r + 1)))
# 引導濾波
# I=img_arr歸一化 引導圖像
# p=img_mim每個通道最小值 輸入圖像
def guided_filter(I, p, r, eps): # (引導I 原圖p)
m_I = cv2.boxFilter(I, -1, (r, r))
m_p = cv2.boxFilter(p, -1, (r, r))
m_Ip = cv2.boxFilter(I * p, -1, (r, r))
cov_Ip = m_Ip - m_I * m_p
m_II = cv2.boxFilter(I * I, -1, (r, r))
var_I = m_II - m_I * m_I
a = cov_Ip / (var_I + eps)
b = m_p - a * m_I
m_a = cv2.boxFilter(a, -1, (r, r))
m_b = cv2.boxFilter(b, -1, (r, r))
q = m_a * I + m_b
return q
def select_bright(Image, img_origin, w, t0, V):
# 計算大氣光A和折射圖t
# 輸入:Image最小值圖像,img_origion原圖,w是t之前的修正參數(shù),t0閾值,V導向濾波結(jié)果
rows, cols = Image.shape
size = rows * cols
# h,w,d=img.shape,size=h*w*d,b=img.reshape(size)
order = [0 for i in range(size)] # order=np.zeros(size)
m = 0 # map0=Image.reshape(1,-1)[0] map1=map0.sort() map2=map1[::-1]
for t in range(0, rows):
for j in range(0, cols):
order[m] = Image[t][j]
m = m + 1
order.sort(reverse=True)
index = int(size * 0.001) # 從暗通道中選取亮度最大的前0.1%
mid = order[index]
A = 0
img_hsv = cv2.cvtColor(img_origin, cv2.COLOR_RGB2HLS)
for i in range(0, rows):
for j in range(0, cols):
if Image[i][j] > mid and img_hsv[i][j][1] > A:
A = img_hsv[i][j][1]
V = V * w
t = 1 - V / A
t = np.maximum(t, t0)
return t, A
def repair(Image, t, A):
rows, cols = Image.shape[:2]
J = np.zeros(Image.shape)
for i in range(0, rows):
for j in range(0, cols):
t[i][j] = t[i][j] - 0.35
J[i][j] = (Image[i][j] - A / 255.0) / t[i][j] + A / 255.0
return J
img = cv2.imread(r'F:\whl_package\img_1.png', 1) # 修改路徑即可
# 歸一化圖像
img_arr = img.astype(float) / 255.0
# 計算暗通道
img_min = min_channel(img_arr)
img_dark = min_filter(img_min, 1)
img_guided = guided_filter(img_min, img_dark, 75, 0.001)
t, A = select_bright(img_dark, img, 0.95, 0.1, img_guided)
# 加載原始圖像
if img is None:
print("錯誤:無法加載原始圖像。")
exit()
# 進行去霧處理
dehazed_image = repair(img_arr, t, A)
if dehazed_image is None:
print("錯誤:圖像處理失敗。")
exit()
# 計算 PSNR
dehazed_image_uint8 = (dehazed_image * 255).astype(np.uint8)
psnr_value = psnr(img, dehazed_image_uint8)
# 輸出 PSNR
print("PSNR:", psnr_value)
# 顯示原始圖像
cv2.imshow('Original', img)
cv2.waitKey(0) # 等待用戶按下任意鍵繼續(xù)
# 顯示暗通道圖像
cv2.imshow('Dark Channel', img_dark)
cv2.waitKey(0) # 等待用戶按下任意鍵繼續(xù)
# 顯示去霧后的圖像
cv2.imshow('Dehazed Image', dehazed_image)
cv2.waitKey(0) # 等待用戶按下任意鍵繼續(xù)
# 釋放窗口
cv2.destroyAllWindows()
柚子快報邀請碼778899分享:手把手教你暗通道先驗去霧算法
參考鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。