OpenCV图像增强(二)——Retinex图像增强

2023-11-03

前言

1.Retinex图像增强是一种高动态范围图像的新色调映射技术。而基础理论是,物体的颜色是由物体对长波(红色)、中波(绿色)、短波(蓝色)光线的反射能力来决定的,而不是由反射光强度的绝对值来决定的,物体的色彩不受光照非均匀性的影响,具有一致性,即retinex是以色感一致性(颜色恒常性)为基础的。不同于传统的线性、非线性的只能增强图像某一类特征的方法,Retinex可以在动态范围压缩、边缘增强和颜色恒常三个方面达到平衡,因此可以对各种不同类型的图像进行自适应的增强。
2.Retinex图像增强包括两个步骤,全局适应和人类视觉系统的局部自适应。在局部自适应过程中,这里使用引导滤波器代替原本的高斯滤波器以减少晕圈伪影。为了保证良好的再现和动态范围压缩,使用基于场景的亮度值的对比度增强因子。此外,引入自适应非线性偏移来处理对数函数的非线性强度。
3.导向滤波作为一种保边滤波,可以运用在很多场合,比如美颜,去雾。

代码实现

void ALTMRetinex(const Mat& src, Mat &dst, bool LocalAdaptation = false, bool ContrastCorrect = true)
{

    Mat temp, src_gray;

    src.convertTo(temp, CV_32FC3);
    //灰度图
    cvtColor(temp, src_gray, CV_BGR2GRAY);

    double LwMax;
    //得到最大值
    minMaxLoc(src_gray, NULL, &LwMax);

    Mat Lw_;
    const int num = src.rows * src.cols;
    //计算每个数组元素绝对值的自然对数
    cv::log(src_gray + 1e-3f, Lw_);
    //矩阵自然指数
    float LwAver = exp(cv::sum(Lw_)[0] / num);

    Mat Lg;
    log(src_gray / LwAver + 1.f, Lg);
    //矩阵除法
    cv::divide(Lg, log(LwMax / LwAver + 1.f), Lg);

    //局部自适应
    Mat Lout;
    if (LocalAdaptation)
    {
        int kernelSize = floor(std::max(3, std::max(src.rows / 100, src.cols / 100)));
        Mat Lp, kernel = cv::getStructuringElement(MORPH_RECT, Size(kernelSize, kernelSize));
        cv::dilate(Lg, Lp, kernel);
        Mat Hg = guidedFilter(Lg, Lp, 10, 0.01f);

        double eta = 36;
        double LgMax;
        cv::minMaxLoc(Lg, NULL, &LgMax);
        Mat alpha = 1.0f + Lg * (eta / LgMax);

        Mat Lg_;
        cv::log(Lg + 1e-3f, Lg_);
        float LgAver = exp(cv::sum(Lg_)[0] / num);
        float lambda = 10;
        float beta = lambda * LgAver;

        cv::log(Lg / Hg + beta, Lout);
        cv::multiply(alpha, Lout, Lout);
        cv::normalize(Lout, Lout, 0, 255, NORM_MINMAX);
    }
    else
    {
        cv::normalize(Lg, Lout, 0, 255, NORM_MINMAX);
    }

    Mat gain(src.rows , src.cols, CV_32F);
    for (int i = 0; i < src.rows; i++)
    {
        for (int j = 0; j < src.cols; j++)
        {
            float x = src_gray.at<float>(i, j);
            float y = Lout.at<float>(i, j);
            if (0 == x) gain.at<float>(i, j) = y;
            else gain.at<float>(i, j) = y / x;
        }
    }

    Mat bgr[3];
    cv::split(temp, bgr);
    if (ContrastCorrect)
    {
        // 校正图像对比度
        bgr[0] = (gain.mul(bgr[0] + src_gray) + bgr[0] - src_gray) *0.5f;
        bgr[1] = (gain.mul(bgr[1] + src_gray) + bgr[1] - src_gray) *0.5f;
        bgr[2] = (gain.mul(bgr[2] + src_gray) + bgr[2] - src_gray) *0.5f;
    }
    else
    {
        cv::multiply(bgr[0], gain, bgr[0]);
        cv::multiply(bgr[1], gain, bgr[1]);
        cv::multiply(bgr[2], gain, bgr[2]);
    }

    cv::merge(bgr, 3, dst);
    dst.convertTo(dst, CV_8UC3);
}

 //导向滤波器
 Mat guidedFilter(cv::Mat& I, cv::Mat& p, int r, float eps)
 {
     /*
     × GUIDEDFILTER   O(N) time implementation of guided filter.
     ×
     ×   - guidance image: I (should be a gray-scale/single channel image)
     ×   - filtering input image: p (should be a gray-scale/single channel image)
     ×   - local window radius: r
     ×   - regularization parameter: eps
     */

     cv::Mat _I;
     I.convertTo(_I, CV_32FC1);
     I = _I;

     cv::Mat _p;
     p.convertTo(_p, CV_32FC1);
     p = _p;

     //因为opencv自带的boxFilter()中的Size,比如9x9,我们说半径为4
     r = 2 * r + 1;

     //mean_I = boxfilter(I, r) ./ N;
     cv::Mat mean_I;
     cv::boxFilter(I, mean_I, CV_32FC1, cv::Size(r, r));

     //mean_p = boxfilter(p, r) ./ N;
     cv::Mat mean_p;
     cv::boxFilter(p, mean_p, CV_32FC1, cv::Size(r, r));

     //mean_Ip = boxfilter(I.*p, r) ./ N;
     cv::Mat mean_Ip;
     cv::boxFilter(I.mul(p), mean_Ip, CV_32FC1, cv::Size(r, r));

     //cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.
     cv::Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);

     //mean_II = boxfilter(I.*I, r) ./ N;
     cv::Mat mean_II;
     cv::boxFilter(I.mul(I), mean_II, CV_32FC1, cv::Size(r, r));

     //var_I = mean_II - mean_I .* mean_I;
     cv::Mat var_I = mean_II - mean_I.mul(mean_I);

     //a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;
     cv::Mat a = cov_Ip / (var_I + eps);

     //b = mean_p - a .* mean_I; % Eqn. (6) in the paper;
     cv::Mat b = mean_p - a.mul(mean_I);

     //mean_a = boxfilter(a, r) ./ N;
     cv::Mat mean_a;
     cv::boxFilter(a, mean_a, CV_32FC1, cv::Size(r, r));

     //mean_b = boxfilter(b, r) ./ N;
     cv::Mat mean_b;
     cv::boxFilter(b, mean_b, CV_32FC1, cv::Size(r, r));

     //q = mean_a .* I + mean_b; % Eqn. (8) in the paper;
     cv::Mat q = mean_a.mul(I) + mean_b;

     return q;
 }

