OpenCV17-图像形态学操作

OpenCV17-图像形态学操作

  • 1.形态学操作
    • 1.1腐蚀
    • 1.2膨胀
  • 2.形态学应用
    • 2.1开运算
    • 2.2闭运算
    • 2.3形态学梯度
    • 2.4顶帽运算
    • 2.5黑帽运算
    • 2.6击中击不中变换
    • 2.7形态学应用示例


1.形态学操作

1.1腐蚀

图像腐蚀(Image erosion)可用于减小图像中物体的大小、填充孔洞或者分离邻近的物体。腐蚀操作通过对图像中的每个像素应用结构元素(也称为腐蚀内核)来实现。

腐蚀操作的原理是将结构元素与图像进行逐像素的比较。如果结构元素的所有像素与图像中对应位置的像素都匹配,那么该像素保持不变。否则,该像素被腐蚀为背景像素。这样,腐蚀操作将使物体边界向内收缩,并且可以消除小的物体或连接物体之间的细小连接。

下面是一种常见的图像腐蚀算法的伪代码表示:

对于图像中的每个像素(x, y):对于结构元素中的每个像素(i, j):如果结构元素的中心与图像中的像素(x, y)对齐:如果结构元素的所有像素与图像中对应位置的像素都匹配:继续下一步否则:将图像中的像素(x, y)设置为背景像素中断内层循环

腐蚀就是寻找图像中能够将结构元素全部包含的像素点。对于输出图像中的每个像素位置(x, y),将结构元素B的中心与输入图像I的对应位置(x, y)对齐,然后在结构元素B覆盖的区域内选择输入图像中的最小像素值作为输出图像中的像素值。

OpenCV提供了 getStructuringElement() 函数用于生成常用的矩形结构元素、十字结构元素和椭圆结构元素。

Mat getStructuringElement(int shape,  // 生成结构元素的形状Size ksize, // 结构元素的尺寸Point anchor = Point(-1,-1)
);//! shape of the structuring element
enum MorphShapes {MORPH_RECT    = 0, //矩形结构元素,所有元素都为1MORPH_CROSS   = 1, //十字结构元素,中间的列和行元素为1MORPH_ELLIPSE = 2  //椭圆结构元素,矩形的内接椭圆元素为1
};

OpenCV提供了 erode() 函数用于图像腐蚀:

void erode(InputArray src, OutputArray dst, InputArray kernel,  // 结构元素Point anchor = Point(-1,-1), int iterations = 1, // 腐蚀的次数,默认为1int borderType = BORDER_CONSTANT,const Scalar& borderValue = morphologyDefaultBorderValue() // 使用边界不变外推法时的边界值
);

该函数根据结构元素对输入图像进行腐蚀,在腐蚀多通道图像时,每个通道独立进行腐蚀运算。

需要注意的是,该函数的腐蚀过程只针对图像中的非零像素,因此如果图像是以0像素为背景(黑底),那么腐蚀操作后会看到图像中的内容变得更瘦更小;如果图像是以255像素为背景(白底),那么腐蚀操作后看到的图像中的内容变得更粗更大。(与下面的膨胀相反)

下面代码中演示了腐蚀的效果,实现对原图中米粒进行计数,通过结果可以发现,腐蚀操作可以去除由噪声引起的较小的连通域,得到了正确的米粒数:

#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no logusing namespace cv;
using namespace std;//绘制包含区域函数
void drawState(Mat& img, int number, Mat centroids, Mat stats, String str) {RNG rng(10086);vector<Vec3b> colors;for (int i = 0; i < number; i++){//使用均匀分布的随机数确定颜色Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));colors.push_back(vec3);}for (int i = 1; i < number; i++){// 中心位置int center_x = centroids.at<double>(i, 0);int center_y = centroids.at<double>(i, 1);//矩形边框int x = stats.at<int>(i, CC_STAT_LEFT);int y = stats.at<int>(i, CC_STAT_TOP);int w = stats.at<int>(i, CC_STAT_WIDTH);int h = stats.at<int>(i, CC_STAT_HEIGHT);// 中心位置绘制circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);// 外接矩形Rect rect(x, y, w, h);rectangle(img, rect, colors[i], 1, 8, 0);putText(img, format("%d", i), Point(center_x, center_y),FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);}imshow(str, img);
}int main()
{cout << "OpenCV Version: " << CV_VERSION << endl;utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);//生成用于腐蚀的原图像Mat src = (Mat_<uchar>(6, 6) <<0, 0, 0, 0, 255, 0,0, 255, 255, 255, 255, 255,0, 255, 255, 255, 255, 0,0, 255, 255, 255, 255, 0,0, 255, 255, 255, 255, 0,0, 0, 0, 0, 0, 0);Mat struct1, struct2;struct1 = getStructuringElement(MORPH_RECT, Size(3, 3));  //矩形结构元素struct2 = getStructuringElement(MORPH_CROSS, Size(3, 3));  //十字结构元素Mat erodeSrc;  //存放腐蚀后的图像erode(src, erodeSrc, struct2);namedWindow("src", WINDOW_GUI_NORMAL);namedWindow("erodeSrc", WINDOW_GUI_NORMAL);imshow("src", src);imshow("erodeSrc", erodeSrc);Mat LearnCV_black = imread("black_white_handwritten.jpg", IMREAD_ANYCOLOR);Mat LearnCV_write = imread("white_black_handwritten.jpg", IMREAD_ANYCOLOR);Mat erode_black1, erode_black2, erode_write1, erode_write2;//黑背景图像腐蚀erode(LearnCV_black, erode_black1, struct1);erode(LearnCV_black, erode_black2, struct2);imshow("LearnCV_black", LearnCV_black);imshow("erode_black1", erode_black1);imshow("erode_black2", erode_black2);//白背景腐蚀erode(LearnCV_write, erode_write1, struct1);erode(LearnCV_write, erode_write2, struct2);imshow("LearnCV_write", LearnCV_write);imshow("erode_write1", erode_write1);imshow("erode_write2", erode_write2);//验证腐蚀对小连通域的去除Mat img = imread("rice.png");if (img.empty()){cout << "请确认图像文件名称是否正确" << endl;return -1;}Mat img2;copyTo(img, img2, img);  //克隆一个单独的图像,用于后期图像绘制Mat rice, riceBW;//将图像转成二值图像,用于统计连通域cvtColor(img, rice, COLOR_BGR2GRAY);threshold(rice, riceBW, 50, 255, THRESH_BINARY);Mat out, stats, centroids;//统计图像中连通域的个数int number = connectedComponentsWithStats(riceBW, out, stats, centroids, 8, CV_16U);cout << "未腐蚀:" << number << endl; // 27drawState(img, number, centroids, stats, "未腐蚀时统计连通域");  //绘制图像erode(riceBW, riceBW, struct1);  //对图像进行腐蚀number = connectedComponentsWithStats(riceBW, out, stats, centroids, 8, CV_16U);cout << "腐蚀后:" << number << endl; // 26drawState(img2, number, centroids, stats, "腐蚀后统计连通域");  //绘制图像waitKey(0);return 0;
}

在这里插入图片描述

在这里插入图片描述

1.2膨胀

图像膨胀(Image dilation)是一种图像处理操作,通常用于增加图像中物体的大小或填充物体的空隙,其目标是扩展和增强图像中的图形特征。

在定义结构元素之后,将结构元素的中心点依次放到图像中每一个非零元素处,如果原图中某个元素被结构元素覆盖,但是该像素的像素值不与结构元素中心点对应的像素点的像素值相同,那么将原图中该像素的像素值修改为结构元素中心点对应点的像素值。(将结构元素覆盖的所有区域,修改为1)

OpenCV提供了 dilate() 函数用于图像膨胀。

void dilate(InputArray src, OutputArray dst, InputArray kernel,Point anchor = Point(-1,-1), int iterations = 1,int borderType = BORDER_CONSTANT,const Scalar& borderValue = morphologyDefaultBorderValue()
);

该函数用法同 erode() 。第三个参数是结构元素尺寸,在图像膨胀操作中,结构元素的形状和大小起着关键作用。较大的结构元素将导致更强的膨胀效果,而较小的结构元素则会产生细微的膨胀效果。第五个参数是使用结构元素膨胀的次数,膨胀次数越多效果越明显。

需要注意的是,该函数的膨胀过程只针对图像中的非零像素,因此如果图像是以0像素为背景(黑底),那么膨胀操作后会看到图像中的内容变得更粗和更大;如果图像是以255像素为背景(白底),那么膨胀操作后看到的图像中的内容变得更细和更小。(与上面的腐蚀相反)

