OpenCV基础(一):图片加载,图片腐蚀,图片模糊,图片边缘检测,图片保存

news2024/10/7 2:28:39

前言

在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》,结合我自己的工作学习经历,我准备写一个音视频系列blog。本文是音视频系列blog的其中一个, 对应的要学习的内容是:使用OpenCV完成图片加载,图片腐蚀,图片模糊,图片边缘检测,图片保存。


音视频系列blog

音视频系列blog: 点击此处跳转查看


目录

在这里插入图片描述


1.1 效果展示

话不多说,先上效果图!(源代码在文章最后)

加载图片:
在这里插入图片描述

图片腐蚀:
在这里插入图片描述

图片模糊:
在这里插入图片描述

图片边缘检测:
在这里插入图片描述


1.2 图片加载

VS2017(或者其他版本VS)如何导入OpenCV,如果你不清楚,可以参考我的这篇文章:

OpenCV分析tfboys十周年演唱会灯牌大战结果

图片加载代码如下:

#include <opencv2/opencv.hpp>
#include <iostream>

// 加载图片
int main() {
	// 定义图片文件的完整路径
	std::string image_path = "D:\\path_to_your_image.jpg";

	// 使用OpenCV加载图片
	cv::Mat image = cv::imread(image_path);

	if (image.empty()) {
		std::cerr << "Error: Unable to load image." << std::endl;
		return -1;
	}

	cv::imshow("Loaded Image", image);
	cv::waitKey(0);

	return 0;
}

Mat

在OpenCV中,cv::Mat 是一个非常重要的类,用于表示图像和矩阵数据,类似于Java中的 BufferedImage 类。它是OpenCV库中的核心数据结构之一,用于存储图像、矩阵和多维数组数据。cv::Mat 可以被看作是一个"容器",用来存储图像和矩阵数据,就像一个盒子,可以放入各种东西。

imread

imread 是 OpenCV 库中的一个函数,用于读取图像文件并将其加载到 cv::Mat 对象中。具体来说,imread 用于从磁盘上的图像文件读取像素数据,并将这些像素数据存储在 cv::Mat 中,以便后续的图像处理和分析。

在以下代码中:

cv::Mat image = cv::imread(image_path);

imread 将指定路径的图像文件加载到名为 imagecv::Mat 对象中。加载后,可以使用 image 对象进行图像处理操作。

imshow

imshow 也是 OpenCV 库中的一个函数,它用于显示图像在图形用户界面 (GUI) 窗口中,它允许你将图像在应用程序中的窗口中显示出来,以便用户可以看到图像的内容。

通常情况下,你可以将 cv::Mat 对象(包含加载的图像数据)传递给 imshow 函数,然后指定窗口的名称。例如:

cv::imshow("Loaded Image", image);

在这个示例中,"Loaded Image" 是窗口的名称,image 是包含图像数据的 cv::Mat 对象。当你调用 imshow 时,它将创建一个名为 "Loaded Image" 的窗口,并在该窗口中显示 image 中的图像数据。

waitKey(0)

cv::waitKey(0) 是 OpenCV 中的一个函数调用,它用于等待用户在图形用户界面 (GUI) 窗口中按下一个键。具体来说,这个函数在窗口上等待用户的键盘输入,并返回用户按下的键的ASCII码值。

在参数中的 0 表示函数将一直等待用户按键,直到用户按下键盘上的任意键。如果你将参数设置为一个正整数,例如 cv::waitKey(100),它将等待100毫秒,然后返回。如果用户在这个时间内按下了某个键,它将返回该键的ASCII码值;如果用户没有按下任何键,它将返回零。

通常,cv::waitKeycv::imshow 一起使用,以便在显示图像时能够等待用户的交互。例如:

cv::imshow("Loaded Image", image);
int key = cv::waitKey(0);

if (key == 27) {
    // 如果用户按下ESC键 (ASCII码值为27),则执行某些操作
    // 比如关闭窗口。。。
}

