当前位置: 首页 > news >正文

形态学图像处理

1 工具

1.1 灰度腐蚀和膨胀

当平坦结构元b的原点是(x,y)时,它在(x,y)处对图像f的灰度腐蚀定义为,图像f与b重合区域中的最小值。结构元b在位置(x,y)处对图像f的腐蚀写为:

类似地,当b的反射的原点是(x,y)时,平坦结构元b在(x,y)处对图像f的膨胀,定义为图像f与b的反射重合区域中的最大值,即

示例:灰度X射线图像分别使用半径为2像素的圆形结构元腐蚀、膨胀图像

Mat src = imread("./7.png", 0);
Mat erodeImg, dilateImg;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(4, 4));
morphologyEx(src, erodeImg, MORPH_ERODE, element);
Mat element1 = getStructuringElement(MORPH_ELLIPSE, Size(4, 4));
morphologyEx(src, dilateImg, MORPH_DILATE, element1);

1.2 灰度开运算和闭运算

灰度图像开运算和闭运算的公式,形式上与二值图像开运算和闭运算的公式相同。结构元b对图像f的开运算是

开运算照例首先用b腐蚀f然后用b膨胀得到结果。类似地,b对f的闭运算是

 示例:灰度X射线图像分别使用a)半径为3像素的圆形结构元进行开运算,b)使用半径为5像素的结构元进行闭运算

Mat src = imread("./7.png", 0);
Mat openImg, closeImg;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(6, 6));
morphologyEx(src, openImg, MORPH_OPEN, element);
Mat element1 = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));

2 灰度图像形态学算法

2.1 形态学平滑

天鹅星座环超新星图像使用半径为5像素的圆形结构元进行开运算+闭运算

Mat src = imread("./8.png", 0);
Mat openImg, closeImg;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
morphologyEx(src, openImg, MORPH_OPEN, element);
Mat element1 = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
morphologyEx(openImg, closeImg, MORPH_CLOSE, element1);

2.2 形态学梯度

脑部CT图像膨胀和腐蚀结合图像相减

Mat src = imread("./9.png", 0);
Mat erodeImg, dilateImg;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(4, 4));
morphologyEx(src, erodeImg, MORPH_ERODE, element);
Mat element1 = getStructuringElement(MORPH_ELLIPSE, Size(4, 4));
morphologyEx(src, dilateImg, MORPH_DILATE, element1);
Mat sub = dilateImg - erodeImg;

2.3 顶帽变换和底帽变换

图像相减结合开运算和闭运算,可以得到所谓的顶帽变换和底帽变换。灰度图像f的顶帽变换定义为f减去其开运算:

类似地,f的底帽变换定义为f的闭运算减去f:

这些变换的主要应用之一是,在开运算或闭运算中用一个结构元从图像中删除目标,而不是拟合将被删除的目标。然后,差运算得到一幅仅保留已删除分量的图像。顶帽变换用于暗背景上的亮目标,而底帽变换则用于亮背景上的暗目标。因此我们通常将这两个变换称为白顶帽变换黑底帽变换

使用顶帽变换校正阴影

Mat src = imread("./10.png", 0);
Mat binImg, tophatImg, blackhatImg, dst;
// 1. Otsu最优阈值处理方法
threshold(src, binImg, 127, 255, THRESH_OTSU);// 2. 顶帽变换校正阴影后Otsu
Mat element = getStructuringElement(MORPH_CROSS, Size(41, 41));
morphologyEx(src, tophatImg, MORPH_TOPHAT, element);
threshold(tophatImg, dst, 127, 255, THRESH_OTSU);

2.4 粒度测定

粒度测定是指确定图像中颗粒的大小分布。由于颗粒急剧无法整齐的分开,因此采用逐个识别颗粒的方法来计算颗粒的属两个非常困难。形态学可间接估计颗粒的大小分布,而不需要识别和测量各个颗粒。对于比背景亮且形状规则的颗粒,这种方法是用逐渐增大的结构元对图像进行开运算。基本思想是,某个特殊大小的开运算会对包含类似大小颗粒的输入图像的那些区域产生最大影响。对于开运算得到的每幅图像,我们计算像素之和。这个和值称为表面区域,它随结构元的增大而减小,因为开运算会减小图像的亮特征。这一过程得到一个一维阵列,阵列中的每个元素都是对应大小的结构元开运算后的像素之和。为了强调两个连续开运算之间的变化,我们计算一维阵列中相邻两个元素的差。画出差值的图像,曲线中的峰值就会指明图像中主要大小颗粒的分布。

