图像处理之Retinex算法(C++)

图像处理之Retinex算法(C++)


文章目录

  • 图像处理之Retinex算法(C++)
  • 前言
  • 一、单尺度Retinex(SSR)
    • 1.原理
    • 2.代码实现
    • 3.结果展示
  • 二、多尺度Retinex(MSR)
    • 1.原理
    • 2.代码实现
    • 3.结果展示
  • 三、带色彩恢复的多尺度Retinex(MSRCR)
    • 1.原理
    • 2.代码实现
    • 3.结果展示
  • 总结


前言

Retinex 理论的基本思想就是光照强度决定了原始图像中所有像素点的动态范围大小,而原始图像的固有属性则是由物体自身的反射系数决定,即假设反射图像和光照图像相乘为原始图像。所以 Retinex 的思路即是去除光照的影响,保留住物体的固有属性。
Retinex模型示意图
如图所示,假设观察者处成像的图像为I(x,y),可以通过下式表达:
成像公式1
参数解释:
I(x,y)–源图像;
L(x,y)–表示光照分量;
R(x,y)–表示物体本身固有性质的反射分量。
对公式两端取对数,公式为:
公式2
公式3
上式即为Retinex理论处理的基本过程。
Retinex算法处理的基本过程如下:
Retinex理论处理的基本过程
流程图解读:图像I(x,y)经过Log变换转换成i(x,y),然后对图像I(x,y)进行亮度图像估计,在对估计的亮度分量进行Log变换得到l(x,y),二者相减得到物体反射分量的Log变换r(x,y),再进行Log变换的反变换Exp,即得到R(x,y)。此处亮度图像估计即通过高斯滤波或者引导滤波对图像滤波
参考资料:Retinex理论


一、单尺度Retinex(SSR)

1.原理

单尺度 Retinex 算法的处理过程非常拟合人眼的视觉成像过程,该算法的基本思路是:先构建高斯环绕函数,然后利用高斯环绕函数分别对图像的三个色彩通道 (R 、G 和 B) 进行滤波,则滤波后的图像就是我们所估计的光照分量,接着再在对数域中对原始图像和光照分量进行相减得到反射分量作为输出结果图像。该算法能压缩图像的动态范围、一定程度上的保持图像的颜色和细节的增强。改进:将高斯环绕函数对三个色彩通道滤波,改为使用引导滤波对三个彩色通道滤波。
公式3
参数解释:
Ii(x,y)–原始图像;
Li(x,y)–表示光照分量;
Ri(x,y)–表示物体本身固有性质的反射分量;
G(x,y)–高斯环绕函数;
Ii(x,y)G(x,y)–对原始图像使用高斯核进行卷积运算。
SSR算法中标准差σ一般取80-100。

2.代码实现

#include <iostream>
#include <opencv.hpp>
using namespace std;/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param double sigma   高斯核的标准差
* @breif 单尺度Retinex图像处理
*/
cv::Mat single_scale_retinex(const cv::Mat& src,double sigma)
{cv::Mat gaussImg, log_src(src.size(),CV_32F), log_gaussImg(src.size(), CV_32F);cv::Mat difference(src.size(), CV_32F);cv::Mat dst(src.size(), CV_32F);// 对输入图像进行高斯模糊处理cv::GaussianBlur(src, gaussImg, cv::Size(0,0), sigma);// 对模糊后的图像和原图像分别进行对数运算,得到两个对数图像// 差分操作前确保两个矩阵类型和尺寸相同// 对差分后的图像进行指数运算gaussImg.convertTo(gaussImg, CV_32F);for(int i=0;i<gaussImg.rows;i++)for (int j = 0; j < gaussImg.cols; j++){log_gaussImg.at<float>(i, j) = log(gaussImg.at<float>(i, j) + 1);log_src.at<float>(i, j) = log(src.at<uchar>(i, j) + 1);difference.at<float>(i, j) = log_src.at<float>(i, j) - log_gaussImg.at<float>(i, j);//dst.at<float>(i, j) = exp(difference.at<float>(i, j));}// 归一化到0-255范围内(疑问:此处对差分图像归一化反而图像显得正常,参考https://blog.csdn.net/TmacDu/article/details/103499795博主也是这样实现)cv::normalize(difference, dst, 0, 255, cv::NORM_MINMAX, CV_8U);return dst;
}/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param double sigma   高斯核的标准差
* @breif 单尺度Retinex图像处理
*/
void retinex_process(const cv::Mat& src, cv::Mat& dst, double sigma)
{std::vector<cv::Mat> channels;std::vector<cv::Mat> channels_dst;cv::split(src, channels);for (int i = 0; i < channels.size(); i++){channels_dst.push_back(single_scale_retinex(channels[i], sigma));}cv::merge(channels_dst, dst);
}int main()
{// 读取图片string filepath = "F://work_study//algorithm_demo//retinex_test1.jpg";cv::Mat src = cv::imread(filepath);if (src.empty()){return -1;}cv::Mat dst(src.size(),CV_8UC3,cv::Scalar(0,0,0));//执行单尺度的Retinex算法retinex_process(src, dst,80);cv::imshow("dst.jpg", dst);cv::waitKey(0);return 0;
}

