opencv 彩色图片去雾化 c++代码
时间: 2023-07-24 15:34:20 浏览: 85
以下是OpenCV C++代码示例,用于对彩色图像进行去雾处理:
```c++
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// 获取暗通道
Mat getDarkChannel(Mat src, int patchSize)
{
Mat darkChannel = Mat::zeros(src.rows, src.cols, CV_8UC1);
int halfPatchSize = patchSize / 2;
for (int i = halfPatchSize; i < src.rows - halfPatchSize; i++)
{
for (int j = halfPatchSize; j < src.cols - halfPatchSize; j++)
{
// 获取当前像素点的局部区域
Mat patch = src(Rect(Point(j - halfPatchSize, i - halfPatchSize), Size(patchSize, patchSize)));
// 计算局部区域内的最小值
double minVal;
minMaxLoc(patch, &minVal, NULL);
// 将最小值作为暗通道像素值
darkChannel.at<uchar>(i, j) = static_cast<uchar>(minVal);
}
}
return darkChannel;
}
// 估计全局大气光
Scalar getAirlight(Mat src, Mat darkChannel)
{
int numPixels = src.rows * src.cols * 0.1;
Mat sortedValues;
cv::sort(darkChannel, sortedValues, SORT_DESCENDING);
int thresholdIdx = sortedValues.at<uchar>(numPixels);
uchar thresholdValue = darkChannel.at<uchar>(thresholdIdx);
Scalar airlight = Scalar(0, 0, 0);
int count = 0;
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
if (darkChannel.at<uchar>(i, j) >= thresholdValue)
{
Vec3f pixel = src.at<Vec3f>(i, j);
airlight += Scalar(pixel[0], pixel[1], pixel[2]);
count++;
}
}
}
airlight /= static_cast<double>(count);
return airlight;
}
// 计算传播图像
Mat getTransmission(Mat src, Scalar airlight, double omega, int patchSize)
{
Mat transmission = Mat::zeros(src.rows, src.cols, CV_32FC1);
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
Vec3f pixel = src.at<Vec3f>(i, j);
double numerator = 1.0 - omega * getDarkChannel(pixel, patchSize).at<uchar>(0, 0) / airlight.val[0];
double denominator = 1.0 - omega * getDarkChannel(pixel, patchSize).at<uchar>(0, 0) / airlight.val[0];
for (int k = 1; k < 3; k++)
{
numerator = min(numerator, 1.0 - omega * getDarkChannel(pixel, patchSize).at<uchar>(0, k) / airlight.val[k]);
denominator = min(denominator, 1.0 - omega * getDarkChannel(pixel, patchSize).at<uchar>(0, k) / airlight.val[k]);
}
transmission.at<float>(i, j) = static_cast<float>(numerator / denominator);
}
}
return transmission;
}
// 估计场景深度
double getDepth(Mat transmission, double beta)
{
double depth = 1.0 - beta * cv::mean(transmission).val[0];
return depth;
}
// 软抠图
Mat softMatting(Mat src, Mat transmission, double lambda, int winSize)
{
Mat result = Mat::zeros(src.rows, src.cols, CV_32FC3);
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
Vec3f pixel = src.at<Vec3f>(i, j);
float t = transmission.at<float>(i, j);
Mat localPatch = src(Rect(Point(j - winSize / 2, i - winSize / 2), Size(winSize, winSize))).reshape(1, winSize * winSize);
Mat cov = (localPatch.t() * localPatch) / (winSize * winSize) + Mat::eye(3, 3, CV_32FC1) * lambda / t;
Mat invCov = cov.inv();
Mat alpha = invCov * localPatch.t() / (winSize * winSize);
Vec3f resultPixel = alpha.at<Vec3f>(0, 0) * t + (1 - t) * pixel;
result.at<Vec3f>(i, j) = resultPixel;
}
}
return result;
}
int main()
{
// 读取彩色图像
Mat src = imread("input.jpg");
Mat srcFloat;
src.convertTo(srcFloat, CV_32FC3, 1.0 / 255.0);
// 参数设置
int patchSize = 15;
double omega = 0.95;
double beta = 1.0;
double lambda = 0.1;
int winSize = 3;
// 获取暗通道
Mat darkChannel = getDarkChannel(srcFloat, patchSize);
// 估计全局大气光
Scalar airlight = getAirlight(srcFloat, darkChannel);
// 计算传播图像
Mat transmission = getTransmission(srcFloat, airlight, omega, patchSize);
// 估计场景深度
double depth = getDepth(transmission, beta);
// 软抠图
Mat result = softMatting(srcFloat, transmission, lambda, winSize);
// 进行调整
result = (result - result.min()) / (result.max() - result.min());
result = result * 255.0;
result.convertTo(result, CV_8UC3);
// 显示结果
namedWindow("Input", WINDOW_AUTOSIZE);
namedWindow("Output", WINDOW_AUTOSIZE);
imshow("Input", src);
imshow("Output", result);
waitKey(0);
return 0;
}
```
在上面的代码中,我们首先读取彩色图像,然后将其转换为浮点型图像,接着进行去雾处理,并显示结果。整个处理过程包括以下几个步骤:
1. 获取暗通道;
2. 估计全局大气光;
3. 计算传播图像;
4. 估计场景深度;
5. 软抠图;
6. 进行调整,并显示结果。
其中,getDarkChannel() 函数用于获取暗通道,采用的是简单的滑动窗口方法;getAirlight() 函数用于估计全局大气光,采用的是基于暗通道的方法;getTransmission() 函数用于计算传播图像,采用的是基于暗通道先验的方法;getDepth() 函数用于估计场景深度,采用的是简单的线性模型;softMatting() 函数用于进行软抠图,采用的是基于颜色一致性的方法。最后,我们可以将结果显示出来,以便观察。
阅读全文