低光照图像增强算法汇总
目錄
- 1、場景需求
- 2、Retinex算法
- 2.1 Retinex算法簡介
- 2.2 Retinex核心代碼實現(xiàn)
- 2.3 Retinex算法效果展示與分析
- 3、LIME算法
- 3.1、LIME算法簡介
- 3.2、LIME核心代碼實現(xiàn)
- 3.3、LIME算法效果展示與分析
- 4、RetinexNet算法
- 4.1 RetinexNet算法簡介
- 4.2 RetinexNet網(wǎng)絡(luò)詳解
- 4.3 RetinexNet核心代碼實現(xiàn)
- 4.4 RetinexNet算法效果展示與分析
- 5、MBLLEN算法
- 5.1 MBLLEN算法簡介
- 5.2 MBLLEN網(wǎng)絡(luò)詳解
- 5.3 MBLLEN核心代碼實現(xiàn)
- 5.4 MBLLEN算法效果展示與分析
- 6、KinD算法
- 6.1 KinD算法簡介
- 6.2 KinD網(wǎng)絡(luò)詳解
- 6.3 KinD核心代碼實現(xiàn)
- 6.4 KinD算法效果展示與分析
- 7、EnlightenGAN算法
- 7.1 EnlightenGAN算法簡介
- 7.2 EnlightenGAN網(wǎng)絡(luò)簡介
- 7.3 EnlightenGAN核心代碼實現(xiàn)
- 7.4 EnlightenGAN算法效果展示與分析
- 8、總結(jié)
- 參考資料
- 注意事項
1、場景需求
??在現(xiàn)實場景中,由于光線、視角等問題會導致我們拍攝出來的照片比較陰暗,具體的圖片如下圖中的1、3、5列所示,然后這些陰暗的圖片不僅會影響我們的觀察,而且會極大的影響計算機視覺處理算法的效果,2、4、6列表示的是使用了低光照圖像增強算法之后的效果。本文主要針對低光照的圖片展開論述,對經(jīng)典的一些低光照圖像增強算法進行了總結(jié)和初略的分析。
2、Retinex算法
論文鏈接-Github鏈接
2.1 Retinex算法簡介
??Retinex是一種常用的建立在科學實驗和科學分析基礎(chǔ)上的圖像增強方法,它是由Edwin.H. Land于1963年提出的。Retinex的基礎(chǔ)理論是物體的顏色是由物體對長波(紅色)、中波(綠色)、短波(藍色)光線的反射能力來決定的,而不是由反射光強度的絕對值來決定的,物體的色彩不受光照非均勻性的影響,具有一致性,即retinex是以色感一致性(顏色恒常性)為基礎(chǔ)的。**不同于傳統(tǒng)的線性、非線性的只能增強圖像某一類特征的方法,Retinex可以在動態(tài)范圍壓縮、邊緣增強和顏色恒定三個方面做到平衡,因此可以對各種不同類型的圖像進行自適應(yīng)的增強。**具體的原理請參考該博客。
2.2 Retinex核心代碼實現(xiàn)
# coding=utf-8 import numpy as np import cv2def singleScaleRetinex(img, sigma):'''單尺度Retinex函數(shù)'''retinex = np.log10(img) - np.log10(cv2.GaussianBlur(img, (0, 0), sigma))return retinexdef multiScaleRetinex(img, sigma_list):'''多尺度Retinex函數(shù)'''# 提前分配空間retinex = np.zeros_like(img)# 遍歷所有的尺度for sigma in sigma_list:# 對計算的結(jié)果進行疊加retinex += singleScaleRetinex(img, sigma)# 計算多個尺度的平均值retinex = retinex / len(sigma_list)return retinexdef colorRestoration(img, alpha, beta):'''顏色灰度函數(shù)'''img_sum = np.sum(img, axis=2, keepdims=True)color_restoration = beta * (np.log10(alpha * img) - np.log10(img_sum))return color_restorationdef simplestColorBalance(img, low_clip, high_clip): '''最簡單的顏色均衡函數(shù)'''total = img.shape[0] * img.shape[1]for i in range(img.shape[2]):unique, counts = np.unique(img[:, :, i], return_counts=True)current = 0for u, c in zip(unique, counts): if float(current) / total < low_clip:low_val = uif float(current) / total < high_clip:high_val = ucurrent += c img[:, :, i] = np.maximum(np.minimum(img[:, :, i], high_val), low_val)return img def MSRCR(img, sigma_list, G, b, alpha, beta, low_clip, high_clip):'''MSRCR函數(shù)'''img = np.float64(img) + 1.0# 對原圖先做多尺度的Retineximg_retinex = multiScaleRetinex(img, sigma_list) # 對原圖做顏色恢復img_color = colorRestoration(img, alpha, beta) # 進行圖像融合 img_msrcr = G * (img_retinex * img_color + b)for i in range(img_msrcr.shape[2]):img_msrcr[:, :, i] = (img_msrcr[:, :, i] - np.min(img_msrcr[:, :, i])) / \(np.max(img_msrcr[:, :, i]) - np.min(img_msrcr[:, :, i])) * \255# 將圖像調(diào)整到[0,255]范圍內(nèi) img_msrcr = np.uint8(np.minimum(np.maximum(img_msrcr, 0), 255))# 做簡單的顏色均衡img_msrcr = simplestColorBalance(img_msrcr, low_clip, high_clip) return img_msrcrdef automatedMSRCR(img, sigma_list):'''automatedMSRCR函數(shù)'''img = np.float64(img) + 1.0img_retinex = multiScaleRetinex(img, sigma_list)for i in range(img_retinex.shape[2]):unique, count = np.unique(np.int32(img_retinex[:, :, i] * 100), return_counts=True)for u, c in zip(unique, count):if u == 0:zero_count = cbreaklow_val = unique[0] / 100.0high_val = unique[-1] / 100.0for u, c in zip(unique, count):if u < 0 and c < zero_count * 0.1:low_val = u / 100.0if u > 0 and c < zero_count * 0.1:high_val = u / 100.0break img_retinex[:, :, i] = np.maximum(np.minimum(img_retinex[:, :, i], high_val), low_val)img_retinex[:, :, i] = (img_retinex[:, :, i] - np.min(img_retinex[:, :, i])) / \(np.max(img_retinex[:, :, i]) - np.min(img_retinex[:, :, i])) \* 255img_retinex = np.uint8(img_retinex)return img_retinexdef MSRCP(img, sigma_list, low_clip, high_clip):'''MSRCP函數(shù)'''img = np.float64(img) + 1.0intensity = np.sum(img, axis=2) / img.shape[2] retinex = multiScaleRetinex(intensity, sigma_list)intensity = np.expand_dims(intensity, 2)retinex = np.expand_dims(retinex, 2)intensity1 = simplestColorBalance(retinex, low_clip, high_clip)intensity1 = (intensity1 - np.min(intensity1)) / \(np.max(intensity1) - np.min(intensity1)) * \255.0 + 1.0img_msrcp = np.zeros_like(img)for y in range(img_msrcp.shape[0]):for x in range(img_msrcp.shape[1]):B = np.max(img[y, x])A = np.minimum(256.0 / B, intensity1[y, x, 0] / intensity[y, x, 0])img_msrcp[y, x, 0] = A * img[y, x, 0]img_msrcp[y, x, 1] = A * img[y, x, 1]img_msrcp[y, x, 2] = A * img[y, x, 2]img_msrcp = np.uint8(img_msrcp - 1.0)return img_msrcp2.3 Retinex算法效果展示與分析
??上圖展示了Retinex算法在一些真實數(shù)據(jù)上面的效果。上面主要展示了該算法在一些文檔上面的增強效果,第一行的5張圖片表示的是原始的輸入圖片,第二行的5張圖片表示的是使用Retinex算法增強之后的效果。通過觀察我們可以發(fā)現(xiàn),該算法不僅能夠增強圖像的亮度信息,同時可以去除圖片中的部分陰影信息;但是該算法的運算速度比較慢,不能應(yīng)用到一些實時的場景中。
3、LIME算法
論文鏈接-LIME主頁-Github鏈接
3.1、LIME算法簡介
??LIME算法是一個簡單而高效的低光照圖像增強算法。該算法首先通過在R、G和B通道中找到最大值來單獨估計每個像素的照明;然后我們通過在初始光照圖上施加一個結(jié)構(gòu)先驗來細化它,作為最終的光照映射;最后根據(jù)光照映射就可以生成最終的增強圖像。
3.2、LIME核心代碼實現(xiàn)
// 導入頭文件 #include "lime.h" #include <vector> #include <iostream>// 定義命名空間 namespace feature {// 獲取原圖像的通道lime::lime(cv::Mat src){channel = src.channels();}cv::Mat lime::lime_enhance(cv::Mat &src){cv::Mat img_norm;// 圖像歸一化src.convertTo(img_norm, CV_32F, 1 / 255.0, 0);// 提前分配空間cv::Size sz(img_norm.size());cv::Mat out(sz, CV_32F, cv::Scalar::all(0.0));auto gammT = out.clone();// 根據(jù)通道做不同的處理if (channel == 3){Illumination(img_norm, out);Illumination_filter(out, gammT);//limestd::vector<cv::Mat> img_norm_rgb;cv::Mat img_norm_b, img_norm_g, img_norm_r;cv::split(img_norm, img_norm_rgb);img_norm_g = img_norm_rgb.at(0);img_norm_b = img_norm_rgb.at(1);img_norm_r = img_norm_rgb.at(2);cv::Mat one = cv::Mat::ones(sz, CV_32F);float nameta = 0.9;auto g = 1 - ((one - img_norm_g) - (nameta * (one - gammT))) / gammT;auto b = 1 - ((one - img_norm_b) - (nameta * (one - gammT))) / gammT;auto r = 1 - ((one - img_norm_r) - (nameta * (one - gammT))) / gammT;cv::Mat g1, b1, r1;//TODO <=1threshold(g, g1, 0.0, 0.0, 3);threshold(b, b1, 0.0, 0.0, 3);threshold(r, r1, 0.0, 0.0, 3);img_norm_rgb.clear();img_norm_rgb.push_back(g1);img_norm_rgb.push_back(b1);img_norm_rgb.push_back(r1);cv::merge(img_norm_rgb,out_lime);out_lime.convertTo(out_lime,CV_8U,255);}else if(channel == 1){Illumination_filter(img_norm, gammT);cv::Mat one = cv::Mat::ones(sz, CV_32F);float nameta = 0.9;//std::cout<<img_norm.at<float>(1,1)<<std::endl;auto out = 1 - ((one - img_norm) - (nameta * (one - gammT))) / gammT;threshold(out, out_lime, 0.0, 0.0, 3);out_lime.convertTo(out_lime,CV_8UC1,255);}else{std::cout<<"There is a problem with the channels"<<std::endl;exit(-1);}return out_lime.clone();}void lime::Illumination_filter(cv::Mat& img_in,cv::Mat& img_out){int ksize = 5;//mean filterblur(img_in,img_out,cv::Size(ksize,ksize));//GaussianBlur(img_in,img_mean_filter,Size(ksize,ksize),0,0);//gammaint row = img_out.rows;int col = img_out.cols;float tem;float gamma = 0.8;for(int i=0;i<row;i++){for(int j=0;j<col;j++){tem = pow(img_out.at<float>(i,j),gamma);tem = tem <= 0 ? 0.0001 : tem; // double epsolon = 0.0001;tem = tem > 1 ? 1 : tem;img_out.at<float>(i,j) = tem;}}}void lime::Illumination(cv::Mat& src,cv::Mat& out){int row = src.rows, col = src.cols;for(int i=0;i<row;i++){for(int j=0;j<col;j++){out.at<float>(i,j) = lime::compare(src.at<cv::Vec3f>(i,j)[0],src.at<cv::Vec3f>(i,j)[1],src.at<cv::Vec3f>(i,j)[2]);}}} }3.3、LIME算法效果展示與分析
??上圖展示了LIME算法在一些圖片上面的效果,第一行表示的是原始的輸入圖片,第二行表示的是由LIME算法輸出的光照映射,第三行表示的是經(jīng)過LIME算法增強之后的效果。通過觀察我們可以得出,LIME算法能夠較好的處理一些低光照圖片,美中不足的是經(jīng)過LIME算法增強之后的圖片的色彩好像不太理想。
4、RetinexNet算法
論文鏈接-Github鏈接-項目主頁
4.1 RetinexNet算法簡介
??RetinexNet是Retinex算法的加強版,主要的思路是通過在收集到的低光照數(shù)據(jù)塊上面訓練一個神經(jīng)網(wǎng)絡(luò)。整個網(wǎng)路分為兩部分,Decom-Net網(wǎng)絡(luò)用來實現(xiàn)圖像分解,Enhance-Net網(wǎng)絡(luò)用來實現(xiàn)光照調(diào)節(jié)。在訓練Decom-Net的過程中,沒有GT,學習網(wǎng)絡(luò)時只需滿足以下關(guān)鍵約束條件包括由成對的低/正常光圖像共享的一致反射率以及光照的一致性,由Enhance-Net來實現(xiàn)光照的增強。RetinexNet是一個端到端的低光照增強網(wǎng)絡(luò),大量的實驗表明,該方法不僅可以獲得令人滿意的低光增強效果,而且可以很好地表示圖像分解。
4.2 RetinexNet網(wǎng)絡(luò)詳解
??上圖展示了RetinexNet網(wǎng)絡(luò)的實現(xiàn)細節(jié),整個圖像增強的過程分為三步,具體包括圖像分解、亮度調(diào)整,圖像重建。在圖像分解階段,Decom-Net子網(wǎng)絡(luò)將輸入的圖像分解為反射率圖像和光照圖像兩部分,兩個部分之間共享權(quán)重,如上圖中的Snormal和Slow所示,輸入的兩個圖像都被分解成兩個部分;在光照調(diào)節(jié)階段,一個基于編解碼架構(gòu)的Enhance-Net網(wǎng)絡(luò)用來對光照圖像進行光照增強,該子網(wǎng)絡(luò)中包含著一些殘差連接用來解決梯度消失問題,同時對反射率圖像執(zhí)行去噪操作;在圖像重建階段,將經(jīng)過光照增強的光照圖像和經(jīng)過去噪的反射率圖像重新組合起來形成最終的增強圖片。
4.3 RetinexNet核心代碼實現(xiàn)
# 導入相應(yīng)的python包 from __future__ import print_functionimport os import time import randomfrom PIL import Image import tensorflow as tf import numpy as npfrom utils import *# 定義concat操作 def concat(layers):return tf.concat(layers, axis=3)def DecomNet(input_im, layer_num, channel=64, kernel_size=3):'''分解子網(wǎng)絡(luò)函數(shù)'''input_max = tf.reduce_max(input_im, axis=3, keepdims=True)input_im = concat([input_max, input_im])with tf.variable_scope('DecomNet', reuse=tf.AUTO_REUSE):conv = tf.layers.conv2d(input_im, channel, kernel_size * 3, padding='same', activation=None, name="shallow_feature_extraction")for idx in range(layer_num):conv = tf.layers.conv2d(conv, channel, kernel_size, padding='same', activation=tf.nn.relu, name='activated_layer_%d' % idx)conv = tf.layers.conv2d(conv, 4, kernel_size, padding='same', activation=None, name='recon_layer')R = tf.sigmoid(conv[:,:,:,0:3])L = tf.sigmoid(conv[:,:,:,3:4])return R, Ldef RelightNet(input_L, input_R, channel=64, kernel_size=3):'''光照增強子網(wǎng)絡(luò)函數(shù)'''input_im = concat([input_R, input_L])with tf.variable_scope('RelightNet'):conv0 = tf.layers.conv2d(input_im, channel, kernel_size, padding='same', activation=None)conv1 = tf.layers.conv2d(conv0, channel, kernel_size, strides=2, padding='same', activation=tf.nn.relu)conv2 = tf.layers.conv2d(conv1, channel, kernel_size, strides=2, padding='same', activation=tf.nn.relu)conv3 = tf.layers.conv2d(conv2, channel, kernel_size, strides=2, padding='same', activation=tf.nn.relu)up1 = tf.image.resize_nearest_neighbor(conv3, (tf.shape(conv2)[1], tf.shape(conv2)[2]))deconv1 = tf.layers.conv2d(up1, channel, kernel_size, padding='same', activation=tf.nn.relu) + conv2up2 = tf.image.resize_nearest_neighbor(deconv1, (tf.shape(conv1)[1], tf.shape(conv1)[2]))deconv2= tf.layers.conv2d(up2, channel, kernel_size, padding='same', activation=tf.nn.relu) + conv1up3 = tf.image.resize_nearest_neighbor(deconv2, (tf.shape(conv0)[1], tf.shape(conv0)[2]))deconv3 = tf.layers.conv2d(up3, channel, kernel_size, padding='same', activation=tf.nn.relu) + conv0deconv1_resize = tf.image.resize_nearest_neighbor(deconv1, (tf.shape(deconv3)[1], tf.shape(deconv3)[2]))deconv2_resize = tf.image.resize_nearest_neighbor(deconv2, (tf.shape(deconv3)[1], tf.shape(deconv3)[2]))feature_gather = concat([deconv1_resize, deconv2_resize, deconv3])feature_fusion = tf.layers.conv2d(feature_gather, channel, 1, padding='same', activation=None)output = tf.layers.conv2d(feature_fusion, 1, 3, padding='same', activation=None)return output4.4 RetinexNet算法效果展示與分析
??上面第一張展示了Retinex-Net算法在一些室內(nèi)和室外場景下和其它不同增強算法的比較結(jié)果,第一列表示原始的輸入圖片,最后一列表示使用Retinex-Net增強之后的結(jié)果。與其它的算法相比,Retinex-Net算法能夠獲得更清晰的增強效果,圖像的細節(jié)更加豐富。第二張展示了Retinex-Net算法在真實的文檔圖片上面的增強效果,第一行表示原始的輸入圖片,第二行表示增強后的圖片,增強后的圖像看起來更加清晰,便于后續(xù)算法的處理。
5、MBLLEN算法
論文鏈接-Github鏈接-項目主頁
5.1 MBLLEN算法簡介
??MBLLEN算法是一個多分支低光照圖像增強網(wǎng)絡(luò)。該算法的核心思想是在不同等級中提取出豐富的圖像特征,因此我們可以通過多個子網(wǎng)絡(luò)做圖像增強,最后通過多分支融合產(chǎn)生輸出圖像。圖像的質(zhì)量從不同的方向得到了提升。該算法不僅僅能用來進行圖像增強,而且可以用來進行視頻增強。
5.2 MBLLEN網(wǎng)絡(luò)詳解
??上圖展示了MBLLEN的網(wǎng)絡(luò)架構(gòu),該網(wǎng)絡(luò)主要包含三個主要的模塊,具體包括FEM模塊、EM模塊和FM模塊。FEM模塊(feature extraction module ),即特征檢測模塊,其主要作用是從圖像中獲取關(guān)鍵的特征,如圖中所示,主要有一些WXHX32的卷積層構(gòu)成;EM模塊(enhancement module),即增強模塊,其主要的作用是通過編解碼架構(gòu)對圖像的特征進行增強,具體的細節(jié)如圖中所示;FM模塊(fusion module),即融合模塊,其主要的作用是將不同等級輸出的結(jié)果融合起來,從而形成最終的結(jié)果。
5.3 MBLLEN核心代碼實現(xiàn)
# 導入相應(yīng)的python包 from keras.layers import Input, Conv2D, Conv2DTranspose, Concatenate from keras.applications.vgg19 import VGG19 from keras.models import Modeldef build_vgg():''''搭建VGG基準網(wǎng)絡(luò)函數(shù)'''# 使用預訓練的VGG網(wǎng)絡(luò)vgg_model = VGG19(include_top=False, weights='imagenet')vgg_model.trainable = Falsereturn Model(inputs=vgg_model.input, outputs=vgg_model.get_layer('block3_conv4').output)def build_mbllen(input_shape):def EM(input, kernal_size, channel):'''搭建EM子網(wǎng)絡(luò)函數(shù)'''conv_1 = Conv2D(channel, (3, 3), activation='relu', padding='same', data_format='channels_last')(input)conv_2 = Conv2D(channel, (kernal_size, kernal_size), activation='relu', padding='valid', data_format='channels_last')(conv_1)conv_3 = Conv2D(channel*2, (kernal_size, kernal_size), activation='relu', padding='valid', data_format='channels_last')(conv_2)conv_4 = Conv2D(channel*4, (kernal_size, kernal_size), activation='relu', padding='valid', data_format='channels_last')(conv_3)conv_5 = Conv2DTranspose(channel*2, (kernal_size, kernal_size), activation='relu', padding='valid', data_format='channels_last')(conv_4)conv_6 = Conv2DTranspose(channel, (kernal_size, kernal_size), activation='relu', padding='valid', data_format='channels_last')(conv_5)res = Conv2DTranspose(3, (kernal_size, kernal_size), activation='relu', padding='valid', data_format='channels_last')(conv_6)return resinputs = Input(shape=input_shape)FEM = Conv2D(32, (3, 3), activation='relu', padding='same', data_format='channels_last')(inputs)EM_com = EM(FEM, 5, 8)for j in range(3):for i in range(0, 3):FEM = Conv2D(32, (3, 3), activation='relu', padding='same', data_format='channels_last')(FEM)EM1 = EM(FEM, 5, 8)EM_com = Concatenate(axis=3)([EM_com, EM1])outputs = Conv2D(3, (1, 1), activation='relu', padding='same', data_format='channels_last')(EM_com)return Model(inputs, outputs)5.4 MBLLEN算法效果展示與分析
??上圖展示了MBLLEN算法的增強效果。第一張圖表示的是MBLLEN算法在一些公有數(shù)據(jù)集上面和其它算法的比較結(jié)果,通過觀察可以得知,該算法能夠獲得更加自然的增強效果,增強后的圖像的整體效果看起來比較舒服,增強之后的細節(jié)更加清晰。第二張圖表示的是該算法在幾張真實的文檔圖像上面的增強效果,增強之后的圖片中仿佛進入了陽光,整個圖片都變得亮堂了很多,但是在有些情況下,該算法輸出的結(jié)果有點過曝光的效果,幸運的是該算法還可以輸出一個較低亮度的結(jié)果,具體的結(jié)果留給你自己去做測試。
6、KinD算法
論文鏈接-Github鏈接
6.1 KinD算法簡介
??在暗光條件下拍攝的圖像經(jīng)常(部分)能見度低。除了不滿意的燈光,多種類型的退化,如由于相機質(zhì)量的限制而產(chǎn)生的噪聲和顏色失真,隱藏在黑暗中。換句話說,
僅僅提高暗區(qū)的亮度必然會放大隱藏的偽影。KinD算法是一個簡單高效的網(wǎng)絡(luò),它是受到Retinex的啟發(fā),將原始的圖像分解為兩個部分。KinD將原始的圖像空間分解為兩個比較相似的子空間,該算法使用在不同曝光程度的圖片塊來進行訓練,該算法對嚴重的視覺缺陷具有很強的魯棒性,并且用戶友好地任意調(diào)整光照水平。另外,我們的模型在2080ti GPU上處理一個VGA分辨率處理圖像的時間不到50ms。
6.2 KinD網(wǎng)絡(luò)詳解
??上圖展示了KinD算法的整體網(wǎng)絡(luò)架構(gòu)。整個網(wǎng)絡(luò)的架構(gòu)和RetinexNet很相似,整個網(wǎng)絡(luò)包括Decomposition-Net、Adjustment-Net和Restoration-Net,Decomposition-Net子網(wǎng)絡(luò)的作用是對輸入的圖像進行分解,網(wǎng)絡(luò)結(jié)構(gòu)方面和RetinexNet稍微有一些不同,但是主要的作用是相同的;Adjustment-Net用來調(diào)節(jié)光照,該子網(wǎng)絡(luò)由幾個卷積層組成,該網(wǎng)絡(luò)不執(zhí)行去噪操作;Restoration-Net子網(wǎng)絡(luò)的作用是通過組合反射率圖像和光照圖像形成最終的增強圖像,該子網(wǎng)絡(luò)是一個帶有殘差連接的編解碼網(wǎng)絡(luò),具體的細節(jié)如上圖所示。
6.3 KinD核心代碼實現(xiàn)
# 導入相應(yīng)的Python包 import tensorflow as tf import tensorflow.contrib.slim as slim from tensorflow.contrib.layers.python.layers import initializersdef lrelu(x, trainbable=None):return tf.maximum(x*0.2,x)def upsample_and_concat(x1, x2, output_channels, in_channels, scope_name, trainable=True):with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE) as scope:pool_size = 2deconv_filter = tf.get_variable('weights', [pool_size, pool_size, output_channels, in_channels], trainable= True)deconv = tf.nn.conv2d_transpose(x1, deconv_filter, tf.shape(x2) , strides=[1, pool_size, pool_size, 1], name=scope_name)deconv_output = tf.concat([deconv, x2],3)deconv_output.set_shape([None, None, None, output_channels*2])return deconv_outputdef DecomNet_simple(input):'''分解網(wǎng)絡(luò)實現(xiàn)函數(shù)'''with tf.variable_scope('DecomNet', reuse=tf.AUTO_REUSE):conv1=slim.conv2d(input,32,[3,3], rate=1, activation_fn=lrelu,scope='g_conv1_1')pool1=slim.max_pool2d(conv1, [2, 2], stride = 2, padding='SAME' )conv2=slim.conv2d(pool1,64,[3,3], rate=1, activation_fn=lrelu,scope='g_conv2_1')pool2=slim.max_pool2d(conv2, [2, 2], stride = 2, padding='SAME' )conv3=slim.conv2d(pool2,128,[3,3], rate=1, activation_fn=lrelu,scope='g_conv3_1')up8 = upsample_and_concat( conv3, conv2, 64, 128 , 'g_up_1')conv8=slim.conv2d(up8, 64,[3,3], rate=1, activation_fn=lrelu,scope='g_conv8_1')up9 = upsample_and_concat( conv8, conv1, 32, 64 , 'g_up_2')conv9=slim.conv2d(up9, 32,[3,3], rate=1, activation_fn=lrelu,scope='g_conv9_1')# Here, we use 1*1 kernel to replace the 3*3 ones in the paper to get better results.conv10=slim.conv2d(conv9,3,[1,1], rate=1, activation_fn=None, scope='g_conv10')R_out = tf.sigmoid(conv10)l_conv2=slim.conv2d(conv1,32,[3,3], rate=1, activation_fn=lrelu,scope='l_conv1_2')l_conv3=tf.concat([l_conv2, conv9],3)# Here, we use 1*1 kernel to replace the 3*3 ones in the paper to get better results.l_conv4=slim.conv2d(l_conv3,1,[1,1], rate=1, activation_fn=None,scope='l_conv1_4')L_out = tf.sigmoid(l_conv4)return R_out, L_outdef Restoration_net(input_r, input_i):'''重建網(wǎng)絡(luò)實現(xiàn)函數(shù)'''with tf.variable_scope('Restoration_net', reuse=tf.AUTO_REUSE):input_all = tf.concat([input_r,input_i], 3)conv1=slim.conv2d(input_all,32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv1_1')conv1=slim.conv2d(conv1,32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv1_2')pool1=slim.max_pool2d(conv1, [2, 2], padding='SAME' )conv2=slim.conv2d(pool1,64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv2_1')conv2=slim.conv2d(conv2,64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv2_2')pool2=slim.max_pool2d(conv2, [2, 2], padding='SAME' )conv3=slim.conv2d(pool2,128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv3_1')conv3=slim.conv2d(conv3,128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv3_2')pool3=slim.max_pool2d(conv3, [2, 2], padding='SAME' )conv4=slim.conv2d(pool3,256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv4_1')conv4=slim.conv2d(conv4,256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv4_2')pool4=slim.max_pool2d(conv4, [2, 2], padding='SAME' )conv5=slim.conv2d(pool4,512,[3,3], rate=1, activation_fn=lrelu,scope='de_conv5_1')conv5=slim.conv2d(conv5,512,[3,3], rate=1, activation_fn=lrelu,scope='de_conv5_2')up6 = upsample_and_concat( conv5, conv4, 256, 512, 'up_6')conv6=slim.conv2d(up6, 256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv6_1')conv6=slim.conv2d(conv6,256,[3,3], rate=1, activation_fn=lrelu,scope='de_conv6_2')up7 = upsample_and_concat( conv6, conv3, 128, 256, 'up_7' )conv7=slim.conv2d(up7, 128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv7_1')conv7=slim.conv2d(conv7,128,[3,3], rate=1, activation_fn=lrelu,scope='de_conv7_2')up8 = upsample_and_concat( conv7, conv2, 64, 128, 'up_8' )conv8=slim.conv2d(up8, 64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv8_1')conv8=slim.conv2d(conv8,64,[3,3], rate=1, activation_fn=lrelu,scope='de_conv8_2')up9 = upsample_and_concat( conv8, conv1, 32, 64, 'up_9' )conv9=slim.conv2d(up9, 32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv9_1')conv9=slim.conv2d(conv9,32,[3,3], rate=1, activation_fn=lrelu,scope='de_conv9_2')conv10=slim.conv2d(conv9,3,[3,3], rate=1, activation_fn=None, scope='de_conv10')out = tf.sigmoid(conv10)return outdef Illumination_adjust_net(input_i, input_ratio):'''光照調(diào)節(jié)網(wǎng)絡(luò)實現(xiàn)函數(shù)'''with tf.variable_scope('Illumination_adjust_net', reuse=tf.AUTO_REUSE):input_all = tf.concat([input_i, input_ratio], 3)conv1=slim.conv2d(input_all,32,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_1')conv2=slim.conv2d(conv1,32,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_2')conv3=slim.conv2d(conv2,32,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_3')conv4=slim.conv2d(conv3,1,[3,3], rate=1, activation_fn=lrelu,scope='en_conv_4')L_enhance = tf.sigmoid(conv4)return L_enhance6.4 KinD算法效果展示與分析
??上圖展示了KinD算法的增強效果。第一張圖像表示的是該算法和其它經(jīng)典的增強算法之間的比較結(jié)果,通過觀察我們可以發(fā)現(xiàn),通過該算法增強后的圖像的更加明亮,看起來更加逼真,色彩基本上都正常的復原了。第二張圖像表示的是該算法在幾張真實的文檔圖片上面的增強效果,除了在第四列圖像上面有一點問題,在其它圖像上面都展現(xiàn)出來較好的增強效果。除此之外,需要提到的是該算法的運行速度并不快,2080Ti上面都需要50ms,都達不到實時,速度還待改進,作者出了一個改進版的KinD++,具體的細節(jié)的效果請看該鏈接。
7、EnlightenGAN算法
論文鏈接-Github鏈接
7.1 EnlightenGAN算法簡介
??EnlightenGAN算法是一個高效的無監(jiān)督生成對抗網(wǎng)絡(luò),它不需要使用低光照/正常圖像塊訓練,大量實驗結(jié)果表明該算法可以在很多測試圖片中取得較好的泛化效果。該算法使用從輸入本身提取的信息來正則化非配對訓練,論文中提出了一個全局-局部鑒別器結(jié)構(gòu)、一個自正則感知損失融合與注意力機制。總而言之,這個算法開啟了無監(jiān)督圖像增強的先河,在訓練使用非配對的訓練塊,而且具有很好的泛化效果,它推動了GAN在圖像增強問題上面的應(yīng)用。
7.2 EnlightenGAN網(wǎng)絡(luò)簡介
??上圖展示了EnlightenGAN網(wǎng)絡(luò)的整體架構(gòu)。整個網(wǎng)絡(luò)包括一個生成器和一個判別器,該生成器是一個帶有殘差連接的編解碼網(wǎng)絡(luò),每一個卷積塊包含兩個3x3的卷積、一個BN和一個LeakyRelu,每一個注意力模塊是有特征映射和注意力映射相乘獲得的;該網(wǎng)絡(luò)包含一個全局判別器和一個局部判別器,全局判別器的輸入是整張圖片,它用來判別輸入的圖片是沒有增強的還是增強過的,局部判別器的輸入是一些patch塊,用來判斷這些patch是增強之后還是沒有增強的。
7.3 EnlightenGAN核心代碼實現(xiàn)
def define_G(input_nc, output_nc, ngf, which_model_netG, norm='batch', use_dropout=False, gpu_ids=[], skip=False, opt=None):'''生成器網(wǎng)絡(luò)代碼實現(xiàn)'''netG = Noneuse_gpu = len(gpu_ids) > 0norm_layer = get_norm_layer(norm_type=norm)if use_gpu:assert(torch.cuda.is_available())if which_model_netG == 'resnet_9blocks':netG = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=9, gpu_ids=gpu_ids)elif which_model_netG == 'resnet_6blocks':netG = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=6, gpu_ids=gpu_ids)elif which_model_netG == 'unet_128':netG = UnetGenerator(input_nc, output_nc, 7, ngf, norm_layer=norm_layer, use_dropout=use_dropout, gpu_ids=gpu_ids)elif which_model_netG == 'unet_256':netG = UnetGenerator(input_nc, output_nc, 8, ngf, norm_layer=norm_layer, use_dropout=use_dropout, gpu_ids=gpu_ids, skip=skip, opt=opt)elif which_model_netG == 'unet_512':netG = UnetGenerator(input_nc, output_nc, 9, ngf, norm_layer=norm_layer, use_dropout=use_dropout, gpu_ids=gpu_ids, skip=skip, opt=opt)elif which_model_netG == 'sid_unet':netG = Unet(opt, skip)elif which_model_netG == 'sid_unet_shuffle':netG = Unet_pixelshuffle(opt, skip)elif which_model_netG == 'sid_unet_resize':netG = Unet_resize_conv(opt, skip)elif which_model_netG == 'DnCNN':netG = DnCNN(opt, depth=17, n_channels=64, image_channels=1, use_bnorm=True, kernel_size=3)else:raise NotImplementedError('Generator model name [%s] is not recognized' % which_model_netG)if len(gpu_ids) >= 0:netG.cuda(device=gpu_ids[0])netG = torch.nn.DataParallel(netG, gpu_ids)netG.apply(weights_init)return netGdef define_D(input_nc, ndf, which_model_netD,n_layers_D=3, norm='batch', use_sigmoid=False, gpu_ids=[], patch=False):'''判別器網(wǎng)絡(luò)代碼實現(xiàn)'''netD = Noneuse_gpu = len(gpu_ids) > 0norm_layer = get_norm_layer(norm_type=norm)if use_gpu:assert(torch.cuda.is_available())if which_model_netD == 'basic':netD = NLayerDiscriminator(input_nc, ndf, n_layers=3, norm_layer=norm_layer, use_sigmoid=use_sigmoid, gpu_ids=gpu_ids)elif which_model_netD == 'n_layers':netD = NLayerDiscriminator(input_nc, ndf, n_layers_D, norm_layer=norm_layer, use_sigmoid=use_sigmoid, gpu_ids=gpu_ids)elif which_model_netD == 'no_norm':netD = NoNormDiscriminator(input_nc, ndf, n_layers_D, use_sigmoid=use_sigmoid, gpu_ids=gpu_ids)elif which_model_netD == 'no_norm_4':netD = NoNormDiscriminator(input_nc, ndf, n_layers_D, use_sigmoid=use_sigmoid, gpu_ids=gpu_ids)elif which_model_netD == 'no_patchgan':netD = FCDiscriminator(input_nc, ndf, n_layers_D, use_sigmoid=use_sigmoid, gpu_ids=gpu_ids, patch=patch)else:raise NotImplementedError('Discriminator model name [%s] is not recognized' %which_model_netD)if use_gpu:netD.cuda(device=gpu_ids[0])netD = torch.nn.DataParallel(netD, gpu_ids)netD.apply(weights_init)return netD7.4 EnlightenGAN算法效果展示與分析
??上圖展示了EnlightenGAN算法的增強效果。第一張證明了EnlightenGAN論文中提出的局部判別器和注意力模塊的有效性,同時也體現(xiàn)出了EnlightenGAN算法的增強效果。第二張展示了該算法在真實場景中的一些圖片上面的展示效果,整體看來該算法取得了較好的增強效果,但是在有些圖像上面增強的結(jié)果不是很均勻,仍然存在著一些陰影區(qū)域,不過越來越多的基于GAN的圖像增強算法會慢慢的解決這些問題,敬請期待。
8、總結(jié)
??本文主要對幾種經(jīng)典的低光照圖像算法進行了簡單的介紹,但是并不代表當前只有這么多算法,我介紹的可能只是冰山一角,如果你對低光照圖像增強感興趣,請參考參考文獻中的一些論文和資料。總而言之,低光照圖像增強算法在現(xiàn)實場景中會有很多的應(yīng)用,比如低光照條件下面的檢測、跟蹤、行人重識別;通過圖像增強來提升文本檢測和文本識別的精度,更多的場景還需要你自己去挖掘和應(yīng)用。
參考資料
1、Learning-to-See-in-the-Dark-論文鏈接-Github鏈接-項目主頁
2、DPED-論文鏈接-Github鏈接-項目主頁
3、noteshrink-Github鏈接
4、SICE-論文鏈接Github鏈接
5、Attention-guided Low-light Image Enhancement-論文鏈接
6、部分低光照資料匯總-Github鏈接
注意事項
[1] 如果您對AI、自動駕駛、AR、ChatGPT等技術(shù)感興趣,歡迎關(guān)注我的微信公眾號“AI產(chǎn)品匯”,有問題可以在公眾號中私聊我!
[2] 該博客是本人原創(chuàng)博客,如果您對該博客感興趣,想要轉(zhuǎn)載該博客,請與我聯(lián)系(qq郵箱:1575262785@qq.com),我會在第一時間回復大家,謝謝大家的關(guān)注.
[3] 由于個人能力有限,該博客可能存在很多的問題,希望大家能夠提出改進意見。
[4] 如果您在閱讀本博客時遇到不理解的地方,希望您可以聯(lián)系我,我會及時的回復您,和您交流想法和意見,謝謝。
[5] 本文測試的圖片可以通過該鏈接進行下載。網(wǎng)盤鏈接- 提取碼:x7ta。
[5] 本人業(yè)余時間承接各種本科畢設(shè)設(shè)計和各種小項目,包括圖像處理(數(shù)據(jù)挖掘、機器學習、深度學習等)、matlab仿真、python算法及仿真等,有需要的請加QQ:1575262785詳聊,備注“項目”!!!
總結(jié)
以上是生活随笔為你收集整理的低光照图像增强算法汇总的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【OpenCV】摄像机标定+畸变校正
- 下一篇: GOTS认证咨询,建立记录保存与内部质量