Mat src = imread("./11.png", 0);
Mat openImg, dst;
int tempGray = sum(src)[0];
for (size_t i = 1; i < 36; i=i+2)
{Mat element = getStructuringElement(MORPH_ELLIPSE, Size(i, i));morphologyEx(src, openImg, MORPH_OPEN, element);int sumGray = sum(openImg)[0];int d = tempGray - sumGray;cout << d << endl;tempGray = sumGray;if (i%10==5)imshow("openImg(ksize="+to_string(i)+")", openImg);
}

2.5 纹理分割

  形态学的纹理分割是以纹理内容为基础,找到两个区域的边界,将图像分割为不同的区域。下图是一幅在亮背景上叠加了暗斑点的噪声图像。图像有两个纹理区域,左侧区域包括一些较小的斑点,而右侧区域包括一些较大的斑点。由于目标斑点比背景暗,可以用一个尺寸大于较小斑点的圆形结构元对图像进行闭运算,删除较小的斑点,就得到只有大斑点的图像。再用尺寸大于较大斑点的圆形结构元对图像进行开运算,可以删除较大斑点之间的亮间距,整个图像形成左侧亮色和右侧暗色两个区域。通过形态学梯度运算,就得到两个区域的边界。最后将形态学梯度获得的边界叠加到原图像上,就实现了左右两种不同纹理的区域分割。

纹理分割

Mat src = imread("./12.png", 0);
Mat closeImg, dst, openImg, gradImg;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(19, 19));
morphologyEx(src, closeImg, MORPH_CLOSE, element);
Mat element1 = getStructuringElement(MORPH_ELLIPSE, Size(61, 61));
morphologyEx(closeImg, openImg, MORPH_OPEN, element1);
Mat element2 = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(openImg, gradImg, MORPH_GRADIENT, element2);
bitwise_or(gradImg, src, dst);

3二值图像形态学算法

3.1 边界提取

前景像素集合A的边界ß(A)可按如下方式得到:首先使用合适的结构元B腐蚀A,然后求A和腐蚀结果的差集。也就是说,

边界提取

Mat src = imread("./4.png",0);
Mat thr, dst, ero;
threshold(src, thr, 128, 255, THRESH_BINARY);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(thr, ero, MORPH_ERODE, kernel);

3.2 孔洞填充

Mat I = imread("./2.png",0);
threshold(I, I, 128, 255, THRESH_BINARY);
Mat Ic,thr, dst, tmp, dilImg;
bitwise_not(I, Ic);
Mat mask = Mat::zeros(I.size(), CV_8UC1);
tmp = mask.clone();
mask.at<uchar>(0, 0) = 255;
Mat kernel = getStructuringElement(MORPH_CROSS, Size(3, 3));
int diff = -1;
while (diff!=0) {tmp = mask.clone();morphologyEx(mask, dilImg, MORPH_DILATE, kernel);bitwise_and(dilImg, Ic, mask);diff = sum(mask - tmp)[0];
}

3.3 提取连通分量

  从二值图像中提取连通分量是自动图像分析的核心步骤。冈萨雷斯《数字图像处理(第四版)》提供了一种提取连通分量的形态学算法,构造一个元素为0的阵列X0,其中对应连通分量的像素值为1,采用迭代过程可以得到所有的连通分量:

该算法与约束膨胀孔洞填充的思路相同,使用条件膨胀来限制膨胀的增长,但用I代替Ic以寻找前景点。

  对于内含多个连通分量的图像A,从仅为连通分量A1内部的某个像素B开始,用3*3的结构元不断进行膨胀。由于其它连通分量与A1之间至少有一条像素宽度的空隙,每次膨胀都不会产生位于其它连通区域内的点。用每次膨胀后的图像与原始图像A取交集,就把膨胀限制在A1内部。随着集合B的不断膨胀,B的区域不断生长,但又被限制在连通分量A1的内部,最终就会充满整个连通分量A1,从而实现对连通分量A1的提取。

