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

图像分割算法

图像分割算法

  • 阈值分割
    • 固定阈值
    • 自适应阈值
    • 大津阈值(OTSU)
    • 最大熵阈值
  • 连通域分析
  • 区域生长
  • 分水岭

阈值分割、连通域分析、区域生长、分水岭

阈值分割

固定阈值、自适应阈值(adaptiveThreshold)、大津阈值(OTSU)、最大熵阈值(KSW)

固定阈值

固定阈值的调用函数:

//InputArray类型的src,输入图像。
//OutputArray类型的dst,输出图像。
//double类型的thresh,阈值的具体值。
//double类型的maxval,阈值最大值。
//int类型的type,阈值操作的类型,包括:
//THRESH_BINARY(标准的二值化阈值法,大于thresh的设为maxval,小于的设为0),
//THRESH_BINARY_INV(反向二值化),
//THRESH_TRUNC(截断阈值法,大于thresh的设为thresh,小于则不变),
//THRESH_TOZERO(零化阈值法,大于thresh的不变,小于则零化),
//THRESH_TOZERO_INV(反向零化),
//THRESH_OTSU(大津算法,适合双峰直方图的图像,通过分析最大的背景前景类间方差,自动调节阈值),
//THRESH_TRIANGLE(三角法,适合单峰直方图图像,建立谷底和峰顶直线,距离直线垂直距离最大的直方图位置,即阈值thresh)。
double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type );

固定阈值的使用非常简单,例如:

cv::Mat im = cv::imread("1.jpg");
cv::Mat imBin;
cv::threshold(im, imBin, 80, 255, cv::THRESH_BINARY);

意思就是:im图像中大于80的像素值直接置为255,否则置为0,并保存在imBin中。

自适应阈值

简单来讲:就是用一个blockSize*blockSize大小的核,在图像中按像素单位移动,计算每次移动过程中的加权均值作为阈值的参考值。

//参数1:要处理的原图
//参数2: 最大闯值,一般为255
//参数3: 小区域闽值的计算方式:
//ADAPTIVE THRESH MEAN C: 小区域内取均值
//ADAPTIVE THRESH GAUSSIAN C: 小区域内加权求和,权重是个高斯核
//参数4: 这是阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV。
//参数5: 小区域的面积,如11就是11*11的小块
//参数6: 最终闻值等于小区域计算出的闯值再减去此值
//特定: 自适应闽值会每次取图片的一小部分计算闽值,这样图片不同区域的闽值就不尽相同,适用于明暗分布不均的图片。
void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)

主要是用于光照变化明显的图像,但针对于一般场景的图像分割,效果往往不甚理想。
简单使用:

cv::Mat im = cv::imread("1.jpg");
cv::Mat imBin;
cv::adaptiveThreshold(im, imBin, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 21, 10);

稍加修改:

