基于Python+Dlib+OpenCV个人换脸应用智能实现(深度学习+机器视觉)含全部工程源码及视频演示(仅供个人学习,请勿商用)

news2024/11/17 21:38:56

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
    • Python 环境
    • 相关库包安装
  • 模块实现
    • 1. 准备数据
    • 2. 提取面部标记
    • 3. 调整脸部对齐
    • 4. 混合图像
    • 5. 校正颜色
    • 6. 转换函数
    • 7. 交互式界面设计
  • 系统测试
  • 工程源代码下载
  • 其它资料下载

在这里插入图片描述

前言

本项目利用Dlib提供的机器学习、数值计算、图模型算法和图像处理等功能,基于人脸识别的预训练模型,旨在实现照片换脸的功能。

Dlib是一个功能强大的开源库,提供了多种机器学习和计算机视觉算法。在本项目中,我们将利用Dlib中的人脸识别预训练模型,识别并定位照片中的人脸区域。

通过使用人脸识别算法,我们可以获取两张照片中的人脸特征点和面部轮廓。然后,利用这些特征点和轮廓信息,我们可以进行脸部的对齐和配准操作。

在配准过程中,我们将根据一个照片中的人脸特征点和面部轮廓,将其与另一张照片中的相应区域进行匹配。通过将两张照片的脸部特征点对齐,我们可以实现两张照片的换脸效果。

这个项目的应用非常有趣和有创造性。它可以用于娱乐、艺术创作、虚拟现实等领域,为用户提供一个有趣和想象力的空间。

本项目仅供个人学习使用,请勿应用于任何商业或者不良领域。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分包括 Python 环境、相关库包安装。

Python 环境

需要 Python 3.6 及以上配置,在 Windows 环境下载 Anaconda 完成 Python 所需环境的配置。

相关库包安装

完成该项目所需要的库文件有 OpenCV、dlib、numpy、sys、PIL、thikter、matplotlib。

dlib 是包含机器学习算法和工具的现代 C++工具包,用在 C++中创建解决现实问题的复杂软件。

OpenCV 是基于 BSD 许可(开源)发行的跨平台库,可以运行在 Linux、Windows、Android 和 Mac OS 操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Ruby、MATLAB 等语言接口,实现图像处理和计算机视觉方面的很多通用算法。

其中,Dlib 库文件需要在 https://pypi.org/project/dlib/19.1.0/#files 把 dlib-19.1.0-cp35-cp35m-win_amd64.whl 文件下载,在命令提示符中使用以下命令安装即可:

pip install dlib-19.1.0-cp35-cp35m-win_amd64.whl

其他所需要的库文件只用在命令提示符中使用 pip install 即可。

模块实现

本项目包括 7 个模块:准备数据、提取面部标记、调整脸部对齐、混合图像、校正颜色、转换函数、交互式界面设计,下面分别给出各模块的功能介绍及相关代码。

1. 准备数据

dlib.get_frontal_face_detector()是人脸检测器,检测图片中是否有人脸,返回一个矩形列表的人脸检测器。

dlib.shape_predictor(PREDICTOR_PATH)特征提取器,由人脸检测器提供的边界框作为算法输入,返回一个人脸关键点预测器。

采用官方提供的预训练模型,帮助开发者节省时间,从 Dlib sourseforge 库下载构建有 68 个特征点组成的人脸特征提取器:http://sourceforge.net/projects/dclib/files/dlib/v18.10/shape_predictor_68_face_landmarks.dat.bz2

相关代码如下:

PREDICTOR_PATH = "D:/HuanLian/model/shape_predictor_68_face_landmarks.dat"
FACE_POINTS = list(range(17, 68))
MOUTH_POINTS = list(range(48, 61))
RIGHT_BROW_POINTS = list(range(17, 22))
LEFT_BROW_POINTS = list(range(22, 27))
RIGHT_EYE_POINTS = list(range(36, 42))
LEFT_EYE_POINTS = list(range(42, 48))
NOSE_POINTS = list(range(27, 35))
JAW_POINTS = list(range(0, 17))
#划分68个点的每个点意味着什么部位,如第27~35的点(xi,yi)就是鼻子
ALIGN_POINTS = (LEFT_BROW_POINTS + RIGHT_EYE_POINTS + LEFT_EYE_POINTS + RIGHT_BROW_POINTS + NOSE_POINTS + MOUTH_POINTS)
#对齐图片的点,即五官
OVERLAY_POINTS = [LEFT_EYE_POINTS + RIGHT_EYE_POINTS + LEFT_BROW_POINTS + RIGHT_BROW_POINTS,NOSE_POINTS + MOUTH_POINTS,]
detector = dlib.get_frontal_face_detector()
#人脸检测器
predictor = dlib.shape_predictor(PREDICTOR_PATH)
#特征提取器