Mat dilImg, tmp1, sub, I;
Mat src = imread("./5.png",0);
threshold(src, I, 200, 255, THRESH_BINARY);
Mat tmp = I.clone();
Mat markImg = Mat::zeros(I.size(), CV_8UC3);
Mat mask = Mat::zeros(I.size(), CV_8UC1);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
vector<vector<Point>> cons;
while (countNonZero(tmp) != 0) {vector<Point> idx;findNonZero(tmp, idx);mask.at<uchar>(idx[0].y, idx[0].x) = 255;tmp1 = mask.clone();sub = mask.clone();while (countNonZero(sub) != 0){morphologyEx(mask, dilImg, MORPH_DILATE, kernel);bitwise_and(dilImg, I, mask);sub = mask - tmp1;   tmp1 = mask.clone();}tmp -= mask;
}

3.4 凸壳

当且仅当数字集合A的欧式凸壳只包含于属于A的数字点,该数字集合A是凸的。一种简单的可视化方法是,用直(连续的)欧几里得线段连接其边界点,如果只有前景点包含于由这些线段形成的集合,那么集合是凸的。令Bi,i=1,2,3,4表示下图中的4个结构元。凸壳程序由如下形态学公式实现:

其中,X0i=I。分别用4个结构元做击中-击不中变换直至收敛,再求并集就是A的凸壳。为了防止凸壳增长到超出保证凸性所需的最小尺寸,设定限制凸壳不超过集合A的垂直和水平尺寸。

3.5 细化

图像细化(Image Thinning),一般指二值图像的骨架化(Image Skeletonization)的一种操作运算。所谓的细化就是经过一层层的剥离,从原来的图中去掉一些点,但仍要保持原来的形状,直到得到图像的骨架。骨架,可以理解为图象的中轴。

Mat src = imread("./6.png", 0);
Mat edge = src.clone();
Mat element = getStructuringElement(MORPH_CROSS, Size(3, 3));
Mat dst = Mat::zeros(src.size(), CV_8UC1);
Mat openImg, tmp;
int n = -1;
while (countNonZero(edge) != 0) {morphologyEx(edge, openImg, MORPH_OPEN, element); // 开运算subtract(edge, openImg, tmp); // 获得骨架子集bitwise_or(dst, tmp, dst); // 将删除的像素添加到骨架图morphologyEx(edge, edge, MORPH_ERODE, element); // 腐蚀,用于下一次迭代
}

opencv实现