在这个示例中,cv::waitKey 用于等待用户在显示图像窗口中按下任意键,并将按下的键的ASCII码值存储在变量 key 中。然后,您可以根据用户的输入执行不同的操作,例如根据按下的键来决定关闭窗口或执行其他处理。


1.3 图片腐蚀

要在OpenCV中对图像进行腐蚀操作,可以使用 cv::erode 函数。腐蚀是一种形态学操作,通常用于图像处理中的图像细化、去噪等任务。下面是一个示例,演示如何在OpenCV中执行图片腐蚀操作:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
	// 读取图像
	cv::Mat image = cv::imread("D:\\path_to_your_image.jpg");

	if (image.empty()) {
		std::cerr << "Error: Unable to load image." << std::endl;
		return -1;
	}

	// 创建一个核(用于定义腐蚀的形状和大小)
	cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));

	// 用来存放腐蚀之后的图片
	cv::Mat erodedImage;

	// 执行腐蚀操作
	cv::erode(image, erodedImage, kernel);

	// 显示原始图像和腐蚀后的图像
	cv::imshow("原始图像", image);
	cv::imshow("腐蚀后的图像", erodedImage);

	// 等待用户按下键盘上的任意键
	cv::waitKey(0);

	return 0;
}

在这个示例中,我们首先读取了一张图像,然后创建了一个核(cv::Mat kernel)来定义腐蚀操作的形状和大小。可以根据需要调整核的大小和形状。(这个核,包括下面的出现的两种核,如果不明白也没关系,我后面图像形态学会详细解释,你目前可以把这个核理解为一个工具,这个工具对每一个像素点进行相关操作,改变这个像素的数值,达到腐蚀,模糊等效果)

接下来,使用 cv::erode 函数来执行腐蚀操作,将原始图像 image 和核应用于腐蚀操作,结果存储在 erodedImage 中。

最后,我们使用 cv::imshow 来显示原始图像和腐蚀后的图像,然后使用 cv::waitKey 等待用户按下键盘上的任意键,以便查看结果。

cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));

这行代码创建了一个核(Kernel)用于形态学操作,特别是腐蚀操作。这行代码的含义:

  1. cv::MORPH_RECT:这是核的形状,表示矩形形状的核。形态学操作通常使用不同形状的核,例如矩形、椭圆或交叉形。在这里,我们选择了一个矩形形状的核,它将应用于腐蚀操作。
  2. cv::Size(5, 5):这是核的大小,表示核的宽度和高度。在这个示例中,我们创建了一个5x5大小的核,它是一个5列5行的矩阵,用于定义腐蚀的操作范围。核的大小会影响腐蚀的效果,较大的核会导致更强烈的腐蚀。

总之,这行代码创建了一个5x5大小的矩形核,它将用于执行腐蚀操作。腐蚀操作会在图像中移动这个核,将核与图像中的像素进行比较,并将核下的像素值设置为核中所有像素的最小值,从而导致图像中的边缘变细。核的大小和形状可以根据具体的应用和图像处理需求进行调整。 ​

cv::erode(image, erodedImage, kernel);

这行代码使用了OpenCV的 cv::erode 函数来执行腐蚀操作。这行代码的含义:

  • image:这是输入图像,即你希望对其执行腐蚀操作的图像。在这个示例中,image 包含了加载的原始图像数据。
  • erodedImage:这是输出图像,即腐蚀操作的结果将存储在 erodedImage 中。cv::erode 函数将对输入图像 image 执行腐蚀操作,并将结果存储在 erodedImage 中。
  • kernel:这是先前创建的核(Kernel),它定义了腐蚀操作的形状和大小。腐蚀操作将使用这个核在输入图像上移动,将核下的像素值设置为核中所有像素的最小值,从而执行腐蚀。

1.4 图片模糊

