he博士提出的暗通道先验去雾算法相信大家多有了解,该算法处理后的图像雾气可以得到很有效的去除,可以说是目前最知名的模型了。之前在知网上看到几篇将双边滤波与暗通道结合起来的去雾算法,编程复现后发现去雾效果很是不错,并且原理也并不复杂。下文附上原理和代码。
大气散射模型:
求解暗通道:
求解大气光幕:
求解透射率
图像复原
附代码:
#include#include #include #include #include #include #include #include using namespace cv; using namespace std; void fogremove(Mat& image, Mat& dstimage) { //求解暗通道图 Mat iimage; image.convertTo(iimage, CV_32FC3,1.0 /255,0); int w = 15; Mat iborder; copyMakeBorder(iimage,iborder,w/2, w / 2, w / 2, w / 2, BORDER_REPLICATE); vector ibordervector(3); split(iborder,ibordervector); Mat darkchannel(image.size(), CV_32FC1); double minTemp, minPixel; for (int r = 0; r < darkchannel.rows; r++) { for (int c = 0; c < darkchannel.cols; c++) { minPixel = 1; for (vector ::iterator itib = ibordervector.begin(); itib != ibordervector.end(); itib++) { Mat roi(*itib, Rect(c, r, w, w)); minMaxLoc(roi, &minTemp); minPixel = min(minTemp, minPixel); } darkchannel.at (r, c) = float(minPixel); } } imshow("dark", darkchannel); //求解大气光强 float ratioa = 0.001; int num = ratioa * darkchannel.rows * darkchannel.cols; Mat dv; dv = darkchannel.reshape(1, 1); Mat_ dvidx; sortIdx(dv, dvidx, SORT_EVERY_ROW + SORT_DESCENDING); int count = 0, temp = 0; int x, y; Mat mask(darkchannel.size(), CV_8UC1); int r = 0; for (int c = 0; c < dvidx.cols; c++) { temp = dvidx.at (r, c); x = temp / darkchannel.cols; y = temp % darkchannel.cols; if (count < num) { mask.at (x, y) = 1; count += 1; } else { mask.at (x, y) = 0; } } vector A(3); vector iv(3); split(iimage, iv); vector ::iterator itA = A.begin(); vector ::iterator itiv = iv.begin(); for (; itA != A.end() && itiv != iv.end(); itA++, itiv++) { minMaxLoc(*itiv,0,&(*itA),0,0,mask); } //求解最小颜色分量图 Mat minRgb = Mat::zeros(image.rows, image.cols, CV_8UC1); for (int i = 0; i < image.rows; i++) for (int j = 0; j < image.cols; j++) { uchar g_minvalue = 255; for (int c = 0; c < 3; c++) { if (g_minvalue > image.at (i, j)[c]) g_minvalue = image.at (i, j)[c]; } minRgb.at (i, j) = g_minvalue; } //求解大气光幕 Mat vbx(minRgb.size(), CV_8UC1); Mat wbx(minRgb.size(), CV_8UC1); Mat gx(minRgb.size(), CV_8UC1); bilateralFilter(minRgb, vbx, 15, 10, 10); for (int i = 0; i < image.rows; i++) for (int j = 0; j < image.cols; j++) { wbx.at (i, j) = abs(minRgb.at (i, j) - vbx.at (i, j)); } bilateralFilter(wbx, gx, 15, 10, 10); Mat bx(minRgb.size(), CV_8UC1); int A0 = (A[0] + A[1] + A[2]) / 3 * 255; for (int i = 0; i < image.rows; i++) for (int j = 0; j < image.cols; j++) { bx.at (i, j) = vbx.at (i, j) - 3 * vbx.at (i, j) * gx.at (i, j) / A0; } Mat vx(minRgb.size(), CV_8UC1); for (int i = 0; i < image.rows; i++) for (int j = 0; j < image.cols; j++) { vx.at (i, j) = MAX(MIN(0.9 * bx.at (i, j), minRgb.at (i, j)), 0); } //求解透射率 Mat tx(minRgb.size(), CV_32FC1); for (int i = 0; i < image.rows; i++) for (int j = 0; j < image.cols; j++) { tx.at (i, j) = 1 - 0.95 * vx.at (i, j) / A0; } imshow("tx", tx); //图像复原 float t0 = 0.1; for (size_t r = 0; r < dstimage.rows; r++) { for (size_t c = 0; c < dstimage.cols; c++) { dstimage.at (r, c) = Vec3f((iimage.at (r, c)[0] - A[0]) / max(tx.at (r, c), t0) + A[0], (iimage.at (r, c)[1] - A[1]) / max(tx.at (r, c), t0) + A[1], (iimage.at (r, c)[2] - A[2]) / max(tx.at (r, c), t0) + A[2]); } } imshow("result",dstimage); } int main() { cv::utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT); Mat src = imread("wutu.png"); Mat dst(src.size(), CV_32FC3); imshow("original",src); fogremove(src,dst); waitKey(); return 0; }
以上代码在配置了opencv库的基础上可以直接运行,效果如下:
原图:
去雾后图像
最后列出本文参考的相关文献,帮助大家可以更好地理解和作出进一步的改进。
王一帆,尹传历,黄义明,王洪玉.基于双边滤波的图像去雾[J].中国图象图形学报,2014,19(03):386-392;
余永龙. 结合双边滤波与暗通道的图像去雾算法及应用研究[D].南昌航空大学,2015;
陈龙,郭宝龙,毕娟,朱娟娟.基于联合双边滤波的单幅图像去雾算法[J].北京邮电大学学报,2012,35(04):19-23.