下面代码示例,代码最后为了验证膨胀与腐蚀效果之间的关系,求取黑色背景图像的复试结果与白色背景图像的膨胀结果进行逻辑“与”、“异或”运算,证明两个过程的相反性。

#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no logusing namespace cv;
using namespace std;int main()
{cout << "OpenCV Version: " << CV_VERSION << endl;utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);//生成用于腐蚀的原图像Mat src = (Mat_<uchar>(6, 6) <<0, 0, 0, 0, 255, 0,0, 255, 255, 255, 255, 255,0, 255, 255, 255, 255, 0,0, 255, 255, 255, 255, 0,0, 255, 255, 255, 255, 0,0, 0, 0, 0, 0, 0);Mat struct1, struct2;struct1 = getStructuringElement(0, Size(3, 3));  //矩形结构元素struct2 = getStructuringElement(1, Size(3, 3));  //十字结构元素Mat erodeSrc;  //存放膨胀后的图像dilate(src, erodeSrc, struct2);namedWindow("src", WINDOW_GUI_NORMAL);namedWindow("dilateSrc", WINDOW_GUI_NORMAL);imshow("src", src);imshow("dilateSrc", erodeSrc);Mat LearnCV_black = imread("black_white_handwritten.jpg", IMREAD_ANYCOLOR);Mat LearnCV_write = imread("white_black_handwritten.jpg", IMREAD_ANYCOLOR);if (LearnCV_black.empty() || LearnCV_write.empty()){cout << "请确认图像文件名称是否正确" << endl;return -1;}Mat dilate_black1, dilate_black2, dilate_write1, dilate_write2;//黑背景图像膨胀dilate(LearnCV_black, dilate_black1, struct1);dilate(LearnCV_black, dilate_black2, struct2);imshow("LearnCV_black", LearnCV_black);imshow("dilate_black1", dilate_black1);imshow("dilate_black2", dilate_black2);//白背景图像膨胀dilate(LearnCV_write, dilate_write1, struct1);dilate(LearnCV_write, dilate_write2, struct2);imshow("LearnCV_write", LearnCV_write);imshow("dilate_write1", dilate_write1);imshow("dilate_write2", dilate_write2);//比较膨胀和腐蚀的结果Mat erode_black1, resultXor, resultAnd;erode(LearnCV_black, erode_black1, struct1);bitwise_xor(erode_black1, dilate_write1, resultXor);bitwise_and(erode_black1, dilate_write1, resultAnd);imshow("resultXor", resultXor);imshow("resultAnd", resultAnd);waitKey(0);return 0;
}

在这里插入图片描述

2.形态学应用

图像形态学腐蚀可以将细小的噪声区域去除,但是会将图像主要区域的面积缩小,造成主要区域的形状发生改变。图像形态学膨胀可以扩充每一个区域的面积,填充较小的空洞,但是会增加噪声的面积。根据两者的特性,将图像腐蚀和膨胀适当结合,便可以既去除图像中的噪声,又不缩小图像中主要区域的面积;既填充较小的空洞,又不增加噪声的面积。

2.1开运算

图像开运算可以去除图像中的噪声,消除较小连通域,保留较大连通域,同时能够在两个物体纤细的连接处将两个物体分离,并且在不明显改变较大连通区域面积的同时能够平滑连通域的边界。

开运算:先腐蚀,消除图像中的噪声和较小的连通域;后膨胀,弥补较大的连通域因腐蚀而造成的面积减小。

开运算是对图像腐蚀和膨胀的结合,OpenCV中没有通过只用于图像开运算的函数,而是提供了图像腐蚀和膨胀运算不同组合形式的 morphologyEx() 函数,以实现开运算、闭运算、形态学梯度、顶帽运算、黑帽运算以及击中击不中变换。

void morphologyEx(InputArray src, OutputArray dst,int op,  // 形态学操作类型标志,如下InputArray kernel, // 结构元素Point anchor = Point(-1,-1), int iterations = 1,// 处理次数int borderType = BORDER_CONSTANT,const Scalar& borderValue = morphologyDefaultBorderValue()
);

该函数根据结构元素对输入图像进行多种形态学操作,在处理多通道图像时,每个通道独立进行处理。

第三个参数是形态学操作类型的标志:

//! type of morphological operation
enum MorphTypes{MORPH_ERODE    = 0, //腐蚀MORPH_DILATE   = 1, //膨胀MORPH_OPEN     = 2, //开运算MORPH_CLOSE    = 3, //闭运算MORPH_GRADIENT = 4, //形态学梯度MORPH_TOPHAT   = 5, //顶帽运算MORPH_BLACKHAT = 6, //黑帽运算MORPH_HITMISS  = 7  //击中击不中bian
};

2.2闭运算

图像闭运算可以去除连通域内的小型空洞,平滑物体轮廓,连接两个临近的连通域。闭运算,先膨胀,填充连通域内小型空洞,扩大连通域边界,将临近的两个连通域连接;后腐蚀,减少由膨胀运算引起的连通域边界的扩大以及面积的增加。

闭运算是对图像膨胀和腐蚀的结合,可以使用 morphologyEx() 函数选择闭运算参数 MORPH_CLOSE 实现闭运算。

2.3形态学梯度

形态学梯度能够描述目标的边界,根据图象腐蚀和膨胀与原图之间的关系计算得到,形态学梯度可以分为基本梯度、内部梯度和外部梯度。

基本梯度:膨胀后图像与腐蚀后图像差值。

内部梯度:原图像与腐蚀后图像差值。

外部梯度:膨胀后图像与原图像差值。

OpenCV提供的 morphologyEx() 函数可以选择形态学梯度参数 MORPH_GRADIENT 实现图像的基本梯度。如果需要计算图像的内部梯度和外部梯度,需要自己通过程序实现。

2.4顶帽运算

顶帽运算是原图像与开运算结果之间的差值,往往用来分离比临近点亮一些的斑块。因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域。

顶帽先对图像进行开运算,之后用原图减去开运算计算的结果。使用 morphologyEx() 函数选择顶帽运算的参数 MORPH_TOPHAT

2.5黑帽运算

与顶帽运算不同,黑帽运算是原图像与闭运算结果之间的差值,往往用来分离比邻近点暗一些的斑块。黑帽运算先对图像进行闭运算,之后从闭运算结果减去原图。使用 morphologyEx() 函数选择黑帽运算的参数 MORPH_BLACKHAT

2.6击中击不中变换

击中击不中变换(Hit-or-Miss Transform)利用两个结构元素,一个称为"击中"元素(Hit element),另一个称为"不中"元素(Miss element)。

击中击不中变换的目的是通过将击中元素与图像进行腐蚀(erosion)操作和将不中元素与图像进行膨胀(dilation)操作,来检测指定形状在图像中的位置。

输出图像中的白色像素表示原始图像中存在与击中元素形状相匹配的区域,黑色像素表示不匹配的区域。

使用 morphologyEx() 函数选择击中击不中变换的参数 MORPH_HITMISS

2.7形态学应用示例

