具体的理论可以参考这篇文章,写得非常详细。
https://blog.csdn.net/songhhll/article/details/12612681
下面直接进行基于opencv4.10的算法实现
一、求取暗原色图像
//求取min(R,G,B)
Mat minRgb = Mat::zeros(src.rows, src.cols, CV_8UC1);
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
uchar g_minvalue = 255;
for (int c = 0; c < 3; c++)
{
if (g_minvalue > src.at<Vec3b>(i, j)[c])
g_minvalue = src.at<Vec3b>(i, j)[c];
}
minRgb.at<uchar>(i, j) = g_minvalue;
}
}
imshow("min[r,g,b]",minRgb);
//求取暗源色图像
Mat darkChannelImage;
int ksize = std::max(3, std::max((int)(src.cols*kernRatio), (int)(src.rows*kernRatio))); //求取自适应核大小
minFilter(minRgb, darkChannelImage, ksize);
/*显示暗原色图像*/
imshow("Dark_Channel_Image",darkChannelImage);
其中滤波函数为
void minFilter(const cv::Mat src, cv::Mat &dst, int ksize)
{
//检测原始图像
if (src.channels() != 1)
return;
if (src.depth() > 8)
return;
int r = (ksize - 1) / 2; //核半径
//初始化目标图像
dst = Mat::zeros(src.rows, src.cols, CV_8UC1);
//最小值滤波
for (int i = 0; i < src.rows; i++)
for (int j = 0; j < src.cols; j++)
{
//初始化滤波核的上下左右边界
int top = i - r;
int bottom = i + r;
int left = j - r;
int right = j + r;
//检查滤波核是否超出边界
if (i - r < 0)
top = 0;
if (i + r > src.rows)
bottom = src.rows;
if (j - r < 0)
left = 0;
if (j + r > src.cols)
right = src.cols;
//求取模板下的最小值
Mat ImROI = src(Range(top, bottom), Range(left, right));
double min, max;
minMaxLoc(ImROI, &min, &max, 0, 0);
dst.at<uchar>(i, j) = min;
}
}
二、求取透过率图
//求取透过率图(根据暗原色先验原理)
Mat t = Mat::zeros(src.rows, src.cols, CV_64FC1);
for (int i = 0; i < src.rows; i++)
for (int j = 0; j < src.cols; j++)
{
t.at<double>(i, j) = (255.0 -
(double)darkChannelImage.at<uchar>(i, j)*wFactor) / 255;
}
imshow("T_Image",t);//透过率图, 如果要显示 只有范围在0到1之间才有意义
三、求取全局大气光强A
//求取全球大气光强A(全局量)
double A; Point maxLoc;
minMaxLoc(darkChannelImage, 0, &A, 0, &maxLoc);
A = std::max(src.at<Vec3b>(maxLoc.y, maxLoc.x)[0],std::max(src.at<Vec3b>(maxLoc.y, maxLoc.x)[1],
src.at<Vec3b>(maxLoc.y, maxLoc.x)[2]));
四、根据去雾公式求取去雾图像
//根据去雾公式求取去雾图像 J=(I-(1-t)*A)/max(t,min_t)
Mat deFog = Mat::zeros(src.rows, src.cols, CV_8UC3);
for (int i = 0; i < src.rows; i++)
for (int j = 0; j < src.cols; j++)
for (int c = 0; c < src.channels(); c++)
deFog.at<Vec3b>(i, j)[c] = (src.at<Vec3b>(i, j)[c] -
(1 - t.at<double>(i, j))*A) /
std::max(t.at<double>(i, j), min_t);
imshow("defog", deFog);
文章中的代码我已经上传到CSDN上了
https://download.csdn.net/download/weixin_42521239/11167242
没有积分的小伙伴可以在评论中留下你的邮箱,我发给你。