3.结果展示

原图
结果

二、多尺度Retinex(MSR)

1.原理

SSR算法在动态范围压缩和色调恢复的两种效果中,只能以牺牲一种功能为代价来改进另一个,因此Jobson等一批研究者们针对单尺度Retinex模型中存在的不足,提出了将不同尺度下的增强结果线性地组合在一起,充分将局部信息和整体信息考虑进去的多尺度Retinex算法。这种算法的主要思想就是结合几种不同的尺度的中心围绕函数通过加权平均以后来估计光照分量。MSR算法可以产生同时拥有良好动态范围压缩、色彩稳定性以及良好色调恢复的单一输出图像。MSR算法的公式为:
MSR
参数解释:
N–表示尺度的个数,即高斯滤波的标准差的个数,一般将N的取值为3,用三个不同尺度的高斯滤波器对原始图像进行滤波,尺度的比例建议为15:80:250。
wk–经过实验验证,发现w1=w2=w3=1/3时,适用于大量的低照度图像,运算简单。
Fk(x,y)–在第k个尺度上的高斯滤波函数。

参考资料:MSR资料

2.代码实现

#include <iostream>
#include <opencv.hpp>
using namespace std;/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param double sigma   高斯核的标准差
* @breif 单尺度Retinex图像处理
*/
cv::Mat single_scale_retinex(const cv::Mat& src,double sigma)
{cv::Mat gaussImg, log_src(src.size(),CV_32F), log_gaussImg(src.size(), CV_32F);cv::Mat difference(src.size(), CV_32F);cv::Mat dst(src.size(), CV_32F);// 对输入图像进行高斯模糊处理cv::GaussianBlur(src, gaussImg, cv::Size(0,0), sigma);// 对模糊后的图像和原图像分别进行对数运算,得到两个对数图像// 差分操作前确保两个矩阵类型和尺寸相同// 对差分后的图像进行指数运算gaussImg.convertTo(gaussImg, CV_32F);for(int i=0;i<gaussImg.rows;i++)for (int j = 0; j < gaussImg.cols; j++){log_gaussImg.at<float>(i, j) = log(gaussImg.at<float>(i, j) + 1);log_src.at<float>(i, j) = log(src.at<uchar>(i, j) + 1);difference.at<float>(i, j) = log_src.at<float>(i, j) - log_gaussImg.at<float>(i, j);//dst.at<float>(i, j) = exp(difference.at<float>(i, j));}// 归一化到0-255范围内(疑问:此处对差分图像归一化反而图像显得正常,参考https://blog.csdn.net/TmacDu/article/details/103499795博主也是这样实现)cv::normalize(difference, dst, 0, 255, cv::NORM_MINMAX, CV_8U);return dst;
}/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param double sigma   高斯核的标准差
* @breif 单尺度Retinex图像处理
*/
void retinex_process(const cv::Mat& src, cv::Mat& dst, double sigma)
{std::vector<cv::Mat> channels;std::vector<cv::Mat> channels_dst;cv::split(src, channels);for (int i = 0; i < channels.size(); i++){channels_dst.push_back(single_scale_retinex(channels[i], sigma));}cv::merge(channels_dst, dst);
}/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param std::vector<double> sigma   高斯核的标准差
* @param std::vector<double> w   权重系数
* @breif 多尺度Retinex图像处理
*/
void multi_retinex_process(const cv::Mat& src, cv::Mat& dst, std::vector<double>& sigma, std::vector<double>& w)
{std::vector<cv::Mat> temp(sigma.size());for (int i = 0; i < sigma.size(); i++){retinex_process(src,temp[i],sigma[i]);}for (int i = 0; i < w.size(); i++){dst += w[i] * temp[i];}
}int main()
{// 读取图片string filepath = "F://work_study//algorithm_demo//retinex_test3.jpg";cv::Mat src = cv::imread(filepath);if (src.empty()){return -1;}cv::Mat dst(src.size(),CV_8UC3,cv::Scalar(0,0,0));//高斯滤波器的尺度std::vector<double> sigma={15,80,250};//各个尺度下的SSR的权重系数std::vector<double> w(3, 1 / 3.0);//执行多尺度的Retinex算法multi_retinex_process(src, dst,sigma,w);cv::imwrite("dst.jpg", dst);cv::waitKey(0);return 0;
}