要在OpenCV中对图像进行模糊操作,可以使用 cv::GaussianBlur 函数来执行高斯模糊。高斯模糊是一种常用的图像模糊方法,可以用于降低图像中的噪声或平滑图像。以下是一个示例代码,演示如何在OpenCV中执行高斯模糊:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 读取图像
    cv::Mat image = cv::imread("D:\\path_to_your_image.jpg");

    if (image.empty()) {
        std::cerr << "Error: Unable to load image." << std::endl;
        return -1;
    }

    // 定义模糊核的大小
    cv::Size kernelSize(5, 5); // 可以根据需要调整核的大小

    // 用来存放模糊之后的图片
    cv::Mat blurredImage;
    // 执行高斯模糊操作
    cv::GaussianBlur(image, blurredImage, kernelSize, 0);

    // 显示原始图像和模糊后的图像
    cv::imshow("Original Image", image);
    cv::imshow("Blurred Image", blurredImage);

    // 等待用户按下键盘上的任意键
    cv::waitKey(0);

    return 0;
}

在这个示例中,首先读取了一张图像,然后定义了模糊核的大小(kernelSize)。

接下来,使用 cv::GaussianBlur 函数来执行高斯模糊操作,将原始图像 image 和模糊核应用于图像,结果存储在 blurredImage 中。

最后,我们使用 cv::imshow 来显示原始图像和模糊后的图像,并使用 cv::waitKey 等待用户按下键盘上的任意键,以便查看结果。

cv::Size kernelSize(5, 5);

cv::Size(5, 5) 是一个创建 OpenCV cv::Size 对象的语句,它用于指定模糊核的大小。它的含义:

  • cv::Size 是 OpenCV 中的一个类,用于表示大小或尺寸。它通常用于指定矩形、核、图像等的大小。
  • (5, 5) 是一个包含两个整数的元组,表示宽度和高度。在这个示例中,(5, 5) 表示模糊核的宽度为5个像素,高度为5个像素,因此模糊核是一个5x5的矩形。

所以,cv::Size(5, 5) 的含义是创建一个大小为5x5的矩形核,该核将用于执行高斯模糊操作。核的大小会影响模糊的程度,较大的核会导致更强烈的模糊效果,而较小的核会产生更轻微的模糊效果。

高斯模糊是一种图像处理技术,用于降低图像中的噪声或平滑图像。它的主要原理是将图像中的每个像素点替换为其周围像素的加权平均值,其中权重是根据高斯分布来确定的。这意味着位于核中心的像素具有更大的权重,而离核中心越远的像素具有较小的权重。

高斯模糊的过程如下:

  1. 定义核的大小: 首先,需要定义一个模糊核,它是一个矩形或正方形的区域,大小由你自己指定。这个核的大小决定了模糊的程度。
  2. 遍历图像: 对于图像中的每个像素,将模糊核放置在该像素周围的区域。
  3. 计算加权平均值: 计算核内所有像素的加权平均值。核中心的像素具有最高的权重,而离中心越远的像素权重越低。
  4. 替换像素值: 使用计算出的平均值替换原始像素的值。这个操作对图像中的每个像素都会执行,从而产生模糊后的图像。

高斯模糊的主要效果是降低图像中的噪声,平滑细节,并模糊图像的轮廓。模糊核的大小决定了模糊的程度,较大的核会导致更强烈的模糊效果,而较小的核会产生较轻微的模糊效果。

cv::GaussianBlur(image, blurredImage, kernelSize, 0);

cv::GaussianBlur 是 OpenCV 中用于执行高斯模糊操作的函数。

  • image:这是输入图像,即要对其执行高斯模糊操作的图像。在这个示例中,image 包含了加载的原始图像数据。
  • blurredImage:这是输出图像,即高斯模糊操作的结果将存储在 blurredImage 中。cv::GaussianBlur 函数将对输入图像 image 执行高斯模糊操作,并将结果存储在 blurredImage 中。
  • kernelSize:这是一个 cv::Size 对象,表示高斯核的大小。在之前的代码中定义了 kernelSize,它决定了高斯模糊的程度,即核的大小。在这个示例中,kernelSize 是一个5x5的大小,用于定义高斯核的大小。
  • 0:这是高斯模糊的标准差(standard deviation),通常为零。标准差用于确定高斯分布的形状,它可以影响模糊的程度。在这里,将标准差设置为零表示使用默认值,而不自定义高斯分布的形状。