2. 提取面部标记

在预训练获取特征提取器后用户输入两个图像的人脸特征点,函数将一个图像转化成numpy 数组,并返回 68*2 元素矩阵,输入图像一张脸有 68 个特征点,每个特征点对应每行的 x、y 坐标。

class TooManyFaces(Exception):#设置检测到太多脸的类
     pass
class NoFaces(Exception):#设置没有检测到脸的类
     Pass
def get_landmarks(im):#获取人脸特征点,将图像转化成numpy数组,返回68*2元素矩阵
	#输入图像的每个特征点对应每行的x、y坐标
	rects = detector(im, 1)#每个矩形列表在图像中对应一个脸
	#rects表示人脸框的位置信息
	if len(rects) > 1: #如果识别的人脸数大于一个,引发TooManyFaces异常
		raise TooManyFaces
	if len(rects) == 0:#如果图片没人脸,引发NoFaces异常
		raise NoFaces
	return numpy.matrix([[p.x, p.y] for p in predictor(im, rects[0]).parts()])
#为加快计算,把得到的特征点转换成numpy矩阵
def read_im_and_landmarks(fname):#从计算机中读取用户所选的图片并提取特征点
	im = cv2.imread(fname, cv2.IMREAD_COLOR)#opencv读取图片并显示
	im = cv2.resize(im, (im.shape[1] * SCALE_FACTOR,
	                         im.shape[0] * SCALE_FACTOR))
	s = get_landmarks(im)
return im, s

3. 调整脸部对齐

Procrustes 分析方法是对两个形状进行归一化处理 。从数学上来讲,普氏分析就是利用最小二乘法寻找形状 A 到形状 B 的仿射变换。

现在已经获得两个标记矩阵,每行有一组坐标对应一个特定的面部特征。下一步要搞清如何旋转、翻译和规模化第一个向量,使它们尽可能适合第二个向量的点。可以用相同的变换在第 1 个图像上覆盖第 2 个图像。

寻找 T、s 和 R,令式(1)表达式的结果最小:

E = min ⁡ ∑ i = 1 68 ∥ s R p i t + T − q i T ∥ 2 E=\min \sum_{i=1}^{68} \| s Rp_i^t +T-q_i^T \|^2 E=mini=168sRpit+TqiT2

其中各参数含义如下:

s:缩放系数。
R:旋转矩阵(在乘以一个向量时改变方向,但不改变大小的效果并保持手性的矩阵)。
p i t p_i^t pit:待匹配的图片提取出 68 个点的坐标向量。
T:平移向量。
q i t q_i^t qit::基准图片提取 68 个点的坐标向量。

相关代码如下:

def transformation_from_points(points1, points2):
#普氏分析(Procrustes analysis)调整脸部,相同变换使两张照片面部特征相对距离尽可能小
#输入的自变量是两张图片特征点矩阵
	points1 = points1.astype(numpy.float64) #将输入矩阵转化为浮点数
	points2 = points2.astype(numpy.float64)
	c1 = numpy.mean(points1, axis=0) #按列求均值,即求样本点在图像中的均值
	c2 = numpy.mean(points2, axis=0)
	points1 -= c1 
	#对所有形状的大小进行归一化,将每个样本点减去对应均值,处理消除平移T的影响
	points2 -= c2
	s1 = numpy.std(points1)#求出每个点的标准差
	s2 = numpy.std(points2)
	points1 /= s1
	points2 /= s2 #每一个点集除以它的标准偏差,这一步处理消除缩放系数s的影响
	U, S, Vt = numpy.linalg.svd(points1.T * points2) #可以求解出R
	R = (U * Vt).T
	return numpy.vstack([numpy.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)), numpy.matrix([0., 0., 1.])])

实质就是将第一张图片进行放缩、旋转、平移,使第 1 张和第 2 张图片尽可能重合,得到一个仿射变换矩阵。插入 OpenCV 的 cv2.warpAffine 函数,将图像 2 映射到图像 1。

4. 混合图像

使用掩模(mask)表示不同区域,属于人脸区域像素值为 1,不属于人脸区域像素值为 0。在提取时直接将原图片乘以掩模,得到人脸,而其余区域像素值为 0;如果将原图片乘以1−mask,即人脸区域是 0,保留其余区域。上面两个结果相加,实现初步换脸。