3.结果展示

MSR结果

三、带色彩恢复的多尺度Retinex(MSRCR)

1.原理

在上图中,我们可以看出无论是单尺度还是多尺度Retinex图像增强后都会发生图像色彩失真,原因是R、G、B三通道的像素值比例发生改变,针对这个现象,Jobson和Rahman等人又一次提出带颜色恢复的多尺度 Retinex(MSRCR)。该算法可以将 MSR 得到的结果按照一定的比例进行调整以求恢复原来的比例数值,具体是通过引入了颜色恢复因子 C ,其公式如下:颜色恢复因子公式
参数解释:
β–增益常数,经验参数为46。
α–调节因子,经验参数为125。
Ci(x,y)–第i个彩色通道的色彩恢复函数(CRF),用来调节三个通道颜色在图像中所占的比例。
MSRCR可以提供必要的颜色恢复,从而把相对较暗区域而无法观察到的信息图像细节展现出来,消除了MSR输出中明显的颜色失真和灰色区域。可以为大多数图像提供良好的效果。
MSRCR公式
参数解释:
t–偏移量系数;
G–增益系数;

2.代码实现

#include <iostream>
#include <opencv.hpp>
using namespace std;
using namespace cv;
/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param double sigma   高斯核的标准差
* @breif 单尺度Retinex图像处理
*/
cv::Mat single_scale_retinex(const cv::Mat& src, double sigma)
{cv::Mat gaussImg, log_src(src.size(), CV_32F), log_gaussImg(src.size(), CV_32F);cv::Mat difference(src.size(), CV_32F);cv::Mat dst(src.size(), CV_32F);// 对输入图像进行高斯模糊处理cv::GaussianBlur(src, gaussImg, cv::Size(0, 0), sigma);// 对模糊后的图像和原图像分别进行对数运算,得到两个对数图像// 差分操作前确保两个矩阵类型和尺寸相同// 对差分后的图像进行指数运算gaussImg.convertTo(gaussImg, CV_32F);for (int i = 0; i < gaussImg.rows; i++)for (int j = 0; j < gaussImg.cols; j++){log_gaussImg.at<float>(i, j) = log(gaussImg.at<float>(i, j) + 1);log_src.at<float>(i, j) = log(src.at<uchar>(i, j) + 1);difference.at<float>(i, j) = log_src.at<float>(i, j) - log_gaussImg.at<float>(i, j);//dst.at<float>(i, j) = exp(difference.at<float>(i, j));}// 归一化到0-255范围内(疑问:此处对差分图像归一化反而图像显得正常,参考https://blog.csdn.net/TmacDu/article/details/103499795博主也是这样实现)// 计算带颜色恢复的归一化放到最后,此处注释//cv::normalize(difference, dst, 0, 255, cv::NORM_MINMAX, CV_8U);return difference;
}/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param double sigma   高斯核的标准差
* @breif 单尺度Retinex图像处理
*/
void retinex_process(const cv::Mat& src, cv::Mat& dst, double sigma)
{std::vector<cv::Mat> channels;std::vector<cv::Mat> channels_dst;cv::split(src, channels);for (int i = 0; i < channels.size(); i++){channels_dst.push_back(single_scale_retinex(channels[i], sigma));}cv::merge(channels_dst, dst);
}/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param std::vector<double> sigma   高斯核的标准差
* @param std::vector<double> w   权重系数
* @breif 多尺度Retinex图像处理
*/
void multi_retinex_process(const cv::Mat& src, cv::Mat& dst, std::vector<double>& sigma, std::vector<double>& w)
{std::vector<cv::Mat> temp(sigma.size());for (int i = 0; i < sigma.size(); i++){retinex_process(src, temp[i], sigma[i]);}for (int i = 0; i < w.size(); i++){dst += w[i] * temp[i];}
}/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param double a   调节因子
* @param double b   增益常数
* @breif 计算颜色恢复因子
*/
void color_restoration(const cv::Mat& src, cv::Mat& dst, double a, double b)
{dst = cv::Mat(src.size(), CV_32FC3);for (int i = 0; i < src.rows; i++)for (int j = 0; j < src.cols; j++){int sum = src.at<cv::Vec3b>(i, j)[0] + src.at<cv::Vec3b>(i, j)[1] + src.at<cv::Vec3b>(i, j)[2];dst.at<cv::Vec3f>(i, j)[0] = b * (log(a * src.at<cv::Vec3b>(i, j)[0] + 1.0) - log(sum + 1.0));dst.at<cv::Vec3f>(i, j)[1] = b * (log(a * src.at<cv::Vec3b>(i, j)[1] + 1.0) - log(sum + 1.0));dst.at<cv::Vec3f>(i, j)[2] = b * (log(a * src.at<cv::Vec3b>(i, j)[2] + 1.0) - log(sum + 1.0));}
}/*
* @param cv::Mat src	输入图像
* @param cv::Mat& dst	输出图像
* @param std::vector<double> sigma   高斯核的标准差
* @param std::vector<double> w   权重系数
* @param double G   增益系数
* @param double t   偏移量系数
* @param double a   调节因子
* @param double b   增益常数
* @breif 带颜色恢复的多尺度Retinex图像处理
*/
void multi_retinex_color_restoration_process(const cv::Mat& src, cv::Mat& dst, std::vector<double>& sigma, std::vector<double>& w, double G, double t, double a, double b)
{dst.convertTo(dst, CV_32FC3);//计算多尺度Retinex图像cv::Mat multiRSImg(src.size(), CV_32FC3, cv::Scalar(0, 0, 0));multi_retinex_process(src, multiRSImg, sigma, w);//计算颜色恢复因子cv::Mat colorResImg(src.size(), CV_32FC3, cv::Scalar(0, 0, 0));color_restoration(src, colorResImg, a, b);//进行带颜色恢复的多尺度Retinex计算//关键点:saturate_cast<uchar>相当于对图像色彩做了保护for (int i = 0; i < src.rows; i++)for (int j = 0; j < src.cols; j++){dst.at<cv::Vec3f>(i, j)[0] = saturate_cast<uchar>(G * ((multiRSImg.at<cv::Vec3f>(i, j)[0] * colorResImg.at<cv::Vec3f>(i, j)[0]) + t));dst.at<cv::Vec3f>(i, j)[1] = saturate_cast<uchar>(G * ((multiRSImg.at<cv::Vec3f>(i, j)[1] * colorResImg.at<cv::Vec3f>(i, j)[1]) + t));dst.at<cv::Vec3f>(i, j)[2] = saturate_cast<uchar>(G * ((multiRSImg.at<cv::Vec3f>(i, j)[2] * colorResImg.at<cv::Vec3f>(i, j)[2]) + t));}cv::normalize(dst, dst, 0, 255, cv::NORM_MINMAX, CV_8UC3);
}int main()
{// 读取图片string filepath = "F://work_study//algorithm_demo//retinex_test4.jpg";cv::Mat src = cv::imread(filepath);if (src.empty()){return -1;}cv::Mat dst(src.size(), CV_8UC3, cv::Scalar(0, 0, 0));//高斯滤波器的尺度std::vector<double> sigma = { 15,80,250 };//各个尺度下的SSR的权重系数std::vector<double> w(3, 1 / 3.0);multi_retinex_color_restoration_process(src, dst, sigma, w, 5, 25, 125, 46);cv::imwrite("dst.jpg", dst);cv::waitKey(0);return 0;
}