1.5 图片边缘检测

要在OpenCV中对图像进行边缘检测,可以使用一种称为Canny边缘检测的算法。以下是一个示例代码,演示如何在OpenCV中执行Canny边缘检测:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
	// 读取图像
	cv::Mat image = cv::imread("D:\\path_to_your_image.jpg");

	if (image.empty()) {
		std::cerr << "Error: Unable to load image." << std::endl;
		return -1;
	}

	// 用来存放边缘检测之后的图片
	cv::Mat edges;
	// 执行Canny边缘检测
	cv::Canny(image, edges, 100, 200); // 调整阈值以控制边缘检测的灵敏度

	// 显示原始图像和边缘检测结果
	cv::imshow("Original Image", image);
	cv::imshow("Edges", edges);

	// 等待用户按下键盘上的任意键
	cv::waitKey(0);

	return 0;
}

在这个示例中,我们首先读取了一张图像。然后,我们使用 cv::Canny 函数来执行Canny边缘检测,将输入图像 image 和一些参数传递给它。在这里,参数 100200 分别表示低阈值和高阈值。可以根据需要调整这些阈值以控制边缘检测的灵敏度。

最后,我们使用 cv::imshow 来显示原始图像和边缘检测的结果,并使用 cv::waitKey 等待用户按下键盘上的任意键,以便查看结果。

cv::Canny(image, edges, 100, 200);

cv::Canny 是 OpenCV 中用于执行Canny边缘检测的函数。

  • image:这是输入图像,即要对其执行Canny边缘检测的图像。在这个示例中,image 包含了你加载的原始图像数据。请注意,Canny边缘检测通常用于灰度图像,因此在使用前,您可能需要将图像转换为灰度图像。
  • edges:这是输出图像,Canny边缘检测的结果将存储在 edges 中。cv::Canny 函数将检测到的边缘信息存储在这个图像中。
  • 100200:这是两个阈值参数。这两个阈值参数用于控制边缘检测的灵敏度和边缘连接的强度。
    • 100 是低阈值(Low threshold):低于这个阈值的边缘被丢弃(就是图片黑色部分)。
    • 200 是高阈值(High threshold):高于这个阈值的像素被认为是强边缘(就是图片白色部分)。

通过调整这两个阈值参数,可以控制Canny边缘检测的结果,以适应不同的图像和应用场景。较低的阈值会导致更多的边缘被检测到,而较高的阈值会产生更强的边缘。可以根据你的需求和图像特性来调整这些阈值。


1.6 图片保存

以下是一个示例代码,演示如何在OpenCV中对一张彩色图像执行Canny边缘检测,并将结果保存到D盘:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 读取彩色图像
    cv::Mat image = cv::imread("D:\\path_to_your_image.jpg");

    if (image.empty()) {
        std::cerr << "Error: Unable to load image." << std::endl;
        return -1;
    }

    // 用来存放边缘检测之后的图片
    cv::Mat edges;
    // 执行Canny边缘检测
    cv::Canny(image, edges, 100, 200); // 调整阈值以控制边缘检测的灵敏度

    // 保存边缘检测结果到D盘
    cv::imwrite("D:\\edges.jpg", edges);

    std::cout << "Edges saved to D:\\edges.jpg" << std::endl;

    return 0;
}

在这个示例中,我们首先读取了一张彩色图像,然后使用 cv::Canny 函数执行Canny边缘检测,将输入图像 image 作为输入,并将边缘检测结果存储在 edges 中。

接下来,我们使用 cv::imwrite 函数将边缘检测结果保存为一张新的图像文件,存储在D盘的根目录下,文件名为 “edges.jpg”。您可以根据需要更改保存路径和文件名。