enum adaptiveMethod{meanFilter,gaaussianFilter,medianFilter};
void AdaptiveThreshold(cv::Mat& src, cv::Mat& dst, double Maxval, int Subsize, double c, adaptiveMethod method = meanFilter){if (src.channels() > 1)cv::cvtColor(src, src, CV_RGB2GRAY);cv::Mat smooth;switch (method){case  meanFilter:cv::blur(src, smooth, cv::Size(Subsize, Subsize));  //均值滤波break;case gaaussianFilter:cv::GaussianBlur(src, smooth, cv::Size(Subsize, Subsize),0,0); //高斯滤波break;case medianFilter:cv::medianBlur(src, smooth, Subsize);   //中值滤波break;default:break;} smooth = smooth - c;//阈值处理src.copyTo(dst);for (int r = 0; r < src.rows;++r){const uchar* srcptr = src.ptr<uchar>(r);const uchar* smoothptr = smooth.ptr<uchar>(r);uchar* dstptr = dst.ptr<uchar>(r);for (int c = 0; c < src.cols; ++c){if (srcptr[c]>smoothptr[c]){dstptr[c] = Maxval;}elsedstptr[c] = 0;}}
}

大津阈值(OTSU)

简单来讲就是利用类间方差的方式,找到背景和目标差异最大的阈值。因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。
OpenCV中也包含了大津阈值的的使用接口:

cv::Mat im = cv::imread("1.jpg");
cv::Mat imBin;
double thresh=0;
thresh = cv::threshold(im, imBin, thresh, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);

针对于一般的图像分割时,不会有太大的问题,但是如果是背景太多的图像,如下图所示:
在这里插入图片描述
采用上述方式得到的结果为:
在这里插入图片描述
不能将图像中的裂缝分割出来。其实那些黑色背景并不需要添加到大津阈值的计算当中,因此我们需要了解大津阈值的具体计算过程,并修改源代码。
OTSU算法的假设是存在阈值K将图像所有像素分为前景N1N_1N1(小于K)背景N2N_2N2(大于K)。假设图像大小为M*N,大于阈值K的像素为I1(x,y)I_1(x,y)I1(x,y),小于阈值K的像素为I2(x,y)I_2(x,y)I2(x,y)则这两类像素各自的均值就为m1m_1m1m2m_2m2
m1=∑I1(x,y)N1;m2=∑I2(x,y)N2{m_1} = \frac{{\sum {{I_1}(x,y)} }}{{{N_1}}}; {m_2} = \frac{{\sum {{I_2}(x,y)} }}{{{N_2}}}m1=N1I1(x,y);m2=N2I2(x,y)属于前景的概率P1P_1P1和属于背景的概率P2P_2P2分别为:
P1=N1M∗N;P2=N2M∗N{P_1} = \frac{{{N_1}}}{{{\rm{M*N}}}}; {P_2} = \frac{{{N_2}}}{{{\rm{M*N}}}}P1=MNN1;P2=MNN2且:
P1+P1=1{P_1}+{P_1} = 1P1+P1=1图像全局均值为mGm_GmG
mG=∑I(x,y)M∗N{m_G} = \frac{{\sum {{I}(x,y)} }}{{{M*N}}}mG=MNI(x,y)且:
P1m1+P1m2=mG{P_1}{m_1}+{P_1}{m_2} = {m_G}P1m1+P1m2=mG根据方差的概念,类间方差表达式为:
σ2=P1(m1−mG)2+P2(m2−mG)2{\sigma ^2} = {P_1}{({m_1} - {m_G})^2} + {P_2}{({m_2} - {m_G})^2} σ2=P1(m1mG)2+P2(m2mG)2背景和目标之间的类间方差越大,说明构成图像的两部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。
将上式稍微变形可以得到:
σ2=P1P2(m1−m2)2{\sigma ^2} = {P_1}{P_2}{({m_1} - {m_2})^2} σ2=P1P2(m1m2)2具体推到过程如下图所示:
请添加图片描述
照着公式,遍历0~255个灰度级,求出使上式类间方差最大灰度级作为 K值就可以了。但还可以对上式进行如下变化,使得式子更加简单,推到过程如下:
假设pip_ipi表示每个灰度级的概率(i=0~255),NiN_iNi表示每个灰度级的数量,N1iN_{1i}N1i表示前景部分每个灰度级的数量,N2iN_{2i}N2i表示背景部分每个灰度级的数量。
pi=NiM∗N{p_i} = \frac{{{N_i}}}{{M*N}}pi=MNNi因此可以得到:
P1=∑i=0Kpi,P2=∑i=K+1255pi{P_1} = \sum\limits_{i = 0}^K {{p_i}},{P_2} = \sum\limits_{i = K+1}^{255} {{p_i}}P1=i=0Kpi,P2=i=K+1255pim1=1/P1∗∑i=0Kipi=∑I1(x,y)N1{m_1} =1/{P_1} *\sum\limits_{i = 0}^K {{ip_i}}= \frac{{\sum {{I_1}(x,y)} }}{{{N_1}}}m1=1/P1i=0Kipi=N1I1(x,y)m2=1/P2∗∑i=K+1255ipi=∑I2(x,y)N2{m_2} =1/{P_2}* \sum\limits_{i = K+1}^{255} {i{p_i}}= \frac{{\sum {{I_2}(x,y)} }}{{{N_2}}}m2=1/P2i=K+1255ipi=N2I2(x,y)定义灰度级为K时前景的累加均值m为:
m=∑i=0Kipim=\sum\limits_{i = 0}^K {{ip_i}}m=i=0Kipi图像全局均值mG{m_G}mG又可以写为:mG=∑i=0255ipi=∑I(x,y)M∗N{m_G}=\sum\limits_{i = 0}^{255} {{ip_i}}= \frac{{\sum {{I}(x,y)} }}{{{M*N}}}mG=i=0255ipi=MNI(x,y)因此可以改写m1{m_1}m1m2m_2m2为:
m1=1/P1∗m{m_1}=1/{P_1}*mm1=1/P1mm2=1/P2∗(mG−m){m_2}=1/{P_2}*{({m_G}-m)}m2=1/P2(mGm)r然后可以将类间方差公式改写为:
σ2=(mG∗P1−m)2P1(1−P1){\sigma ^2} = \frac{{{{({m_G}*{P_1} - m)}^2}}}{{{P_1}(1 - {P_1})}} σ2=P1(1P1)(mGP1m)2具体推到过程如下图所示:
在这里插入图片描述
最后贴上代码

int Otsu(cv::Mat& src, cv::Mat& dst)
{const int Grayscale = 256;int graynum[Grayscale] = { 0 };int r = src.rows;int c = src.cols;double srcpixnum = 0;for (int i = 0; i < r; ++i){uchar* ptr = src.ptr<uchar>(i);for (int j = 0; j < c; ++j) {        //直方图统计if (ptr[j] == 0)  //不计算背景{ptr[j] = uchar(255); //背景变亮(根据实际情况而定)continue;}graynum[ptr[j]]++;srcpixnum++;}}double P[Grayscale] = { 0 };double PK[Grayscale] = { 0 };double MK[Grayscale] = { 0 };double sumtmpPK = 0, sumtmpMK = 0;for (int i = 0; i < Grayscale; ++i) {P[i] = graynum[i] / srcpixnum;   //每个灰度级出现的概率PK[i] = sumtmpPK + P[i];         //概率累计和 sumtmpPK = PK[i];MK[i] = sumtmpMK + i * P[i];       //灰度级的累加均值                                                                                                                                                                                                                                                                                                                                                                                                        sumtmpMK = MK[i];}//计算类间方差int thresh;double Var = 0;for (int k = 0; k < Grayscale; ++k) {if ((MK[Grayscale - 1] * PK[k] - MK[k])*(MK[Grayscale - 1] * PK[k] - MK[k]) / (PK[k] * (1 - PK[k])) > Var) {Var = (MK[Grayscale - 1] * PK[k] - MK[k])*(MK[Grayscale - 1] * PK[k] - MK[k]) / (PK[k] * (1 - PK[k]));thresh = k;}}//阈值处理dst = src.clone();for (int i = 0; i < r; ++i) {uchar* ptr = dst.ptr<uchar>(i);for (int j = 0; j < c; ++j){if (ptr[j] > thresh)  //大于阈值变暗(根据实际情况而定)ptr[j] = 0;elseptr[j] = 255;}}return thresh;
}

根据上述代码进行上面图像分割可以得到:
在这里插入图片描述

最大熵阈值

最大熵阈值分割法和OTSU算法类似,假设将图像分为背景和前景两个部分。熵代表信息量,图像信息量越大,熵就越大,最大熵算法就是找出一个最佳阈值使得背景与前景两个部分熵之和最大。

连通域分析

连通区域(Connected Component) 一般是指图像中具有相同像素值且位置相邻的前景像素点组成的图像区域,连通区域分析是指将图像中的各个连通区域找出并标记。在图像中,最小的单位是像素,每个像素周围有邻接像素,常见的连通关系有2种: 4连通与8连通。
在这里插入图片描述
在这里插入图片描述
如果A与B连通,B与C连通,则A与C连通,在视觉上看来,彼此连通的点形成了一个区域,而不连通的点形成了不同的区域。这样的一个所有的点彼此连通点构成的集合,我们称为一个连通区域。
在这里插入图片描述
4邻接,则有3个连通区域;8邻接,则有2个连通区域。

OpenCV的连通与分析,参考上面链接。这里简单介绍一下Two-Pass算法。两遍扫描法( Two-Pass ),正如其名,指的就是通过扫描两遍图像,将图像中存在的所有连通域找出并标记。

第一次扫描 :
从左上角开始遍历像素点,找到第一个像素为255的点label=1 ;
当该像素的左邻像素和上邻像素为无效值时,给该像素置个新的label值label ++,记录集合;
当该像素的左邻像素或者上邻像素有一个为有效值时,将有效值像素的label赋给该像素的label值 ;
当该像素的左邻像素和上邻像素都为有效值时,选取其中较小的label值赋给该像素的label值
在这里插入图片描述
第二次扫描 :
对每个点的label进行更新,更新为其对于其集合中最小的label
在这里插入图片描述

区域生长

基本思想是将具有相似性质的像素集合起来构成区域步骤 :

  1. 在图像中选取若干个种子点,将种子点存入vector中,vector中存储待生长的种子点;选取一个种子点(x0,y0);
  2. 以(x0,y0)为中心,考虑(x0,y0)的4邻域像素(x, y)如果(x0,y0)满足生长准则,将(x, y)与(x0,y0)合并(在同一区域内),同时将(x,y)压入堆栈;
  3. 从堆栈中取出一个像素,把它当作(x0,y0)返回到步骤2:
  4. 当堆栈为空时,返回到步骤1;
  5. 重复步骤1 - 4直到图像中的每个点都有归属时;
  6. 生长结束。
/***************************************************************************************
Function:  区域生长算法
Input:     src 待处理原图像 pt 初始生长点 th 生长的阈值条件
Output:    肺实质的所在的区域 实质区是白色,其他区域是黑色
Description: 生长结果区域标记为白色(255),背景色为黑色(0)
Return:    NULL
Others:    NULL
***************************************************************************************/
void RegionGrow(cv::Mat& src, cv::Mat& matDst, cv::Point2i pt, int th)
{cv::Point2i ptGrowing;							//待生长点位置int nGrowLable = 0;								//标记是否生长过int nSrcValue = 0;								//生长起点灰度值int nCurValue = 0;								//当前生长点灰度值matDst = cv::Mat::zeros(src.size(), CV_8UC1);	//创建一个空白区域,填充为黑色//生长方向顺序数据int DIR[8][2] = { { -1, -1 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 } };std::vector<cv::Point2i> vcGrowPt;				//生长点栈vcGrowPt.push_back(pt);							//将生长点压入栈中matDst.at<uchar>(pt.y, pt.x) = 255;				//标记生长点nSrcValue = src.at<uchar>(pt.y, pt.x);			//记录生长点的灰度值while (!vcGrowPt.empty())						//生长栈不为空则生长{pt = vcGrowPt.back();						//取出一个生长点vcGrowPt.pop_back();//分别对八个方向上的点进行生长for (int i = 0; i < 8; ++i){ptGrowing.x = pt.x + DIR[i][0];ptGrowing.y = pt.y + DIR[i][1];//检查是否是边缘点if (ptGrowing.x < 0 || ptGrowing.y < 0 || ptGrowing.x >(src.cols - 1) || (ptGrowing.y > src.rows - 1))continue;nGrowLable = matDst.at<uchar>(ptGrowing.y, ptGrowing.x);		//当前待生长点的灰度值if (nGrowLable == 0)					//如果标记点还没有被生长{nCurValue = src.at<uchar>(ptGrowing.y, ptGrowing.x);if (abs(nSrcValue - nCurValue) < th)					//在阈值范围内则生长{matDst.at<uchar>(ptGrowing.y, ptGrowing.x) = 255;		//标记为白色vcGrowPt.push_back(ptGrowing);					//将下一个生长点压入栈中}}}}
}

分水岭

分水岭算法步骤:
1、加载原始图像
2、闽值分割,将图像分割为黑白两个部分
3、对图像进行开运算,即先腐蚀在膨胀
4、对开运算的结果再进行 膨胀,得到大部分是背景的区域
5、通过距离变换 Distance Transform 获取前景区域
6、背景区域sure bg 和前景区域sure fg相减,得到即有前景又有背景的重合区域
7、连通区域处理
8、最后使用分水岭算法
一个使用分水岭算法的例子:

//分水岭算法
Mat WaterSegment(Mat src) {int row = src.rows;int col = src.cols;//1. 将RGB图像灰度化Mat grayImage;cv::cvtColor(src, grayImage, cv::COLOR_BGR2GRAY);//2. 使用大津法转为二值图,并做形态学闭合操作threshold(grayImage, grayImage, 0, 255, THRESH_BINARY | THRESH_OTSU);//3. 形态学闭操作Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);//4. 距离变换distanceTransform(grayImage, grayImage, DIST_L2, DIST_MASK_3, 5);//5. 将图像归一化到[0, 1]范围normalize(grayImage, grayImage, 0, 1, NORM_MINMAX);//6. 将图像取值范围变为8位(0-255)grayImage.convertTo(grayImage, CV_8UC1);//7. 再使用大津法转为二值图,并做形态学闭合操作threshold(grayImage, grayImage, 0, 255, THRESH_BINARY | THRESH_OTSU);morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);//8. 使用findContours寻找marksvector<vector<Point>> contours;findContours(grayImage, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));Mat marks = Mat::zeros(grayImage.size(), CV_32SC1);for (size_t i = 0; i < contours.size(); i++){//static_cast<int>(i+1)是为了分水岭的标记不同,区域1、2、3...这样才能分割drawContours(marks, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i + 1)), 2);}//9. 对原图做形态学的腐蚀操作Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));morphologyEx(src, src, MORPH_ERODE, k);//10. 调用opencv的分水岭算法watershed(src, marks);//11. 随机分配颜色vector<Vec3b> colors;for (size_t i = 0; i < contours.size(); i++) {int r = theRNG().uniform(0, 255);int g = theRNG().uniform(0, 255);int b = theRNG().uniform(0, 255);colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));}// 12. 显示Mat dst = Mat::zeros(marks.size(), CV_8UC3);int index = 0;for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {index = marks.at<int>(i, j);if (index > 0 && index <= contours.size()) {dst.at<Vec3b>(i, j) = colors[index - 1];}else if (index == -1){dst.at<Vec3b>(i, j) = Vec3b(255, 255, 255);}else {dst.at<Vec3b>(i, j) = Vec3b(0, 0, 0);}}}return dst;
}

总结:个人觉得分水岭算法其实很依赖图像阈值分割算法的处理效果,然后就是轮廓检测,这两步没处理好的话,后续效果也一般。
参考:https://blog.csdn.net/just_sort/article/details/87376355

相关文章:

图像分割算法

图像分割算法阈值分割固定阈值自适应阈值大津阈值(OTSU)最大熵阈值连通域分析区域生长分水岭阈值分割、连通域分析、区域生长、分水岭 阈值分割 固定阈值、自适应阈值(adaptiveThreshold)、大津阈值(OTSU)、最大熵阈值(KSW) 固定阈值 固定阈值的调用函数&#xff1a; //Input…...

《mysql技术内幕:innodb存储引擎》笔记

任何时候Why都比What重要&#xff1b;不要相信任何的“神话”,学会自己思考&#xff1b;不要墨守成规,大部分人都知道的事情可能是错误的&#xff1b;不要相信网上的传言,去测试,根据自己的实践做出决定&#xff1b;花时间充分地思考,敢于提出质疑。1.MYSQL被设计为一个单进程多…...

windows与linux系统ntp服务器配置

一. windows 打开windows终端&#xff08;管理员&#xff09;&#xff0c;顺序输入以下指令 net stop w32time w32tm /unregister w32tm /register net start w32time w32tm /resync net stop w32time net start w32timewin r 输入regedit&#xff0c;打开注册表。 ①将HKEY_…...

html常用font-family设置字体样式

<table border"1" cellpadding"0" cellspacing"0" ><tr><td><h3 style"font-family: 黑体;">黑体&#xff1a;SimHei</h3></td><td><h3 style"font-family: 华文黑体;">华…...

数据库事务AICD以及隔离级别

目录一.事务的ACID二.隔离级别三.并发事务中的问题1.脏写2.脏读3.不可重复读4.幻读四.MVCC机制五.读锁与写锁六.大事务的影响七.事务优化一.事务的ACID 原子性(Atomicity)&#xff1a;一个事务中的所有操作&#xff0c;要么全部成功&#xff0c;要么失败全部回滚&#xff0c;不…...

(4)VScode之ssh基础配置

VScode和SSH基础配置问题集合 Author&#xff1a;onceday date&#xff1a;2022年8月31日 本文记录linux的ssh和vscode开发环境搭建之路。 参考文档&#xff1a; 离线安装vscode Once Day CSDN博客关于x86、x86_64/x64、amd64和arm64/aarch64 Bogon 简书arm64和aarch64之间…...

springcloud-1环境搭建、service provider

搭建项目环境创建新项目&#xff0c;选择archetype-webapp&#xff0c;创建一个父项目&#xff0c;该父项目会去管理多个微服务模块(module)项目设置Settings->Editor->File Encoding:Global/Project Encoding 改为UTF-8Default encoding for properties files:默认属性文…...

光谱仪工作过程及重要参数定义

标题光谱仪工作过程CCD、PDA薄型背照式BT-CCD狭缝Slit暗电流Dark Current分辨率Resolution色散Dispersion光栅和闪耀波长Grating波长精度、重复性和准确度Precision带宽Band widthF数F/#光谱仪工作过程 CCD、PDA 电荷耦合器件&#xff08;Charger Coupled Device&#xff0c;缩…...

W800|iot|HLK-W800-KIT-PRO|AliOS|阿里云| |官方demo|学习(1):板载AliOS系统快速上手

板载系统简介 HLK-W800-KIT-PRO 是海凌科电子面向开发者&#xff0c;采用了联盛德 w800 方案&#xff0c;带有一个RGB三色灯&#xff0c;集成了 CHT8305C 温湿度传感器的多功能开发板&#xff0c;用户可以在上面学习、研究嵌入式系统和物联网产品的开发&#xff0c;本套设备运行…...

字节终面,一道Linux题难住我了

以下是一道难道系数中高并且高频出现的linux面试题&#xff0c;题目具体要求如下&#xff1a; linux面试题&#xff1a; 某文件有多列数据&#xff0c;空格隔开&#xff0c;统计第n列单词&#xff0c;打印出现频率最高的5个单词。 解答这道面试题需要用到3个linux命令&#xff…...

三、NetworkX工具包实战2——可视化【CS224W】(Datawhale组队学习)

开源内容&#xff1a;https://github.com/TommyZihao/zihao_course/tree/main/CS224W 子豪兄B 站视频&#xff1a;https://space.bilibili.com/1900783/channel/collectiondetail?sid915098 斯坦福官方课程主页&#xff1a;https://web.stanford.edu/class/cs224w NetworkX…...

【MySQL】MySQL 架构

一、MySQL 架构 C/S 架构&#xff0c;即客户端/服务器架构。服务器程序直接和我们存储的数据打交道&#xff0c;多个客户端连接这个服务器程序。客户端发送请求&#xff0c;服务器响应请求。 MySQL 数据库实例 &#xff1a;即 MySQL 服务器的进程 &#xff08;我们使用任务管理…...

Python日期时间模块

Python 提供了 日期和时间模块用来处理日期和时间&#xff0c;还可以用于格式化日期和时间等常见功能。 时间间隔是以秒为单位的浮点小数。每个时间戳都以自从 1970 年 1 月 1 日午夜&#xff08;历元&#xff09;经过了多长时间来表示。 一、time模块使用 Time 模块包含了大…...

学以致用——植物信息录入1.0(selenium+pandas+os+tkinter)

目的 书接上文&#xff0c;学以致用——植物信息录入&#xff08;seleniumpandasostkinter) 更新要点&#xff1a; tkinter界面&#xff1a;自动登录、新增&#xff08;核心功能&#xff09;、文件夹选择、流程台selenium自动化操作&#xff1a;验证码识别excel数据&#xf…...

什么是压敏电阻

下面的这些都是压敏电阻&#xff0c;常常用在一些电源和信号的浪涌防护电路中。这个是它的电路符号&#xff0c;电路中常用RV表示。当压敏电阻两端电压小于压敏电压时&#xff0c;压敏电阻相当于一个阻值非常大的电阻。当压敏电阻两端电压大于压敏电压时&#xff0c;压敏电阻相…...

Leetcode.901 股票价格跨度

题目链接 Leetcode.901 股票价格跨度 Rating &#xff1a; 1709 题目描述 设计一个算法收集某些股票的每日报价&#xff0c;并返回该股票当日价格的 跨度 。 当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数&#xff08;从今天开始往回数&#xff0c;…...

vue入门(四)组件基础,$emits简单用法

上一篇&#xff1a;vue入门&#xff08;三&#xff09;事件&#xff08;方法&#xff09;处理、侦听器、模板引用 1.组件最基础的用法&#xff1a; 首先有一个button.vue的组件&#xff0c;里面只画了一个按钮 button.vue: <script> export default({data(){return{but…...

VBA提高篇_27 OptionBOX_CheckBox_Frame_Image_VBA附加控件

文章目录1.单选按钮OptionBOX:2.复选框CheckBox:3.框架Frame:4.图像Image: (loadPictrue)5. VBA附加控件:6. 适用于很多控件的重要属性:1.单选按钮OptionBOX: 默认时,同一窗体的所有单选按钮均属于同一组,只能选中一个 可通过Frame控件进行分组解决. 2.复选框CheckBox: 一次可以…...

STM32开发(11)----CubeMX配置独立看门狗(IWDG)

CubeMX配置独立看门狗&#xff08;IWDG&#xff09;前言一、独立看门狗的介绍二、实验过程1.STM32CubeMX配置独立看门狗2.代码实现3.硬件连接4.实验结果总结前言 本章介绍使用STM32CubeMX对独立看门狗定时器进行配置的方法。门狗本质上是一个定时器&#xff0c;提供了更高的安…...

医疗方案 | 星辰天合入选“2022智慧新医信优秀解决方案”

近日&#xff0c;由 HC3i数字医疗网主办的《数字化转型驱动下的医院高质量发展论坛》暨 2022 智慧新医信优秀解决方案发布仪式在线上召开。XSKY星辰天合的“智慧医疗软件定义数据基础设施”解决方案成功入选 2022 智慧新医信优秀解决方案&#xff0c;。此次论坛由 HC3i 数字医疗…...

delphi7 链表 使用方法

在 Delphi 中&#xff0c;链表是一种常见的数据结构&#xff0c;用于存储一系列的元素&#xff0c;其中每个元素都包含一个指向列表中下一个元素的引用。在 Delphi 7 中&#xff0c;你可以手动实现链表&#xff0c;或者使用一些现有的集合类&#xff0c;例如 TList 或者 TLinke…...

应用层协议:HTTPS

目录 HTTPS&#xff1a;超文本传输安全协议 1、概念 2、通信过程及关键技术 2.1 通信过程 1> TLS握手协商&#xff08;建立安全通道&#xff09; 2> 加密数据传输 2.2 关键技术 1> 对称加密算法 2> 非对称加密 3> 对称加密和非对称加密组合 4> 数…...

LeetCode 高频 SQL 50 题(基础版)之 【子查询】· 上

题目&#xff1a;1978. 上级经理已离职的公司员工 题解&#xff1a; select employee_id from Employees where salary<30000 and manager_id is not null and manager_id not in (select distinct employee_id from Employees ) order by employee_id题目&#xff1a;626.…...

Java八股文——MySQL篇

文章目录 Java八股文——MySQL篇慢查询如何定位慢查询&#xff1f;如何分析慢SQLExplain标准答案 索引索引类型索引底层数据结构什么是聚簇索引什么是非聚簇索引&#xff1f;&#xff08;二级索引&#xff09;&#xff08;回表&#xff09;聚集索引选取规则回表查询 什么是覆盖…...

api将token设置为环境变量

右上角 可以新增或者是修改当前的环境 环境变量增加一个token,云端值和本地值可以不用写 在返回token的接口里设置后执行操作&#xff0c;通常是登录的接口 右侧也有方法提示 //设置环境变量 apt.environment.set("token", response.json.data.token); 在需要传t…...

【选配电脑】CPU核显工作机控制预算5000

【选配电脑】CPU核显工作机控制预算5000 1.背景2.配置及估价3.选配的说明 1.背景 不需要独立显卡&#xff0c;内存&#xff0c;硬盘尽量大&#xff1b; 预算控制到5000&#xff0c; 主板型号&#xff0c;电源功率支持后续添加独立显卡。 时间节点&#xff1a;2025.06.07 2.配…...

快捷键的记录

下面对应的ATL数字 ATL4 显示编译输出 CTRL B 编译 CTRLR 运行exe 菜单栏 ALTF ALTE ALTB ALTD ALTH...

超大规模芯片验证:基于AMD VP1902的S8-100原型验证系统实测性能翻倍

引言&#xff1a; 随着AI、HPC及超大规模芯片设计需求呈指数级增长原型验证平台已成为芯片设计流程中验证复杂架构、缩短迭代周期的核心工具。然而&#xff0c;传统原型验证系统受限于单芯片容量&#xff08;通常<5000万门&#xff09;、多芯片分割效率及系统级联能力&#…...

数学复习笔记 27

前言 太难受了。因为一些事情。和朋友倾诉了一下&#xff0c;也没啥用&#xff0c;几年之后不知道自己再想到的时候&#xff0c;会怎么考虑呢。另外&#xff0c;笔记还是有框架一点比较好&#xff0c;这样比较有逻辑感受。不然太乱了。这篇笔记是关于线代第五章&#xff0c;特…...

鸿蒙PC,有什么缺点?

点击上方关注 “终端研发部” 设为“星标”&#xff0c;和你一起掌握更多数据库知识 价格太高&#xff0c;二是部分管理员权限首先&#xff0c;三对于开发者不太友好举个例子&#xff1a;VSCode的兼容性对程序员至关重要。若能支持VSCode&#xff0c;这台电脑将成为大多数开发者…...