//#include <opencv2/core.hpp>
//#include <opencv2/highgui.hpp>
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;int main()
{cout << "OpenCV Version: " << CV_VERSION << endl;utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);//用于验证形态学应用的二值化矩阵Mat src = (Mat_<uchar>(9, 12) <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);namedWindow("src", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸imshow("src", src);//3×3矩形结构元素Mat kernel = getStructuringElement(0, Size(3, 3));//对二值化矩阵进行形态学操作Mat open, close, gradient, tophat, blackhat, hitmiss;//对二值化矩阵进行开运算morphologyEx(src, open, MORPH_OPEN, kernel);namedWindow("open", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸imshow("open", open);//对二值化矩阵进行闭运算morphologyEx(src, close, MORPH_CLOSE, kernel);namedWindow("close", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸imshow("close", close);//对二值化矩阵进行梯度运算morphologyEx(src, gradient, MORPH_GRADIENT, kernel);namedWindow("gradient", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸imshow("gradient", gradient);//对二值化矩阵进行顶帽运算morphologyEx(src, tophat, MORPH_TOPHAT, kernel);namedWindow("tophat", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸imshow("tophat", tophat);//对二值化矩阵进行黑帽运算morphologyEx(src, blackhat, MORPH_BLACKHAT, kernel);namedWindow("blackhat", WINDOW_NORMAL);   //可以自由调节显示图像的尺寸imshow("blackhat", blackhat);//对二值化矩阵进行击中击不中变换morphologyEx(src, hitmiss, MORPH_HITMISS, kernel);namedWindow("hitmiss", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸imshow("hitmiss", hitmiss);//用图像验证形态学操作效果Mat keys = imread("keys.jpg", IMREAD_GRAYSCALE);imshow("原图像", keys);threshold(keys, keys, 80, 255, THRESH_BINARY);imshow("二值化后的keys", keys);//5×5矩形结构元素Mat kernel_keys = getStructuringElement(0, Size(5, 5));Mat open_keys, close_keys, gradient_keys, tophat_keys, blackhat_keys, hitmiss_keys;//对图像进行开运算morphologyEx(keys, open_keys, MORPH_OPEN, kernel_keys);imshow("open_keys", open_keys);//对图像进行闭运算morphologyEx(keys, close_keys, MORPH_CLOSE, kernel_keys);imshow("close_keys", close_keys);//对图像进行梯度运算morphologyEx(keys, gradient_keys, MORPH_GRADIENT, kernel_keys);imshow("gradient_keys", gradient_keys);//对图像进行顶帽运算morphologyEx(keys, tophat_keys, MORPH_TOPHAT, kernel_keys);imshow("tophat_keys", tophat_keys);//对图像进行黑帽运算morphologyEx(keys, blackhat_keys, MORPH_BLACKHAT, kernel_keys);imshow("blackhat_keys", blackhat_keys);//对图像进行击中击不中变换morphologyEx(keys, hitmiss_keys, MORPH_HITMISS, kernel_keys);imshow("hitmiss_keys", hitmiss_keys);int k = waitKey(0); // Wait for a keystroke in the windowreturn 0;
}

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

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

相关文章

华为eNSP配置专题-VRRP的配置

文章目录 华为eNSP配置专题-VRRP的配置0、参考文档1、前置环境1.1、宿主机1.2、eNSP模拟器 2、基本环境搭建2.1、基本终端构成和连接 2.VRRP的配置2.1、PC1的配置2.2、接入交换机acsw的配置2.3、核心交换机coresw1的配置2.4、核心交换机coresw2的配置2.5、配置VRRP2.6、配置出口…

C++多态、虚函数、纯虚函数、抽象类

多态的概念 通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 举个简单的例子&#xff1a;抢红包&#xff0c;我们每个人都只需要点击一下红包&#xff0c;就会抢到金额。有些人能…

OpenCV中world模块介绍

OpenCV中有很多模块&#xff0c;模块间保持最小的依赖关系&#xff0c;用户可以根据自己的实际需要链接相关的库&#xff0c;而不需链接所有的库&#xff0c;这样在最终交付应用程序时可以减少总库的大小。但如果需要依赖OpenCV的库太多,有时会带来不方便&#xff0c;此时可以使…

vue2 element手术麻醉信息系统源码,手术预约、手术安排、排班查询、手术麻醉监测、麻醉记录单

手术麻醉临床信息系统有着完善的临床业务功能&#xff0c;能够涵盖整个围术期的工作&#xff0c;能够采集、汇总、存储、处理、展现所有的临床诊疗资料。通过该系统的实施&#xff0c;能够规范麻醉科的工作流程&#xff0c;实现麻醉手术过程的信息数字化&#xff0c;自动生成麻…

mac 升级node到指定版本

node版本14.15.1升级到最新稳定版18.18.2 mac系统 先查看一下自己的node版本 node -v开始升级 第一步 清除node的缓存 sudo npm cache clean -f第二步 安装n模块【管理模块 n是管理 nodejs版本】 sudo npm install -g n第三步升级node sudo n stable // 把当前系统的 Node…

计算机毕业设计 基于SpringBoot智慧养老中心管理系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

【趣味随笔】盘点国内外做双足机器人的公司

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

leetCode 392. 判断子序列 动态规划 + 优化空间 / 双指针 等多种解法

392. 判断子序列 - 力扣&#xff08;LeetCode&#xff09; 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c…

Aocoda-RC F405V2 FC(STM32F405RGT6 v.s. AT32F435RGT7) IO Definitions

[TOC](Aocoda-RC F405V2 FC(STM32F405RGT6 v.s. AT32F435RGT7) IO Definitions) 1. 源由 Aocoda-RC F405V2飞控支持betaflight/inav/Ardupilot固件&#xff0c;是一款固件兼容性非常不错的开源硬件。 之前我们对比过STM32F405RGT6 v.s. AT32F435RGT7 Comparison for Flight …

