图像处理之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一步一步进行实现,代码结构简单清晰,便于阅读,但是效率有待提高,后续对代码进行重构,欢迎大家阅读和讨论代码中的不足。
本文代码均已在本地运行正确,有问题欢迎交流。

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

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

相关文章

Linux加强篇-存储结构与管理硬盘(一)

目录 ⛳️推荐 从“/”开始 物理设备命名规则 文件系统与数据资料 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 从“/”开始 Linux系统中一切都是文件&#xff0c;都是从“…

deep learning

谷歌在线notebook 一、基本数据类型与用法 1.torch.tensor(张量) 按照维度不同(中括号的对数)&#xff0c;可以用torch.tensor创建scalar(标量)、vector(向量)、matrix(矩阵)&#xff0c; 一般的&#xff0c;一维是标量&#xff0c;二维是向量&#xff0c;三维是矩阵&#…

银河麒麟V10 SP1服务器客户端定时数据同步

银河麒麟V10 SP1服务器客户端定时数据同步 0.概述 当前只测试了将数据从客户端往服务端推送&#xff0c;两个客户端分别推送不同的数据 1.环境 三台电脑均为银河麒麟V10SP1桌面操作系统 服务器IP&#xff1a;192.168.1.51 用户名&#xff1a;wlh 客户端IP&#xff1a;192…

LabVIEW和MES系统的智能化车间数据对接

LabVIEW和MES系统的智能化车间数据对接 随着工业4.0时代的到来&#xff0c;智能制造成为推动制造业高质量发展的重要手段。其中&#xff0c;数字化车间作为智能制造的重要组成部分&#xff0c;其设计与实现至关重要。在数字化车间环境下&#xff0c;如何利用LabVIEW软件与MES系…

解析SoC芯片:构建智能设备的核心技术

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

linux磁盘原理

在linux系统中&#xff0c;对磁盘进行管理与windows系统类似&#xff0c;都要先分区&#xff0c;格式化&#xff0c;创建文件系统&#xff0c;挂载目录&#xff0c;数据写入

【PHP开发工程师详细讲解分析】——网站注册账号(头像的上传操作),让自己喜欢的头像更换畅通无阻

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

便携式应急指挥箱规格参数

概况: 微缩型的无线视频音频传输的机动挥所。体积小、重量轻、公配电方便、携带便携、功能齐全。可进行单兵作战&#xff0c;通过此无线音频视频传输的指挥箱能完成现场图像、语音、数据的采集等功能&#xff0c;可以通过5G/4G/WIFI等多种无线网络完成传输的需求&#xff0c;或…

计算机网络相关知识总结

一、概述 计算机网络可以极大扩展计算机系统的功能机器应用范围&#xff0c;提高可靠性&#xff0c;在为用户提供放方便的同时&#xff0c;减少了整体系统费用&#xff0c;提高性价比。 计算机网络的功能主要有&#xff1a;1. 数据共享&#xff1b;2. 资源共享&#xff1b;3. 管…

echart坑

echart坑 原因&#xff1a; 引用了echarts里面的init方法显示没有定义 解决的方法 将import echarts from echarts 的引入方式改为&#xff1a; import * as echarts from echarts

【vue2】实现微信截图(复制图片)在项目内可粘贴

需求 后台管理在上传图片地方需要将复制的图片粘贴上传 一、添加事件 在原有上传组件的基础上添加 paste事件 二、方法 onPaste(e) {const items (e.clipboardData || window.clipboardData).items;let blob null;for (let i 0; i < items.length; i) {if (items[i].ty…

学习Rust的第10天:枚举和模式匹配

今天我们来看看一个类似的概念 enums 。 Enums: We saw that in Rust, enums are data types that list possible values, giving a simple and type-safe mechanism to describe alternatives. We looked at how to create enums and use them to represent similar possibili…

Dropout Feature Ranking for Deep Learning Models

摘要 深度神经网络( deep neural networks&#xff0c;DNNs )在多个领域取得了最新的研究成果。不幸的是&#xff0c;DNNs因其不可解释性而臭名昭著&#xff0c;从而限制了其在生物和医疗保健等假说驱动领域的适用性。此外&#xff0c;在资源受限的环境下&#xff0c;设计依赖…

沐风老师3dMax万有引力插件ToGround使用方法详解

3dMax万有引力插件ToGround使用教程 3dMax万有引力插件ToGround&#xff0c;用于在复杂地形&#xff08;曲面&#xff09;上将对象放置在适当高度的实用工具。例如&#xff1a;将大量的人、植物和汽车快速放置在一个街道、公园和小跑道高度不同的区域尤其有用。 【适用版本】 …

android openGL ES详解

1、渲染线程与主线程的通信 两个线程之间的通信可以用如下方法: 在主线程中的 GLSurfaceView 实例可以调用 queueEvent( &#xff09;方法传递一个 Runnable 给后台渲染线程&#xff0c;渲染线程可以调用 Activity 的 runOnUIThread()来传递事件 (event) 给主线程。 2、顶点…

SQLite FTS3 和 FTS4 扩展(三十二)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite 的命令行 Shell(三十一&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 概述 FTS3 和 FTS4 是 SQLite 虚拟表模块&#xff0c;允许用户执行 对一组文档进行全文搜索。最常见&#xff08;和最有效…

Linux之yum和vim的使用

一、yum的使用 yum 后面跟install要安装的文件名&#xff1a; 若你要安装的文件已经存在&#xff0c;则会出现&#xff1a; 要删除文件&#xff1a; yum remore文件名即可删除 在我们安装完lrzsz之后&#xff0c;可以用rz指令和sz指令&#xff1a; rz指令可以从window窗口中…

开源模型应用落地-chatglm3-6b-集成langchain(十)

一、前言 langchain框架调用本地模型&#xff0c;使得用户可以直接提出问题或发送指令&#xff0c;而无需担心具体的步骤或流程。通过LangChain和chatglm3-6b模型的整合&#xff0c;可以更好地处理对话&#xff0c;提供更智能、更准确的响应&#xff0c;从而提高对话系统的性能…

LoggerFactory is not a Logback

错误信息 LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.SimpleLoggerFactory loaded from file:/D:/maven/repository/org/slf4j/slf4j-simple/1.7.26/slf…

easyx库的学习(鼠标信息)

前言 本次博客是作为介绍easyx库的使用&#xff0c;最好是直接代码打到底&#xff0c;然后看效果即可 代码 int main() {initgraph(640, 480, EX_SHOWCONSOLE|EX_DBLCLKS);setbkcolor(RGB(231, 114, 227));cleardevice();//定义消息结构体ExMessage msg { 0 };//获取消息wh…