运行结果
在这里插入图片描述
在这里插入图片描述

结语

我这里使用的库OpenCV版本是3.30,关于opencv学习,有兴趣的看我之前发的博客,可以加之前博客后面给的兴趣群。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV图像增强(二)——Retinex图像增强 的相关文章

  • 如何在Python中使用tcp套接字发送和接收网络摄像头流?

    我正在尝试重新创建这个项目 https github com hamuchiwa AutoRCCar 我拥有的是服务器 我的电脑 和客户端 我的树莓派 我所做的与原始项目不同的是我尝试使用一个简单的网络摄像头而不是树莓派摄像头将图像从我的
  • 提高 pytesseract 从图像中正确识别文本的能力

    我正在尝试使用读取验证码pytesseract模块 大多数时候它都能提供准确的文本 但并非总是如此 这是读取图像 操作图像以及从图像中提取文本的代码 import cv2 import numpy as np import pytesser
  • 如何删除树莓派的相机预览

    我在我的 raspberryPi 上安装了 SimpleCv 并安装了用于使用相机板的驱动程序 uv4l 驱动程序 现在我想使用它 当我在 simpleCV shell Camera 0 getImage save foo jpg 上键入时
  • 如何设置K-means openCV c++的初始中心

    我正在尝试使用 OpenCv 和 Kmeans 对图像进行分割 我刚刚实现的代码如下 include opencv2 objdetect objdetect hpp include opencv2 highgui highgui hpp i
  • OpenCV 仅围绕大轮廓绘制矩形?

    第一次发帖 希望我以正确的方式放置代码 我正在尝试检测和计算视频中的车辆 因此 如果您查看下面的代码 我会在阈值处理和膨胀后找到图像的轮廓 然后我使用 drawContours 和矩形在检测到的轮廓周围绘制一个框 我试图在 drawCont
  • opencv形态扩张滤波器作为最大滤波器

    就像中值滤波器的定义一样 我可以将 最大滤波器 定义为局部窗口 例如dst x y max 3x3 局部窗口像素 但我在opencv中找不到这样的过滤器 最接近的是 dilate 函数 然后我使用 dilate 函数的默认配置 但结果不正确
  • 如何去除给定图像中的噪声,使 ocr 输出完美?

    我已经对这个孟加拉文本图像进行了大津阈值处理 并使用 tesseract 进行 OCR 但输出非常糟糕 我应该应用什么预处理来消除噪音 我也想校正图像 因为它有轻微的倾斜 我的代码如下 import tesserocr from PIL i
  • OpenCV IP 相机应用程序崩溃 [h264 @ 0xxxxx] 访问单元中缺少图片

    我在 cpp 中有一个 opencv 应用程序 它使用 opencv 的简单结构捕获视频流并将其保存到视频文件中 它与我的网络摄像头完美配合 但是 当我运行它从 IP 摄像机捕获流时 它可能会在大约十秒后崩溃 我的编译命令是 g O3 IP
  • OpenCV 错误:connectedComponents_sub1 中断言失败 (L.channels() == 1 && I.channels() == 1) [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我在 OpenCV python 中遇到以下错误 并用 google 搜索了很多 但无法解决 如果有人能为我提供一些线索
  • 使用 OpenCV 改进特征点匹配

    我想匹配立体图像中的特征点 我已经用不同的算法找到并提取了特征点 现在我需要一个良好的匹配 在本例中 我使用 FAST 算法进行检测和提取 BruteForceMatcher用于匹配特征点 匹配代码 vector lt vector
  • 从包含带边框的表格的图像中提取表格结构

    我正在尝试提取下表中的单元格位置 应用自适应阈值处理后 我能够获得细胞位置周围的轮廓 并且 HoughLines 获得垂直和水平结构元素 这是我的代码 img cv2 imread os path join img path file im
  • opencv人脸检测示例

    当我在设备上运行应用程序时 应用程序崩溃并显示以下按摩 java lang UnsatisfiedLinkError 无法加载 detector based tracker findLibrary 返回 null 我正在使用 OpenCV
  • 如何使用 opencv python 计算乐高积木上的孔数?

    我正在开发我的 python 项目 我需要计算每个乐高积木组件中有多少个孔 我将从输入 json 文件中获取有关需要计算哪个程序集的信息 如下所示 img 001 red 0 blue 2 white 1 grey 1 yellow 1 r
  • 如何绘制更大的边界框和仅裁剪边界框文本 Python Opencv

    我正在使用 easyocr 来检测图像中的文本 该方法给出输出边界框 输入图像如下所示 Image 1 Image 2 使用下面的代码获得输出图像 But I want to draw a Single Bigger bounding bo
  • 如何使用 colorchecker 在 opencv 中进行颜色校准?

    我有数码相机获取的色彩检查器图像 我如何使用它来使用 opencv 校准图像 按照以下颜色检查器图像操作 您是想问如何进行颜色校准或如何使用 OpenCV 进行校准 为了进行颜色校准 您可以使用校准板的最后一行 灰色调 以下是您应该逐步进行
  • 同时从多个流中捕获、最佳方法以及如何减少 CPU 使用率

    我目前正在编写一个应用程序 该应用程序将捕获大量 RTSP 流 在我的例子中为 12 个 并将其显示在 QT 小部件上 当我超过大约 6 7 个流时 问题就会出现 CPU 使用率激增并且出现明显的卡顿 我认为它不是 QT 绘制函数的原因是因
  • 二值图像中骨架上两点之间的最短路径

    我有一个二进制图像 其中包含图像的一个像素宽度骨架 您可能基本上知道 在这个二值图像中 我在骨架上有 1 在其他地方有 0 如何找到骨架上两个非零元素之间的最短距离 路径也应该在骨架本身上 我想使用 A star 算法的 C 实现 我找到了
  • Opencv Mat内存管理

    内存管理对于图像类至关重要 在opencv中 图像类是cv Mat 它有一个微妙的内存管理方案 假设我已经有了自己的图像类SelfImage class SelfImage public int width int height unsig
  • OpenCV:如何从网络摄像头获取原始 YUY2 图像?

    你知道如何获得吗raw YUY2来自网络摄像头的图像 使用 OpenCV DirectShow 无 VFW http opencv willowgarage com wiki CameraCapture http opencv willow
  • 在 Visual Studio C++ 2008 中包含 dll

    有没有办法将 dll 包含在项目中 这样我就不必在编译后将这些 dll 与可执行文件放在同一文件夹中 这样我就可以用它们编译我的项目 这是否有可能 如果是 有人可以指导我 我的项目是一个 opencv 项目 有很多 dll 我必须包含在文件

随机推荐

  • 快排、二路归并疑难杂症

    蒟蒻小 复习机试 记录一些疑点和注意点 细节见代码注释 快排 快排中的边界条件判断需保证i
  • SiteMesh 过滤不装饰的页面

    意思也即是这个页面不被sitemesh过滤器装饰 我们可新建立一个文件夹 将不被装饰的页面放在里面 下面我们操作两个配置文件即可 1 在sitemesh xml里需要有excludes元素 lt sitemesh gt lt propert
  • 一次元数据空间内存溢出的排查记录

    在应用中 我们使用的 SpringData ES的 ElasticsearchRestTemplate来做查询 使用方式不对 导致每次ES查询时都新实例化了一个查询对象 会加载相关类到元数据中 最终长时间运行后元数据出现内存溢出 问题原因
  • 重要前端面试题,来自一个2022年面试大牛(下)

    五 React 1 react 函数组件和 class 组件区别 类组件视图是怎么更新的呢 首先第一次渲染的时候 会创建一个类的实例 之后在更新的时候 仅仅按照生命周期流程调用render 实例不会变 而函数式组件每次渲染更新都会重新执行调
  • 前端例程20220818:边框跑马霓虹灯效按钮

    演示 原理 按钮使用阴影实现外发光效果 按钮设置倒影效果 使用四个块元素以按钮为基础绝对定位到上下左右四边作为边框 通过给边框元素设置动画 并设置动画时间差以实现边框跑马效果 代码
  • C# 火山引擎 语音合成 HTTP接口调用方法

    官方没有提供C demo 且文档有可能看不懂 这里记录下调用方法 C 代码 WebClient wc new WebClient string appid 应用的APPID string uid 账号的uid string voice ot
  • 蓝桥杯 Python 组省赛夺奖班-3.1 数组

    一 区间修改 区间求和 题目 思路 可以使用暴力法进行模拟但是不能全过 听讲解是要用线段树 唉不会的知识太多了 等学了回来补坑 代码 暴力法 n m map int input split a list map int input spli
  • SSL_connect returned=1 errno=0 state=error: certificate verify failed

    起因 起因是这样的 我昨天使用 gem 安装 irb 的时候出现了下面这个错误 root master gem install irb ERROR Could not find a valid gem irb gt 0 here is wh
  • STM32之IIC

    IIC协议 IIC全称Inter Integrated Circuit 集成电路总线 由PHILIPS公司在80年代开发的两线式串行总线 用于连接微控制器及其外围设备 IIC属于半双工同步通信方式 IIC构成 IIC串行总线有两根信号线 一
  • 【VUE】vue3+vite中process.env的配置方法

    问题详情 在request js中 使用process env BASE API 需要对请求路径进行全局配置 创建axios实例 const service axios create baseURL process env BASE API
  • 生成新SSH密钥并添加到ssh-agent

    生成命令 ssh keygen t ed25519 C your email example com 回车3次后生成 查看公钥 cat ssh id ed25519 pub 进入ssh页面 https github com settings
  • 16.python的文件处理

    应用程序运行过程中产生的数据最先都是存放于内存中的 若想永久保存下来 必须要保存于硬盘中 应用程序若想操作硬件必须通过操作系统 而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念 用户或应用程序对文件的操作 就是向操作系统发起调用 然后由
  • vue 富文本编辑器使用

    环境 在vue TS 中使用富文本编辑器 markdown文本编辑器更加适合开发者使用 普通用户更适合类似word的使用方式 所见即所得 推荐使用的富文本编辑器 ckeditor5 内置插件和扩展性非常好 quill medium edit
  • 黑盒测试、白盒测试、灰盒测试

    1 黑盒测试 黑盒测试也称功能测试 它是通过测试来检测每个功能是否都能正常使用 在测试中 把程序看作一个不能打开的黑盒子 在完全不考虑程序内部结构和内部特性的情况下 在程序接口进行测试 它只检查程序功能是否按照需求规格说明书的规定正常使用
  • uniapp中使用swiper无法触发触底生命周期onReachBottom

    使用swiper导致onReachBottom生命周期不会触发 解决办法 使用scroll view的scrolltolower方法 具体使用
  • 【单片机毕业设计】【mcuclub-dz-079】基于单片机的火灾检测控制系统设计

    最近设计了一个项目基于单片机的火灾检测控制系统设计 与大家分享一下 一 基本介绍 项目名 火灾检测 项目编号 mcuclub dz 079 单片机 STC89C52 功能简介 1 通过MQ 7检测CO值 当CO值大于设置最大值 进行声光报警
  • NMOS管和PMOS管使用区别之一

    使用的位置 NMOS管在电路中常做下管使用 PMOS管在电路中常做上管使用 VCC叫上 GND叫下 NMOS管在电路中常做下管使用 S端接GND D端接负载 负载再接VCC PMOS管在电路中常做上管使用 S端接VCC D端接负载 负载再接
  • 纯手工gcc 编译android native Cpp代码

    纯手工gcc 编译android native Cpp代码 api level 19 32位 编译成功 api level 19 home charlie android tool android ndk r10e toolchains a
  • MySQL-MVCC原理以及数据库锁实战

    多个事务并发对同一批数据进行增删改查操作时 可能会导致脏写 脏读 不可重复读 幻读问题 MySQL为解决这些问题 设计了事务隔离级别 锁机制 MVCC多版本并发控制隔离机制来解决这些问题 锁与事务隔离级别 事务隔离级别 读未提交 Read
  • OpenCV图像增强(二)——Retinex图像增强

    前言 1 Retinex图像增强是一种高动态范围图像的新色调映射技术 而基础理论是 物体的颜色是由物体对长波 红色 中波 绿色 短波 蓝色 光线的反射能力来决定的 而不是由反射光强度的绝对值来决定的 物体的色彩不受光照非均匀性的影响 具有一