3.结果展示

原图
MSRCR
参数比较多,不好调,大家可以阅读一位大佬写的文章,只需要调一个参数,文章链接:MSRCR
本文调节的参数在代码中,尝试很久,效果跟大佬文章效果类似。


总结

本文介绍了单尺度、多尺度、带颜色恢复的Retinex的算法原理和实现,使用C++和Opencv一步一步进行实现,代码结构简单清晰,便于阅读,但是效率有待提高,后续对代码进行重构,欢迎大家阅读和讨论代码中的不足。
本文代码均已在本地运行正确,有问题欢迎交流。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【01-机器学习入门:理解Scikit-learn与Python的关系】

文章目录 前言Python与机器学习Scikit-learn简介Scikit-learn与Python的关系使用Scikit-learn进行机器学习结语 前言 在当今的数据科学和人工智能领域&#xff0c;机器学习已经成为了一个不可或缺的组成部分。而对于那些刚刚踏入这一领域的新手来说&#xff0c;理解机器学习的基…

线性代数 --- 矩阵的对角化以及矩阵的n次幂

矩阵的对角化以及矩阵的n次幂 &#xff08;特征向量与特征值的应用&#xff09; 前言&#xff1a; 在上一篇文章中&#xff0c;我记录了学习矩阵的特征向量和特征值的学习笔记&#xff0c;所关注的是那些矩阵A作用于向量x后&#xff0c;方向不发生改变的x(仅有尺度的缩放)。线…