1)凸包

在处理过程中,需要寻找图像中包围某个物体的凸包。凸包跟多边形相似,包围物体最外层的一个凸集,是所有能包围这个物体凸集的交集。如图所示,圆圈线条所包围的凸集即为凸包。

在这里插入图片描述

2)凸包实现

在 OpenCV 中,通过函数 convexHull 得到一系列点的凸包。例如,由点组成的轮廓,通过 convexHull 函数,得到轮廓的凸包:

def draw_convex_hull(im, points, color):#绘制凸包
	points = cv2.convexHull(points)
	#寻找图像的凸包,points就是输入的一组点
	cv2.fillConvexPoly(im, points, color=color)
	#cv2.fillConvexPoly()函数可以填充凸多边形,由凸包得到的轮廓点作为顶点

3)遮罩实现

def get_face_mask(im, landmarks):#为一张图像和一个标记矩阵生成一个遮罩
	#画出了两个凸多边形:一个是眼睛周围的区域,一个是鼻子和嘴部周围的区域
	im = numpy.zeros(im.shape[:2], dtype=numpy.float64)
	#numpy.zeros返回给定形状和类型的新数组,用0填充
	#img.shape[:2] 取彩色图片的高、宽
	for group in OVERLAY_POINTS:
		#OVERLAY_POINTS 定义为[LEFT_EYE_POINTS + RIGHT_EYE_POINTS + LEFT_BROW_POINTS + RIGHT_BROW_POINTS ,  NOSE_POINTS + MOUTH_POINTS,]
		#分为[眼睛周围、鼻子和嘴]两个区域,是第二张图片中要覆盖第一张图片的点
		draw_convex_hull(im,landmarks[group],color=1)
		#对图片中68特征点集里是OVERLAY_POINTS的点进行凸包绘制
		im = numpy.array([im, im, im]).transpose((1, 2, 0))
		im = (cv2.GaussianBlur(im, (FEATHER_AMOUNT, FEATHER_AMOUNT),0)>0)*1.0
		#高斯滤波
		im = cv2.GaussianBlur(im, (FEATHER_AMOUNT, FEATHER_AMOUNT), 0)
	return im

4)图像结合

一个遮罩同时为两个图像生成,可以使图像 2 的遮罩转化为图像 1 的坐标空间。将两个遮罩结合成一个,是为了确保图像 1 被掩盖,而显现出图像 2 的特性。

def warp_im(im, M, dshape):#得到了转换矩阵M后,使用它进行映射,OpenCV的cv2.warpAffine函数,将图像2映射到图像1
	output_im = numpy.zeros(dshape, dtype=im.dtype)
	#返回给定形状和类型的新数组,用0填充
	#将图像二映射到图像一
	cv2.warpAffine(im, #输入图像
					M[:2],#仿射矩阵
					(dshape[1], dshape[0]),
					dst=output_im,#输出图像
					borderMode=cv2.BORDER_TRANSPARENT,#边缘像素模式
					flags=cv2.WARP_INVERSE_MAP)#插值方法的组合
	return output_im

5. 校正颜色

由于两幅图像背景光照或者肤色等因素的影响,图片直接融合效果不理想 。实现思路是利用高斯模糊来帮助校正颜色。具体操作:用一个模板扫描图像中的每一个像素,用模板确定的邻域内像素加权平均灰度值去替代模板中心像素点的值。

1)高斯模糊

对于像素能量高的部分采取加权平均方法重新计算像素值,变成能量较低的值。对于图像而言其高频部分经过低通滤波器之后整幅图像变成低频造成图像模糊,被称为高斯模糊。

2)导入图片和具体实现

OpenCV 提供了 GaussianBlur()函数对图形进行高斯滤波。