#include <opencv2/opencv.hpp>
#include <algorithm>
#include <iostream>
using namespace std;
using namespace cv;void ThinOnce(Mat& pSrc, Mat& pDst, int flag) {int rows = pSrc.rows;int cols = pSrc.cols;for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {if (pSrc.at<float>(i, j) == 1.0f) {/// get 8 neighbors/// calculate C(p)int P2 = (int)pSrc.at<float>(i - 1, j);int P3 = (int)pSrc.at<float>(i - 1, j + 1);int P4 = (int)pSrc.at<float>(i, j + 1);int P5 = (int)pSrc.at<float>(i + 1, j + 1);int P6 = (int)pSrc.at<float>(i + 1, j);int P7 = (int)pSrc.at<float>(i + 1, j - 1);int P8 = (int)pSrc.at<float>(i, j - 1);int P9 = (int)pSrc.at<float>(i - 1, j - 1);int sum = P2 + P3 + P4 + P5 + P6 + P7 + P8 + P9;int arr[9]{ P2, P3, P4, P5, P6, P7, P8, P9, P2 };int count = 0;for (int i = 0; i < 8; i++) {if (arr[i] == 0 && arr[i + 1] == 1)count++;} if (flag == 0 && sum < 7 && sum > 1 && P2 * P4 * P6 == 0 && P4 * P6 * P8 == 0 && count == 1)pDst.at<float>(i, j) = 0.0f;                if (flag == 1 && sum < 7 && sum > 1 && P2 * P4 * P8 == 0 && P2 * P6 * P8 == 0 && count == 1)pDst.at<float>(i, j) = 0.0f;}}}
}
void thin(Mat& src, Mat& dst) {bool bDone = false;int rows = src.rows;int cols = src.cols;/// pad source and dstMat p_enlarged_src, p_enlarged_dst;copyMakeBorder(src, p_enlarged_src, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(0));p_enlarged_src.convertTo(p_enlarged_src, CV_32F, 1/255.0);p_enlarged_dst = p_enlarged_src.clone();<br>Mat p_cmp = Mat::zeros(rows + 2, cols + 2, CV_8UC1);int iter = 0;while (bDone != true) {// sub-iterationint i = iter % 2;ThinOnce(p_enlarged_src, p_enlarged_dst, i);// comparecompare(p_enlarged_src, p_enlarged_dst, p_cmp, CMP_EQ);// checkint num_non_zero = countNonZero(p_cmp);if (num_non_zero == (rows + 2) * (cols + 2)) {bDone = true;}// copyp_enlarged_dst.copyTo(p_enlarged_src);iter++;}// copy resultdst = p_enlarged_dst({ 1, 1, cols, rows }).clone();
}int main(int argc, char* argv[])
{Mat src = imread("./6.png", 0);Mat dst;thin(src, dst);imshow("src", src);imshow("dst", dst);waitKey(0);return 0;
} 

相关文章:

形态学图像处理

1 工具 1.1 灰度腐蚀和膨胀 当平坦结构元b的原点是(x,y)时&#xff0c;它在(x,y)处对图像f的灰度腐蚀定义为&#xff0c;图像f与b重合区域中的最小值。结构元b在位置(x,y)处对图像f的腐蚀写为&#xff1a; 类似地&#xff0c;当b的反射的原点是(x,y)时&#xff0c;平坦结构元…...

安泰电压放大器的选型方案是什么

电压放大器是一种常见的电路元件&#xff0c;广泛应用于各种电子设备中。在选择电压放大器的时候&#xff0c;我们需要考虑一系列因素&#xff0c;以确保选型方案能够满足实际需求。下面安泰电子将详细介绍电压放大器选型的主要考虑因素&#xff0c;包括应用需求、技术性能、成…...

ARMV8安全特性:Pointer Authentication

文章目录 前言一、Introduction二、Problem Definition三、Pointer Authentication3.1 Instructions3.2 Cryptography3.3 Key Management 四、Sample Use Cases4.1 Software Stack Protection4.2 Control Flow Integrity (CFI)4.3 Binding Pointers to Addresses 五、Security …...

MySQL和Redis更新一致性问题

1. 先更新数据库&#xff0c;再更新缓存 适用场景&#xff1a;适用于对数据一致性要求不是特别高&#xff0c;且缓存更新失败对 系统影响较小的场景。例如&#xff0c;某些非关键数据的缓存更新。 风险&#xff1a;如果缓存更新失败&#xff0c;会导致数据库和缓存数据不一致。…...

(19)夹钳(用于送货)

文章目录 前言 1 常见的抓手参数 2 参数说明 前言 Copter 支持许多不同的抓取器&#xff0c;这对送货应用和落瓶很有用。 按照下面的链接&#xff08;或侧边栏&#xff09;&#xff0c;根据你的设置了解配置信息。 Electro Permanent Magnet v3 (EPMv3)Electro Permanent M…...

安装lap和cython_bbox失败了很多次!!!终于被我发现了!

先说 lap 试了很多种方式&#xff0c;pip install lap / conda install -c conda-forge lap … 全失败了后面发现 lap 不支持 python > 3.9 的版本使用 pip install lapx 成功&#xff01; cython_bbox 更难了 一直提示缺少MicroSoft C 14.0 … 大家有需要自行下载&#x…...

异业联盟整合各大行业门店,共享资源

异业联盟系统是一种将不同行业的企业或商家整合在一起&#xff0c;通过资源共享、优势互补、合作推广等方式&#xff0c;实现共同发展和互利共赢的商业合作模式的数字化管理和运营系统。 其具有以下显著优势&#xff1a; 1.拓展客户群体&#xff1a;不同行业的企业联合起来&am…...

前端如何去看蓝湖

首先加入团队&#xff0c;在内容中我们可以看到点击图片&#xff0c;右边出现的图 包含了像素甚至有代码&#xff0c;我们可以参考这个代码。 那么在使用之前我们需要调整好像素&#xff0c;例如我们的像素宽为375&#xff0c;不用去管高&#xff0c;然后这个宽度我们可以去自…...

HTML+CSS+JS 实现3D风吹草动效果(B站视频)

效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>3D effect&…...

常用网络概念

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ☁️运维工程师的职责&#xff1a;监…...

图鸟UI框架在uni-app多端应用开发中的实践与应用

摘要&#xff1a; 随着移动互联网的蓬勃发展&#xff0c;跨平台应用开发已成为行业趋势。本文将探讨图鸟UI框架如何在uni-app开发环境下助力开发者高效构建多端应用&#xff0c;并通过具体案例展示其在实际项目中的应用效果。 一、引言 在移动应用开发领域&#xff0c;跨平台…...

特征值究竟体现了矩阵的什么特征?

特征值究竟体现了矩阵的什么特征&#xff1f; 简单来说就是x经过矩阵A映射后和自己平行 希尔伯特第一次提出eigenvalue,这里的eigen就是自己的。所以eigenvalue也称作本征值 特征值和特征向量刻画了矩阵变换空间的特征 对平面上的任意向量可以如法炮制&#xff0c;把他在特征…...

C语言-顺序表

&#x1f3af;引言 欢迎来到HanLop博客的C语言数据结构初阶系列。在这个系列中&#xff0c;我们将深入探讨各种基本的数据结构和算法&#xff0c;帮助您打下坚实的编程基础。本次我将为你讲解。顺序表&#xff08;也称为数组&#xff09;是一种线性表&#xff0c;因其简单易用…...

OpenCV漫水填充函数floodFill函数的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 功能描述 ffloodFill函数是OpenCV库中用于图像处理的一个功能&#xff0c;它用于填充与种子点颜色相近的连通区域。这个函数在很多场景下都非常有用&#x…...

redis内存分析

阿里云redis集群对key进行hash后保存在对应的后端节点&#xff0c;使每个节点的key数量大致相同&#xff0c;但是如果存在大key&#xff0c;就会导致单个节点内存用满&#xff0c;可以使用redis-rdb-tools 或rdr来对内存进行分析。 redis-rdb-tools redis-rdb-tools通过对dum…...

redis批量删除keys,用lua脚本。

文章目录 现象解决方法 现象 系统报错&#xff1a; misconf redis is configured to save ....后查看机器内存。 是内存满了&#xff0c;需要删除其中的key 解决方法 (1) 编写一个脚本&#xff0c;放在redis-cli.exe同一个目录 (2) 脚本内容如下&#xff1a; -- 使用Lua脚…...

Python-找客户软件

软件功能 请求代码&#xff1a; 填充表格&#xff1a; 可以search全国各个区县的所有企业信息&#xff0c;过滤手机号、查看是否续存/在业状态。方便找客户。 支持定-制-其他引-留-阮*件&#xff08;XHSS&#xff0c;DYY&#xff0c;KS&#xff0c;Bi-li*Bi-li&#xff09; V*…...

STM32 - PWR 笔记

PWR&#xff08;Power Control&#xff09;电源控制 PWR 负责管理 STM32 内部的电源供电部分&#xff0c;可以实现 可编程电压监测器 和 低功耗模式 的功能 可编程电压监测器&#xff08;PVD&#xff09;可以监控VDD电源电压&#xff0c;当VDD下降到PVD阀值以下或上升到PVD…...

标准盒模型和怪异盒子模型的区别

在 CSS 中&#xff0c;标准盒模型和怪异盒模型是两种不同的盒子模型计算方式&#xff0c;主要区别如下&#xff1a; 一、标准盒模型&#xff08;content-box&#xff09; 1. 定义与组成 - 标准盒模型是 CSS 中默认的盒模型。 - 它由内容区域&#xff08;content&#xff09;、…...

推荐算法——MRR

定义&#xff1a; MRR计算的是第一个正确答案的排名的倒数&#xff0c;并对所有查询取平均值。它衡量了模型在排序结果中快速找到正确答案的能力。 其中&#xff1a; Q 是查询的总数。ranki​ 是第 i 个查询中第一个正确答案的排名&#xff08;位置&#xff09;。如果第一个正…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...