Xilinx 7系列中clock IP核通过AXI4-Lite接口实现动态重新配置

当选择了动态重配置&#xff08;Dynamic Reconfiguration&#xff09;选项时&#xff0c;AXI4-Lite接口将默认被选中用于重新配置时钟组件。动态重新配置可以通过AXI4-Lite接口实现了Clocking Wizard IP核的时钟组件MMCM/PLL的动态重新配置。 如果需要直接访问MMCM/PLL的DRP寄…

C++ 头文件/宏冲突问题解决?如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

SpringBoot + kotlin 协程小记

前言&#xff1a; Kotlin 协程是基于 Coroutine 实现的&#xff0c;其设计目的是简化异步编程。协程提供了一种方式&#xff0c;可以在一个线程上写起来像是在多个线程中执行。 协程的基本概念&#xff1a; 协程是轻量级的&#xff0c;不会创建新的线程。 协程会挂起当前的协…

【软件】ERETCAD-Env:在轨空间环境3D动态仿真软件

文章介绍了Extreme-environment Radiation Effect Technology Computer-Aided Design – Environment (ERETCAD-Env)软件&#xff0c;文章的介绍和展示了ERETCAD-Env软件的功能和特点&#xff0c;这是一款用于动态模拟在轨卫星所处空间环境的计算机辅助设计软件。强调了该软件在…

如何在CentOS本地搭建DataEase数据分析服务并实现远程查看数据分析

文章目录 前言1. 安装DataEase2. 本地访问测试3. 安装 cpolar内网穿透软件4. 配置DataEase公网访问地址5. 公网远程访问Data Ease6. 固定Data Ease公网地址 前言 DataEase 是开源的数据可视化分析工具&#xff0c;帮助用户快速分析数据并洞察业务趋势&#xff0c;从而实现业务…

pycharm远程连接server

1.工具–部署–配置 2.部署完成后&#xff0c;将现有的项目的解释器设置为ssh 解释器。实现在远端开发 解释器可以使用/usr/bin/python3

怎么排查K8S容器当中的Java程序内存泄露问题

今天早上发现生产线其中的一个服务在凌晨的时候突然重启了&#xff0c;内存突然从1G升到1.8G&#xff0c;CPU使用量从0.1升到了0.28&#xff0c;说明在这个时间点&#xff0c;内存突增达到了限额以上&#xff0c;服务重启了。因为这个服务布署了多节点&#xff0c;这次重启对业…