ThreadLocal源码解密

1 背景 作为一只懒懒地程序员,其实我是不太爱看源码的,晦涩、深奥、难懂、耗费时间等等,就觉得不是我这种能力平平地小老百姓能吃得消的,但现实比人强,记得曾经我就被不懂原理的情况下乱用ThreadLocal给毒打了。 犹记得当时在一个JSF服务中的责任链的校验场景中需要在源…

UART、SPI、I2C通信协议超全入门教程

本文引注: https://mp.weixin.qq.com/s/lVWK8xlDt7cOLi8WHYSuPg 1.SPI协议 1.基础 2.简介 3.工作原理 4.SPI数据传输步骤与优缺点 2.UART协议

分布式微服务技术栈-SpringCloud<Eureka,Ribbon,nacos>

微服务技术栈 一、微服务 介绍了解1 架构结构案例与 springboot 兼容关系拆分案例拆分服务拆分-服务远程调用 2 eureka注册中心Eureka-提供者与消费者Eureka-eureka原理分析Eureka-搭建eureka服务Eureka-服务注册Eureka-服务发现 3 Ribbon组件 负载均衡Ribbon-负载均衡原理Ribb…

python随手小练6

1、汉诺塔 汉诺塔&#xff1a;汉诺塔&#xff08;又称河内塔&#xff09;问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放…

ubuntu终端命令行下如何使用NetworkManager(netplan)来配置wifi网络

最近在给家里折腾一个文件共享服务器给家里的小米摄像头保存监控视频用。树莓派太贵了&#xff0c;找来找去发现香橙派orangepi zero3 是最低成本的替代解决方案&#xff08;网络足够快&#xff0c;CPU的IO能力足够强&#xff09;&#xff0c;香橙派orangepi zero3的操作系统是…

学信息系统项目管理师第4版系列33_信息化发展

1. 企业信息化发展战略要点 1.1. 【高22下选12】 1.2. 以信息化带动工业化 1.3. 信息化与企业业务全过程的融合、渗透 1.4. 信息产业发展与企业信息化良性互动 1.5. 充分发挥政府的引导作用 1.6. 高度重视信息安全 1.7. 企业信息化改组改造和形成现代企业制度有机结合 …

虚拟化、容器与Docker基本介绍以及安装部署(Docker 基本管理)

目录 1 Docker 概述 1.1 Docker与虚拟机的区别 1.2 容器在内核中支持2种重要技术 1.3 Docker核心概念 2 安装 Docker 2 Docker 镜像操作 2.1 搜索镜像 2.2 获取镜像 2.3 镜像加速下载 2.4 查看镜像信息 2.4.1 查看下载的镜像文件信息 2.4.2 查看下载到本地的所有镜像…

RabbitMQ队列及交换机的使用

目录 一、简单模型 1、首先控制台创建一个队列 2、父工程导入依赖 3、生产者配置文件 4、写测试类 5、消费者配置文件 6、消费者接收消息 二、WorkQueues模型 1、在控制台创建一个新的队列 2、生产者生产消息 3、创建两个消费者接收消息 4、能者多劳充分利用每一个消…

400 The plain HTTP request was sent to HTTPS port

接口请求发生问题&#xff1a; 解决方法&#xff1a; Nginx HTTP服务器的报错 “400 Bad Request: The plain HTTP request was sent to HTTPS port”&#xff0c;本文将讲解如何解决这个问题。简单从报错的字面意思上来看&#xff0c;是因为HTTP请求被发送到HTTPS端口&#x…

CRM自动化意味着什么?企业如何从中受益?

客户关系管理&#xff08;CRM&#xff09;软件不再仅仅适用于大公司或销售周期长的行业&#xff0c;它越来越成为各种规模企业的重要工具。 在日常工作中&#xff0c;当你陷入流程的所有细节时&#xff0c;可能会产生不必要的工作。因此&#xff0c;如果你想要CRM提供的组织和…

【Javascript】基础数据类型

目录 基础数据类型 1.number 字面量声明 数字对象方式声明 整数判断 指定返回小数位数 NaN-表示非数字值 浮点精度 解决误差 String 字面量声明 数字对象声明 连接运算符 获取长度 大小写转换 转换成大写 转换成小写 ​编辑 移除空白 获取单字符 ​编辑 截…