def correct_colours(im1, im2, landmarks1):
	#修正两幅图像之间不同肤色和光线造成的覆盖区域边缘不连续
	blur_amount = COLOUR_CORRECT_BLUR_FRAC * numpy.linalg.norm(
	numpy.mean(landmarks1[LEFT_EYE_POINTS], axis=0) -
	numpy.mean(landmarks1[RIGHT_EYE_POINTS],axis=0))
	#numpy.mean求左右眼点集均值,其中axis=0,压缩行,对各列求均值,返回1*n矩阵
	#从左眼点集、右眼点集分别得到一个代表左眼和右眼的点,两者相减是左右眼横,纵相对距离
	#用numpy.linalg.norm得到矩阵所有元素平方和开根号,勾股定理,得到了两眼之间的距离
	#COLOUR_CORRECT_BLUR_FRAC*两眼距离作为高斯内核大小
	#内核太小,第一个图像的面部特征将显示在第二个图像中
	#内核过大,内核之外区域像素被覆盖并发生变色,COLOUR_CORRECT_BLUR_FRAC设置为0.6
	blur_amount = int(blur_amount)
	if blur_amount % 2 == 0:
		blur_amount += 1 #高斯内核大小不能是偶数
		im1_blur = cv2.GaussianBlur(im1, (blur_amount, blur_amount), 0)
		#用模板扫描图像中的每一个像素,确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值
	#高斯矩阵的长与宽是高斯内核(blur_amount)的大小,标准差取0,返回高斯滤波后的图像
	im2_blur = cv2.GaussianBlur(im2, (blur_amount, blur_amount), 0)
	im2_blur += (128 * (im2_blur <= 1.0)).astype(im2_blur.dtype)
	#防止除零,将高斯滤波后im2元素的数据类型返回,强制类型转换成数据类型
	return (im2.astype(numpy.float64) * im1_blur.astype(numpy.float64) /
	        im2_blur.astype(numpy.float64))
#试图改变图像2的颜色来匹配图像1,通过用im2*im1/im2的高斯模糊

6. 转换函数

以上所定义的函数均为转换函数作铺垫,相关代码如下:

def main():
	global image1,image2#将两张照片设置为全局变量,方便在各个函数中直接使用
	im1, landmarks1 = read_im_and_landmarks(image1)#提取图片1的特征点
	im2, landmarks2 = read_im_and_landmarks(image2)#提取图片2的特征点
	M = transformation_from_points(landmarks1[ALIGN_POINTS],
	                               landmarks2[ALIGN_POINTS])
	#普氏分析(Procrustes analysis)调整脸部,相同变换使两张照片面部特征的相对距离尽可能小
	mask = get_face_mask(im2, landmarks2)#为一张图像和一个标记矩阵生成一个遮罩
	warped_mask = warp_im(mask, M, im1.shape)
	#把图像2遮罩通过仿射矩阵M映射到图像1上
	combined_mask = numpy.max([get_face_mask(im1, landmarks1), warped_mask], axis=0)
	warped_im2 = warp_im(im2, M, im1.shape)#把图像2映射到遮好的图像1上
	warped_corrected_im2 = correct_colours(im1, warped_im2, landmarks1)#校正颜色
	output_im = im1 * (1.0 - combined_mask) + warped_corrected_im2 * combined_mask
	cv2.imwrite('output.jpg', output_im) #输出换脸后的照片

7. 交互式界面设计

#从计算机中选择原图1并展示
def show_original1_pic():
	global image1
	image1 = askopenfilename(title='选择文件') #将选择的图片作为待换脸图片
	print(image1)
	Img = PIL.Image.open(r'{}'.format(image1))
	Img = Img.resize((270,270),PIL.Image.ANTIALIAS)   
	img_png_original = ImageTk.PhotoImage(Img)
	label_Img_original1.config(image=img_png_original)
	label_Img_original1.image = img_png_original  #保持参考点
	cv_orinial1.create_image(5, 5,anchor='nw', image=img_png_original)
	
#从计算机中选择原图2并展示
def show_original2_pic():
	global image2
	image2 = askopenfilename(title='选择文件')#将选择的图片作为待换脸图片
	print(image2)
	Img = PIL.Image.open(r'{}'.format(image2))
	Img = Img.resize((270,270),PIL.Image.ANTIALIAS)  
	img_png_original = ImageTk.PhotoImage(Img)
	label_Img_original2.config(image=img_png_original)
	label_Img_original2.image = img_png_original  #keep a reference
	cv_orinial2.create_image(5, 5,anchor='nw', image=img_png_original)
	
#设置按钮,打开图片1并将其作为待替换图片
Button(root, text = "打开图片1", command = show_original1_pic).place(x=50,y=120)
#设置按钮,打开图片2并将其作为待替换图片
Button(root, text = "打开图片2", command = show_original2_pic).place(x=50,y=200)
#进行换脸
Button(root, text = "换脸!!", command = main).place(x=50,y=280)
#配置界面的一些细节,如边框、线条等
Label(root,text = "图片1",font=10).place(x=280,y=120)
cv_orinial1 = Canvas(root,bg = 'white',width=270,height=270)
cv_orinial1.create_rectangle(8,8,260,260,width=1,outline='red')
cv_orinial1.place(x=180,y=150)
label_Img_original1 = Label(root)
label_Img_original1.place(x=180,y=150)
Label(root,text="图片2",font=10).place(x=600,y=120)
cv_orinial2 = Canvas(root,bg = 'white',width=270,height=270)
cv_orinial2.create_rectangle(8,8,260,260,width=1,outline='red')
cv_orinial2.place(x=500,y=150)
label_Img_original2 = Label(root)
label_Img_original2.place(x=500,y=150)
root.mainloop()