12 c++版本的坦克大战

前言 呵呵 这大概是 大学里面的 c 贪吃蛇了吧 有一些 面向对象的理解, 但是不多 这里 具体的实现 就不赘述, 仅仅是 发一下代码 以及 具体的使用 坦克大战 #include<iostream> #include<windows.h> #include<conio.h> #include<ctime> #include…

jvm(JVM快速入门、stack栈、堆、GC垃圾回收、Arthas)

文章目录 1. JVM快速入门1.1. 结构图1.2. 类加载器ClassLoader1.3. 执行引擎Execution Engine1.4. 本地接口Native Interface1.5. Native Method Stack1.6. PC寄存器(程序计数器)1.7. Method Area方法区 2. stack栈3. 堆3.1. 堆体系概述3.1.1. 新生区3.1.2. 老年代3.1.3. 永久代…

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测 目录 分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现CNN-GRU…

Visual Studio 对 C++ 头文件和模块的支持

在 C 编程领域&#xff0c;头文件和模块的管理有时候确实比较令人头疼。但是&#xff0c;有许多工具和功能可以简化此过程&#xff0c;提高效率并减少出错的可能性。下面是我们为 C 头文件和模块提供的几种工具的介绍。 构建明细 通过菜单栏 Build > Run Build Insights&a…

基于Rust的多线程 Web 服务器

构建多线程 Web 服务器 在 socket 上监听 TCP 连接解析少量的 HTTP 请求创建一个合适的 HTTP 响应使用线程池改进服务器的吞吐量优雅的停机和清理注意&#xff1a;并不是最佳实践 创建项目 ~/rust ➜ cargo new helloCreated binary (application) hello package~/rust ➜ma…

maven-依赖管理

依赖配置 https://mvnrepository.com/?__cf_chl_rt_tkvRzDsumjmJ_HF95MK4otu9XluVRHGqAY5Wv4UQYETR8-1714103058-0.0.1.1-1557 <dependencies><dependency><groupId></groupId><artifactId></artifactId><version></version>…

Day4 商品管理

Day4 商品管理 这里会总结构建项目过程中遇到的问题&#xff0c;以及一些个人思考&#xff01;&#xff01; 学习方法&#xff1a; 1 github源码 文档 官网 2 内容复现 &#xff0c;实际操作 项目源码同步更新到github 欢迎大家star~ 后期会更新并上传前端项目 编写品牌服务 …

Java集合相关的List、Set、Map基础知识

目录 一、集合介绍 二、List 三、Map HashMap的数据结构 如何理解红黑树 四、set 一、集合介绍 在Java中&#xff0c;集合是一种用于存储对象的数据结构&#xff0c;它提供了一种更加灵活和强大的方式来处理和操作数据。Java集合框架提供了一系列接口和类&#xff0c;用…

表格的单元格合并和表头的合并——vxe-table

vxe-table的官网&#xff1a;https://vxetable.cn/#/table/advanced/mergeCell在你的项目中下载安装完成后&#xff0c;先在main.js文件中引入&#xff1a; import VXETable from vxe-table import vxe-table/lib/style.css Vue.use(VXETable)一、单元格合并 效果图&#xff…

Linux驱动开发——(七)Linux阻塞和非阻塞IO

目录 一、阻塞和非阻塞IO简介 二、等待队列 2.1 等待队列头 2.2 等待队列项 2.3 将队列项添加/移除等待队列头 2.4 等待唤醒 2.5 等待事件 三、轮询 四、驱动代码 4.1 阻塞IO 4.2 非阻塞IO 一、阻塞和非阻塞IO简介 IO指的是Input/Output&#xff0c;也就是输入/输…

JavaWeb--06Vue组件库Element

Element 1 Element组件的快速入门1.1 Table表格 1 Element组件的快速入门 https://element.eleme.cn/#/zh-CN Element是饿了么团队开发的 接下来我们来学习一下ElementUI的常用组件&#xff0c;对于组件的学习比较简单&#xff0c;我们只需要参考官方提供的代码&#xff0c;然…