opencv:基于暗通道先验(DCP)的内窥镜图像去雾

目录

项目大体情况

[暗通道先验(Dark Channel Prior, DCP)原理](#暗通道先验(Dark Channel Prior, DCP)原理)

项目代码解析

该项目是由我和我导师与舟山某医院合作开发的一个基于暗通道先验(Dark Channel Prior,DCP)的内窥镜图像去雾方法。具体来说,我们将应用该方法来去除内窥镜图像中的雾霾,使得图像更加清晰,便于后续的分析和诊断。该算法基于图像的暗通道信息,能有效地估算出图像的雾霾程度,并进行恢复。

参考文献

  1. He, K., Sun, J., & Tang, X. (2010). "Single image haze removal using dark channel prior." IEEE Conference on Computer Vision and Pattern Recognition (CVPR) . DOI: 10.1109/CVPR.2010.5539971
  2. Bertalmío, M., & M. S. (2007). "Image inpainting and restoration using dark channel prior." Image Processing: Algorithms and Systems XII . 链接
  3. Fattal, R. (2008). "Single image dehazing." ACM Transactions on Graphics (TOG) , 27(3), 1-9. DOI: 10.1145/1360612.1360652

项目大体情况

因为是寒假在家,所以是没有医院的设备,需要我自己去大概模拟那个环境。具体要实现的目标差不多就是,我需要让电脑A(电脑A认为是内窥镜采集的图像)通过视频采集卡连接到电脑B(用的是Ubuntu的系统,认为是医院的设备),然后用自己编写的程序读取到A的屏幕信息,然后进行暗通道先验窥镜图像去雾。然后图像是4K30帧,所以每帧的图像需要在33ms内处理完成。

视频采集卡,我用的是绿联的产品。

ubantu的主机,我用的是英伟达的一块专门用于深度学习的板子。

下面的是大体的效果,左边的电脑是我采用了远程桌面连接了那块板子,左右电脑之间是用视频采集卡链接。

最终的延迟大概是,传输延迟在8ms左右,每一帧的代码处理时间是在15ms左右。

暗通道先验(Dark Channel Prior, DCP)原理

暗通道先验(DCP)是一种基于图像统计学的去雾方法,它的基本思想是利用图像的暗通道信息来估计图像的雾霾程度,从而恢复出原始的清晰图像。这个方法由**He et al.**于2010年提出,广泛应用于单幅图像的去雾任务中。

1. 暗通道的定义

暗通道是指图像中每个像素的RGB通道 中,最小值的最小值。具体来说,对于图像中的每个像素,找到该像素的三个颜色通道(红色、绿色和蓝色)的最小值,然后在所有像素中找到这些最小值中的最小值,称为暗通道。在实际操作中,暗通道通通常使用3x3的窗口来进行局部计算。

公式表达如下:

  • 表示图像中像素的暗通道值。
  • 表示像素在颜色通道上的值(为RGB)。
  • 表示以像素为中心的一个局部区域,通常是一个的邻域。
2. 暗通道先验的核心思想

暗通道先验的核心假设是:在自然场景中,除了天空等透明物体,几乎所有图像中的像素都会有至少一个颜色通道的强度接近于零。换句话说,对于大多数图像中的像素,至少有一个颜色通道的值会非常小。

  • 雾霾图像:由于雾霾的存在,图像的颜色和对比度会发生改变,使得图像的暗通道值通常会比较高。
  • 无雾图像:清晰的图像中,暗通道值会比较小,因为大多数自然物体(如草地、建筑物等)都有至少一个颜色通道的值接近于零。

这个先验的假设使得我们可以利用图像的暗通道信息来估算图像的雾霾程度。

3. 雾霾图像的模型

为了能够从暗通道先验中恢复出清晰图像,我们需要建立雾霾图像的数学模型。雾霾图像可以用一个简单的物理模型来描述:

  • 表示输入的有雾图像的像素值。
  • 表示无雾图像(清晰图像)的像素值。
  • 表示透射率(transmittance),反映了大气透过率(通常值在[0,1]之间,值越大表示图像越清晰,值越小表示雾霾越重)。
  • 表示大气光(通常是图像中亮度较高的区域的颜色值)。
4. 透射率估计

根据暗通道先验,雾霾图像的暗通道值通常比清晰图像的暗通道值要高。通过以下步骤可以估计透射率:

  1. 计算暗通道:首先计算图像的暗通道,对于每个像素,找到三个颜色通道中的最小值,并且选取局部窗口中的最小值。

  2. 估算大气光:大气光是图像中亮度最高的部分。通过寻找图像中暗通道值最小的像素位置,估算大气光。通常,选择图像中亮度最强的像素值作为大气光。

  3. 估算透射率:通过以下公式计算每个像素的透射率:

    其中,是一个调节参数,通常取值为0.95。该公式基于暗通道先验的假设,透射率与暗通道的值呈反比关系。也就是说,暗通道值越大,透射率越小,说明图像受雾霾的影响越大。

  4. 恢复清晰图像:根据透射率估计值和大气光值,恢复清晰图像:

    这个恢复过程通过反向推算透射率和大气光,去除了雾霾的影响,恢复出清晰图像。

项目代码解析

1. 引入必要的库和定义参数

cpp 复制代码
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cmath>
#include <vector>
#include <chrono>

using namespace cv;
using namespace std;

int block = 1; // block * block 的矩形,block 越大,速度越快,但失真越明显
double omega = 0.6; // 除雾程度,[0,1],值越大,处理后图像颜色越深

在这一段,我们引入了OpenCV库以及其他一些标准库(如cmath、vector、chrono等)。OpenCV提供了图像处理的功能,而chrono则用于计时,帮助我们分析代码的执行效率。

block:这是腐蚀操作的块大小,控制去雾速度和效果的平衡。block越大,计算速度越快,但可能会导致更多失真。

omega:去雾强度的控制参数,决定了去雾的程度,数值越大,图像颜色越深。

2. 最小值函数

cpp 复制代码
double min_3(double g, double b, double r) {
    return std::min({ g, b, r });
}

这段代码定义了一个简单的函数min_3,它用于计算RGB图像中三个通道(红、绿、蓝)的最小值。这在暗通道先验的计算中是非常重要的步骤。

3. 去雾函数

cpp 复制代码
Mat defogging(Mat image_in, int block, double omega) {
    vector<Mat> channels(3);
    split(image_in, channels);
    .......
    parallel_for_(Range(0, image_in.rows), [&](const Range& range) {
    .......
    });

    return out;
}

这段代码实现了图像去雾的核心部分。首先,它会将输入图像分割成RGB三个通道。然后,通过计算每个像素点的暗通道(即最小RGB值),来估算图像的雾霾程度。(这里没有给出完整代码)

  • 使用getStructuringElement创建了一个大小为block的矩形核,然后通过erode操作提取图像的暗通道。
  • omega参数用于控制去雾强度,A为常数,代表白色光的RGB值,最终通过调整亮度来恢复图像清晰度。

在处理每一行图像时,我们使用了OpenCV的parallel_for_函数来并行化操作,提升处理效率。

4. MSCN计算

cpp 复制代码
Mat computeMSCN(const Mat& img, double sigma = 7.0) {
    Mat mu, mu_sq, sigma_img, MSCN;
    GaussianBlur(img, mu, Size(7, 7), sigma);
    mu_sq = mu.mul(mu);

    Mat img_sq = img.mul(img);
    GaussianBlur(img_sq, sigma_img, Size(7, 7), sigma);
    sigma_img = cv::abs(sigma_img - mu_sq);
    sigma_img.convertTo(sigma_img, CV_32F);

    cv::sqrt(sigma_img, sigma_img);
    MSCN = (img - mu) / (sigma_img + 1.0);
    return MSCN;
}

在这里,我们计算了MSCN(均值和标准差归一化)系数,这是NIQE(自然图像质量评估)算法的一个重要步骤。通过高斯模糊计算图像的均值和方差,进而得到标准化的MSCN系数。这一过程为后续的图像质量评估提供了基础。

5. 计算NIQE分数

cpp 复制代码
double calculateNIQE(const Mat& img) {
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    gray.convertTo(gray, CV_32F);

    Mat MSCN = computeMSCN(gray);
    vector<double> imgFeatures = computeFeatures(MSCN);
    vector<double> naturalModel = getNaturalSceneModel();

    return computeDistance(imgFeatures, naturalModel);
}

这段代码计算图像的NIQE分数。首先,将图像转换为灰度图,然后计算其MSCN系数,并提取图像的统计特征。最后,计算图像特征与自然场景模型之间的欧几里得距离,这个距离值作为图像的质量评分,数值越小表示图像质量越好。

6. 视频捕捉和处理

cpp 复制代码
VideoCapture cap(0); // 打开摄像头

if (!cap.isOpened()) {
    cerr << "无法打开采集卡" << endl;
    return -1;
}

while (true) {
    Mat frame;
    cap >> frame;

    if (frame.empty()) {
        cerr << "无法读取视频帧" << endl;
        break;
    }

    // 去雾处理
    Mat dehazed = defogging(frame, block, omega);
    hconcat(frame, dehazed, combined); // 水平拼接
    imshow("原图和去雾后图像", combined);

    imshow("去雾后图像", dehazed);

    if (waitKey(1) == 'q') break;
}

cap.release();
destroyAllWindows();

这一部分代码实现了视频的实时处理。首先打开摄像头,并捕捉每一帧图像。对每一帧图像进行去雾处理,并使用imshow函数将原图与去雾后的图像拼接在一起进行显示。

最终的延迟大概是,传输延迟在8ms左右,每一帧的代码处理时间是在15ms左右。

相关推荐
猿java2 分钟前
MySQL 如何实现主从复制?
java·后端·mysql
小高Baby@7 分钟前
Deepseek
人工智能·笔记
Golinie9 分钟前
【C++高并发服务器WebServer】-12:TCP详解及实现
服务器·c++·tcp·webserver
martian66512 分钟前
【Java基础篇】——第4篇:Java常用类库与工具类
java·开发语言
Amarantine、沐风倩✨15 分钟前
区块链技术未来发展趋势(人工智能和物联网领域)
人工智能·物联网·区块链
LeeZhao@29 分钟前
【AIGC魔童】DeepSeek v3提示词Prompt书写技巧
人工智能·语言模型·自然语言处理·面试·prompt·aigc
nangonghen32 分钟前
user、assistant、system三大角色在大语言模型中的作用(通俗解释)
人工智能·语言模型·大模型
violin-wang37 分钟前
Intellij IDEA调整栈内存空间大小详细教程,添加参数-Xss....
java·ide·intellij-idea·xss·栈内存·栈空间
在下陈平安38 分钟前
java-LinkedList源码详解
java·开发语言
小蜗牛~向前冲40 分钟前
MFC线程安全案例
c++·mfc