系统测试

应用程序界面如图所示。左边有一列按钮,前两个按钮是打开图片 1。第一步,单击进入浏览页面,自行浏览计算机内的文件;第二步,选择换脸的照片;第三步,右边两个框,在图片 1 下方框内显示出自己刚选择的照片。同理,打开图片 2 功能和打开图片 1 一样;第四步,单击左边最下方的换脸按钮,进行换脸。单击换脸后,在当前文件目录下生成换脸后的图片。

在这里插入图片描述

工程源代码下载

详见本人博客资源下载页

其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

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

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

相关文章

Linux远程管理工具

在使用远程管理工具之前&#xff0c;应先设置宿主机 Windows 与虚拟机 Linux 能够连通。这里要注意 VMware 的网卡设置&#xff0c;Linux 中更改网络设置可以使用 ifconfig 和 setup 命令&#xff0c;若还是无法进行远程连接&#xff0c;要么就是 SSH 服务没有启动&#xff0c;…

Vlan(Access、Trunk、Hybrid)与ARP(免费ARP)讲解

目录 Vlan讲解 Vlan标签 二层接口类型 ARP ARP的作用 ARP地址解析报文讲解 免费ARP报文讲解 ARP缓存表 Vlan讲解 Vlan&#xff08;Virtual Local Area Network&#xff09;虚拟局域网&#xff0c;将一个物理的LAN在逻辑上划分为多个广播域&#xff1b;可以理解为一个V…

【MySql】MySql视图

文章目录 视图概念基本使用创建视图修改视图对基表有影响修改基表对视图有影响删除视图 视图规则和限制OJ题目 视图概念 视图就是一张虚拟表&#xff0c;其内容由查询定义。与真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化影响到基表&#xff0…

[Web程序设计]实验: 开发工具使用

一、实验目的 &#xff08;1&#xff09;掌握web应用运行所必须的服务端软件使用。 &#xff08;2&#xff09;掌握web应用开发所必须的开发工具使用。 二、实验内容 Tomcat的安装及使用&#xff1b;使用idea开发一个简单的web应用。 三、实验要求 &#xff08;1&#xf…

baichuan-7B的测试教程

1.百川模型介绍 baichuan-7B不仅在C-Eval、AGIEval和Gaokao中文权威评测榜单上,以显著优势全面超过了ChatGLM-6B等其他大模型,并且在MMLU英文权威评测榜单上,大幅领先LLaMA-7B。baichuan-7B是由百川智能开发的一个开源的大规模预训练模型。基于Transformer结构,在大约1.2万…

【Linux】详解进程控制 ( fork函数 | 写时拷贝 | 进程退出 | 进程等待 )

fork函数fork函数初识fork返回值问题fork常规用法 写时拷贝进程退出进程退出码进程退出场景进程如何退出 进程等待僵尸进程进程等待的方法 fork函数 fork函数初识 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而…

第42步 深度学习图像识别:Mobilenet建模(Tensorflow)

基于WIN10的64位系统演示 一、写在前面 &#xff08;1&#xff09;Mobilenet MobileNet是谷歌研究团队于2017年发布的一种轻量级的深度学习网络架构。这种架构特别适用于移动设备和嵌入式设备上&#xff0c;因为它的模型体积小&#xff0c;计算量少&#xff0c;但又能保持相…

无人船实时路径规划与编队控制仿真研究

源自&#xff1a;系统仿真学报 作者&#xff1a;宋大雷 干文浩 许嘤枝 曲秀青 曹江丽 摘 要 安全和无碰撞导航是无人船正常航行的基础。通过Unity3D构建高保真的虚拟海洋环境&#xff0c;在无人船建模基础上&#xff0c;提出一种面向未知复杂环境的实时路径规划及编队控…

系统空间数据库设计

文章目录 1 .空间数据库2. 空间数据库实体结构属性与空间数据库关联设计 1 .空间数据库 系统空间数据库存储电力管线设备和管网各业务图的地理空间信息&#xff0c; GIS 服务器GeoServer 通过读取空间数据库的实体表中的空间信息确定地物类的位置和几何形状&#xff0c;然后将…