cv::imwrite(“D:\edges.jpg”, edges);

cv::imwrite 是 OpenCV 中用于将图像保存为文件的函数。

  • "D:\\edges.jpg":这是保存图像的目标文件路径。在这里,图像将保存为名为 “edges.jpg” 的文件,该文件将存储在D盘(D:\)的根目录下。可以根据需要更改目标文件的路径和文件名。
  • edges:这是要保存的图像数据。在这个示例中,edges 包含了之前执行Canny边缘检测操作后得到的边缘图像数据。cv::imwrite 将这个图像数据保存为指定路径的图像文件。

源代码:(欢迎star)
OpenCV基础(一):图片加载,图片腐蚀,图片模糊,图片边缘检测,图片保存

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android逆向学习(四)app修改smali函数跳过弹窗广告,等待广告,更新提醒

Android逆向学习&#xff08;四&#xff09;app修改smali函数跳过弹窗广告&#xff0c;等待广告&#xff0c;更新提醒 一、写在前面 这是吾爱破解课程的第三个练习&#xff0c;我在写这篇博客时遇到了vscode插件bug&#xff0c;已经想办法联系原作者了&#xff0c;希望能够尽…

【已解决】pyqt5界面拖拽文件进入时,显示禁止图标,槽函数也没有进入。怎么办?

我今天遇到了一个很无语的问题&#xff0c;不知道为啥&#xff0c;用 QMainwindow 创建了一个简单的界面&#xff0c;里面只有一个 Qlabel。 想要尝试拖拽文件进来&#xff0c;然后打印文件路径。但是怎么改都没反应。一直显示禁止的一个图标&#xff0c;类似于&#xff1a; 一…

LeetCode——顺时针打印矩形

题目地址 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目解析 按照顺时针一次遍历&#xff0c;遍历外外层遍历里层。 代码如下 class Solution { public:vector<int> spiralOrder(vector<vector<int>>& matrix) {if(…

anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter

Win11查看安装的Python路径及安装的库 anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter 介绍开源包管理系统和环境管理系统 &#xff0c;包括多种语言的包安装&#xff0c;运行&#xff0c;更新&#xff0c;删除&#xff0c;最重要的是可以解…

YOLOV8模型改进-添加CBAM注意力机制

1.CBAM介绍 CBAM注意力机制是yolov8自带的注意力机制&#xff0c;它是通道注意模块和空间注意模块的结合。 2.查看CBAM在yolov8中的位置 路径&#xff1a;ultralytics/nn/modules/conv.py 3.添加CBAM 1.首先打开tasks.py文件&#xff1a;ultralytics/nn/modules/tasks.py 2.…

centos编译升级cmake,痛苦的Linux小白

环境 root 用户 下载 cmake官网下载地址&#xff1a;https://cmake.org/download/ 获取下载地址&#xff0c;右击cmake-3.27.4.tar.gz 命令行输入链接地址&#xff0c;下载 wget https://github.com/Kitware/CMake/releases/download/v3.27.4/cmake-3.27.4.tar.gz解压 tar -zx…

​Vue + Element UI前端篇(二):Vue + Element 案例 ​

Vue Element UI 实现权限管理系统 前端篇&#xff08;二&#xff09;&#xff1a;Vue Element 案例 导入项目 打开 Visual Studio Code&#xff0c;File --> add Folder to Workspace&#xff0c;导入我们的项目。 安装 Element 安装依赖 Element 是国内饿了么公司提…

【算法训练-链表 三】删除链表的倒数第N个节点

最近工作有点忙&#xff0c;刷道中等题缓解下压力&#xff01;删除链表的倒数第N个节点&#xff0c;使用【链表】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&#xff1a;目标公司最近一年出现频率排序&#xff0c;由高…

解决Nacos服务器连接问题:一次完整的排查经验分享

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

【docker】私有仓库搭建

