opencv:基于暗通道先验(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的窗口来进行局部计算。

公式表达如下:

I_{\text{dark}}(x) = \min_{c \in \{r,g,b\}} \left( \min_{y \in \Omega(x)} I_c(y) \right)

  • I_{dark}(x) 表示图像中像素$x$的暗通道值。
  • I_c(y)表示像素y在颜色通道$c$上的值($c$为RGB)。
  • $\Omega(x)$ 表示以像素$x$为中心的一个局部区域,通常是一个$3 \times 3$的邻域。
2. 暗通道先验的核心思想

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

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

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

3. 雾霾图像的模型

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

I(x) = J(x) t(x) + A(1 - t(x))

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

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

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

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

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

    t(x) = 1 - \omega \cdot \frac{I_{\text{dark}}(x)}{A}

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

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

    J(x) = \frac{I(x) - A(1 - t(x))}{t(x)}

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

项目代码解析

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

#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. 最小值函数

double min_3(double g, double b, double r) {
    return std::min({ g, b, r });
}

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

3. 去雾函数

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计算

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分数

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. 视频捕捉和处理

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左右。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/967135.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java 大视界 -- Java 大数据在智能政务中的应用与服务创新(78)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

【DeepSeek】DeepSeek概述 | 本地部署deepseek

目录 1 -> 概述 1.1 -> 技术特点 1.2 -> 模型发布 1.3 -> 应用领域 1.4 -> 优势与影响 2 -> 本地部署 2.1 -> 安装ollama 2.2 -> 部署deepseek-r1模型 1 -> 概述 DeepSeek是由中国的深度求索公司开发的一系列人工智能模型&#xff0c;以其…

数据库,数据表的增删改查操作

一.数据库的基本操作 &#xff08;1&#xff09;创建数据库 创建数据库就是在数据库系统中划分一块存储数据的空间&#xff0c;方便数据的分配、放置和管理。在MySQL中使用CREATE DATABASE命令创建数据库&#xff0c;语法格式如下: CREATE DATABASE数据库名称; 注&#xff1a…

书籍《新能源汽车动力电池安全管理算法设计》和《动力电池管理系统核心算法》脑图笔记

目录 一、阅读背景二、《新能源汽车动力电池安全管理算法设计》脑图笔记三、《动力电池管理系统核心算法》脑图笔记四、后记参考学习 一、阅读背景 如今身处新能源动力电池行业&#xff0c;欲对动力电池相关算法做一些了解&#xff0c;通过查找相关电子书app&#xff0c;最后找…

激活函数篇 03 —— ReLU、LeakyReLU、RandomizedLeakkyReLU、PReLU、ELU

本篇文章收录于专栏【机器学习】 以下是激活函数系列的相关的所有内容: 一文搞懂激活函数在神经网络中的关键作用 逻辑回归&#xff1a;Sigmoid函数在分类问题中的应用 整流线性单位函数&#xff08;Rectified Linear Unit, ReLU&#xff09;&#xff0c;又称修正线性单元&a…

Python Pandas(3):DataFrame

1 介绍 DataFrame 是 Pandas 中的另一个核心数据结构&#xff0c;类似于一个二维的表格或数据库中的数据表。它含有一组有序的列&#xff0c;每列可以是不同的值类型&#xff08;数值、字符串、布尔型值&#xff09;。DataFrame 既有行索引也有列索引&#xff0c;它可以被看做由…

【C++高并发服务器WebServer】-14:Select详解及实现

本文目录 一、BIO模型二、非阻塞NIO忙轮询三、IO多路复用四、Select()多路复用实现 明确一下IO多路复用的概念&#xff1a;IO多路复用能够使得程序同时监听多个文件描述符&#xff08;文件描述符fd对应的是内核读写缓冲区&#xff09;&#xff0c;能够提升程序的性能。 Linux下…

算法兵法全略(译文)

目录 始计篇 谋攻篇 军形篇 兵势篇 虚实篇 军争篇 九变篇 行军篇 地形篇 九地篇 火攻篇 用间篇 始计篇 算法&#xff0c;在当今时代&#xff0c;犹如国家关键的战略武器&#xff0c;也是处理各类事务的核心枢纽。算法的世界神秘且变化万千&#xff0c;不够贤能聪慧…

瑞芯微 Rockchip 系列 RK3588 主流深度学习框架模型转成 rknn 模型教程

前言 在瑞芯微 Rockchip 芯片上进行 NPU 推理&#xff0c;需要先将模型文件转换成 rknn 模型文件&#xff0c;才能执行各种推理任务。本文将介绍如何安装各种工具&#xff0c;并最终实现将各种深度学习框架的模型文件转换成 rknn 文件。 本教程不仅适合 RK3588 平台&#xff…

STM32的HAL库开发---高级定时器---互补输出带死区实验

一、互补输出简介 互补输出&#xff1a;OCx输出高电平&#xff0c;则互补通道OCxN输出低电平。OCx输出低电平&#xff0c;则互补通道OCxN输出高电平。 带死区控制的互补输出&#xff1a;OCx输出高电平时&#xff0c;则互补通道OCxN过一会再输出输出低电平。这个时间里输出的电…

git提交到GitHub问题汇总

1.main->master git默认主分支是maser&#xff0c;如果是按照这个分支名push&#xff0c;GitHub会出现两个branch&#xff0c;与预期不符 解决方案&#xff1a;更改原始主分支名为main git config --global init.defaultBranch main2.git&#xff1a;OpenSSL SSL_read: SS…

【图片合并转换PDF】如何将每个文件夹下的图片转化成PDF并合并成一个文件?下面基于C++的方式教你实现

医院在为患者进行诊断和治疗过程中&#xff0c;会产生大量的医学影像图片&#xff0c;如 X 光片、CT 扫描图、MRI 图像等。这些图片通常会按照检查时间或者检查项目存放在不同的文件夹中。为了方便医生查阅和患者病历的长期保存&#xff0c;需要将每个患者文件夹下的图片合并成…

vite + axios 代理不起作用 404 无效

vite axios 代理不起作用 先看官方示例 export default defineConfig({server: {proxy: {// 字符串简写写法/foo: http://localhost:4567,// 选项写法/api: {target: http://jsonplaceholder.typicode.com,changeOrigin: true,rewrite: (path) > path.replace(/^\/api/, )…

Spring Boot接入Deep Seek的API

1&#xff0c;首先进入deepseek的官网&#xff1a;DeepSeek | 深度求索&#xff0c;单击右上角的API开放平台。 2&#xff0c;单击API keys&#xff0c;创建一个API&#xff0c;创建完成务必复制&#xff01;&#xff01;不然关掉之后会看不看api key&#xff01;&#xff01;&…

Windows 系统下使用 Ollama 离线部署 DeepSeek - R1 模型指南

引言 随着人工智能技术的飞速发展&#xff0c;各类大语言模型层出不穷。DeepSeek - R1 凭借其出色的语言理解和生成能力&#xff0c;受到了广泛关注。而 Ollama 作为一款便捷的模型管理和部署工具&#xff0c;能够帮助我们轻松地在本地环境中部署和使用模型。本文将详细介绍如…

Python+Flask搭建属于自己的B站,管理自己电脑里面的视频文件。支持对文件分类、重命名、删除等操作。

适用场景 个人用户:管理本地图片和视频文件,快速查找和分类。 团队协作:共享文件分类标签,提升团队文件管理效率。 教育机构:用于教学资源管理,方便教师和学生查找资料。 企业应用:作为内部文件管理系统,支持批量操作和分类管理。 功能介绍 文件浏览与播放:用户可以浏…

深入Linux系列之进程地址空间

深入Linux系列之进程地址空间 1.引入 那么在之前的学习中&#xff0c;我们知道我们创建一个子进程的话&#xff0c;我们可以在代码层面调用fork函数来创建我们的子进程&#xff0c;那么fork函数的返回值根据我们当前所处进程的上下文是返回不同的值&#xff0c;它在父进程中返…

前端 CSS 动态设置样式::class、:style 等技巧详解

一、:class 动态绑定类名 v-bind:class&#xff08;缩写为 :class&#xff09;可以动态地绑定一个或多个 CSS 类名。 1. 对象语法 通过对象语法&#xff0c;可以根据条件动态切换类名。 <template><div :class"{ greenText: isActive, red-text: hasError }&…

ArgoCD实战指南:GitOps驱动下的Kubernetes自动化部署与Helm/Kustomize集成

摘要 ArgoCD 是一种 GitOps 持续交付工具,专为 Kubernetes 设计。它能够自动同步 Git 仓库中的声明性配置,并将其应用到 Kubernetes 集群中。本文将介绍 ArgoCD 的架构、安装步骤,以及如何结合 Helm 和 Kustomize 进行 Kubernetes 自动化部署。 引言 为什么选择 ArgoCD?…

go语言文件和目录

打开和关闭文件 os.Open()函数能够打开一个文件&#xff0c;返回一个*File 和一个 err。操作完成文件对象以后一定要记得关闭文件。 package mainimport ("fmt""os" )func main() {// 只读方式打开当前目录下的 main.go 文件file, err : os.Open(".…