全志V3S嵌入式驱动开发(spi-nor image制作和烧入)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 其实&#xff0c;我们之前就讨论过怎么把image烧入到v3s的spi-nor当中去。当时使用的方法是借助于sunxi-fel工具&#xff0c;烧入的image也比计较小…

重磅:微前端与模块联邦项目落地

微前端概念及诞生背景 微前端的出现背景可以追溯到大型前端应用的开发和维护过程中所面临的挑战和问题。 大型应用的复杂性&#xff1a;随着前端应用规模的扩大&#xff0c;应用的复杂性也增加。大型应用通常由多个团队协同开发&#xff0c;每个团队负责一部分功能模块&#x…

干货 | 智能网联车个人数据流通安全要求

以下内容整理自清华大学《数智安全与标准化》课程大作业期末报告同学的汇报内容。 我们对相关已有的标准规范进行调研&#xff0c;在工业和信息化部办公厅印发的《车联网网络安全和数据安全标准体系建设指南》中规定了六个部分的安全要求&#xff0c;我们做的主要是个人信息保护…

MaskFormer:将语义分割和实例分割作为同一任务进行训练

目标检测和实例分割是计算机视觉的基本任务&#xff0c;在从自动驾驶到医学成像的无数应用中发挥着关键作用。目标检测的传统方法中通常利用边界框技术进行对象定位&#xff0c;然后利用逐像素分类为这些本地化实例分配类。但是当处理同一类的重叠对象时&#xff0c;或者在每个…

c++11 标准模板(STL)(std::basic_streambuf)(五)

定义于头文件 <streambuf> template< class CharT, class Traits std::char_traits<CharT> > class basic_streambuf; 类 basic_streambuf 控制字符序列的输入与输出。它包含下列内容并提供到它们的访问&#xff1a; 1) 受控制字符序列&#xff…

【探索 Kubernetes|作业管理篇 系列 13】StatefulSet 拓扑状态

前言 大家好&#xff0c;我是秋意零。 在上一篇中&#xff0c;我们讲解了 Deployment 这种无状态的控制器&#xff1b;而如果要部署有状态的应用&#xff0c;那么 Deployment 显然是达不到我们的需求的。 今天讲解的是 StatefulSet 有状态控制器。 最近搞了一个扣扣群&…

电气照明节能设计在智能控制系统中的应用

【摘要】&#xff1a;随着社会的不断发展&#xff0c;经济水平也随之稳步提升&#xff0c;人们的消防意识也正在逐步加强&#xff0c;这就促进了消防应急照明系统的发展。当今社会,智能照明系统已经普及到家家户户&#xff0c;并在建筑工程中被广泛应用&#xff0c;同时其自身具…

【计算机网络自顶向下】计算机网络期末自测题(一)

前言 “(学不懂一点) &#xff08;阴暗的爬行&#xff09;&#xff08;尖叫&#xff09;&#xff08;扭曲&#xff09;&#xff08;阴暗的爬行&#xff09;&#xff08;尖叫&#xff09;&#xff08;扭曲&#xff09;&#xff08;阴暗的爬行&#xff09;&#xff08;尖叫&#…

非公平锁实现原理+源码解读

目录 非公平锁实现原理 加锁解锁流程 加锁源码 解锁源码 非公平锁实现原理 加锁解锁流程 先从构造器开始看&#xff0c;默认为非公平锁实现 public ReentrantLock() {sync new NonfairSync(); } NonfairSync 继承自 AQS 没有竞争时 第一个竞争出现时 Thread-1 执行了…

解决不允许一个用户使用一个以上用户名与一个服务器或共享资源的多重连接的问题

问题概述&#xff1a; 用windows server 2012 r2 vl x64搭了个文件服务器&#xff0c;在使用时有个问题&#xff0c;老是用户登录有问题&#xff0c;提示“不允许一个用户使用一个以上用户名与一个服务器或共享资源的多重连接”。出现的原因不详&#xff0c;网上也没查到合理的…

操作系统3:CPU任务调度和进程调度

目录 1、处理机调度的层次 &#xff08;1&#xff09;高级调度(High Level Scheduling) &#xff08;2&#xff09;低级调度(Low Level Scheduling) &#xff08;3&#xff09;中级调度(Intermediate Scheduling) 2、处理机调度算法的目标 批处理系统的目标 3、作业与作…