Docker 私有仓库搭建 在 Docker 中&#xff0c;当我们执行 docker pull xxx 的时候 &#xff0c;它实际上是从 registry.hub.docker.com 这个地址去查找&#xff0c;这就是Docker公司为我们提供的公共仓库。在工作中&#xff0c;我们不可能把企业项目push到公有仓库进行管理。…

基于FPGA的数字秒表设计(完整工程)

目录 概述 设计功能 数字秒表设计的目的 模块仿真 设计代码 概述 该设计是用于体育比赛的数字秒表,基于FPGA在Quartus II 9.0sp2软件下应用VHDL语言编写程序,采用ALTRA公司CycloneII系列的EP2C8Q208芯片进行了计算机仿真&#xff0c;并给出了相应的仿真结果。本设计有效的…

Ribbon负载均衡+Nacos服务搭建

Ribbon负载均衡 流程 首先通过RibbonLoadBalanceerClient获取服务名&#xff0c;并传给DynamicServerListLoadBalancer——>通过EureKa-server获取服务名对应服务列表(也就是被注册到EureKa中的服务&#xff0c;可能包括不同端口的)&#xff0c;然后我们会根据IRule中的服务…

学习pytorch9 神经网络-卷积层

神经网络-卷积层 官网卷积数据公式参数说明卷积运算演示输入输出channel代码**注意点&#xff1a;**code 执行结果 官网 https://pytorch.org/docs/stable/nn.html#convolution-layers 图像识别常用conv2d 二维卷积 nn.Conv2d https://pytorch.org/docs/stable/generated/torch…

文件包含漏洞学习小结

目录 一、介绍 二、常见文件包含函数 三、文件包含漏洞代码举例分析 四、文件包含漏洞利用方式 4.1 本地文件包含 1、读取敏感文件 2、文件包含可运行的php代码 ①包含图片码 ②包含日志文件 ③包含环境变量getshell ④临时文件包含 ⑤伪协议 4.2 远程文件包含 4.…

【学习笔记】C++ 中 static 关键字的作用

目录 前言static 作用在变量上static 作用在全局变量上static 作用在局部变量上static 作用在成员变量上 static 作用在函数上static 作用在函数上static 作用在成员函数上 前言 在 C/C 中&#xff0c;关键字 static 在不同的应用场景下&#xff0c;有不同的作用&#xff0c;这…

指针进阶(一)

指针进阶 1. 字符指针面试题 2. 指针数组3. 数组指针3.1 数组指针的定义3.2 &数组名VS数组名 3.3 数组指针的使用4. 数组传参和指针传参4.1 一维数组传参4.2 二维数组传参4.3 一级指针传参4.4 二级指针传参 前言 指针的主题&#xff0c;我们在初级阶段的《指针》章节已经接…

腾讯音乐基于 Apache Doris + 大模型构建全新智能数据服务平台

当前&#xff0c;大语言模型的应用正在全球范围内引发新一轮的技术革命与商业浪潮。腾讯音乐作为中国领先在线音乐娱乐平台&#xff0c;利用庞大用户群与多元场景的优势&#xff0c;持续探索大模型赛道的多元应用。本文将详细介绍腾讯音乐如何基于 Apache Doris 构建查询高效、…

Python之调用shell两种写法(二十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

如何优雅的关闭流

https://blog.csdn.net/zy345293721/article/details/103654745 JDK1.7 开始使用 关闭流使用try-catch-finally 是jdk1.7 之前的语法 try (FileInputStream fis new FileInputStream(srcFile)){fis.read(fileContent);fis.close();} catch (IOException e) {e.printStackTr…

大模型参数高效微调技术原理综述(二)-BitFit、Prefix Tuning、Prompt Tuning

随着&#xff0c;ChatGPT 迅速爆火&#xff0c;引发了大模型的时代变革。然而对于普通大众来说&#xff0c;进行大模型的预训练或者全量微调遥不可及。由此&#xff0c;催生了各种参数高效微调技术&#xff0c;让科研人员或者普通开发者有机会尝试微调大模型。 因此&#xff0c…