Python+Dlib+OpenCV 개인 얼굴 변경 응용 프로그램 지능형 구현(딥 러닝 + 머신 비전)을 기반으로 모든 프로젝트 소스 코드 및 비디오 데모(상업용이 아닌 개인 학습용)를 포함합니다.

여기에 이미지 설명 삽입

머리말

이 프로젝트는 얼굴 인식의 사전 훈련 모델을 기반으로 Dlib에서 제공하는 기계 학습, 수치 계산, 그래프 모델 알고리즘 및 이미지 처리 기능을 사용하여 사진에서 얼굴을 바꾸는 기능을 구현하는 것을 목표로 합니다.

Dlib는 다양한 기계 학습 및 컴퓨터 비전 알고리즘을 제공하는 강력한 오픈 소스 라이브러리입니다. 이 프로젝트에서는 Dlib에서 사전 훈련된 얼굴 인식 모델을 사용하여 사진에서 얼굴 영역을 식별하고 찾습니다.

얼굴 인식 알고리즘을 사용하여 두 장의 사진에서 얼굴 특징점과 얼굴 윤곽을 얻을 수 있습니다. 그런 다음 이러한 특징점과 윤곽선 정보를 사용하여 얼굴 정렬 및 등록 작업을 수행할 수 있습니다.

등록 과정에서 한 사진의 얼굴 특징 및 얼굴 윤곽을 다른 사진의 해당 영역과 일치시킵니다. 두 사진의 얼굴 특징점을 정렬하여 두 사진의 얼굴 교환 효과를 얻을 수 있습니다.

이 프로젝트의 적용은 매우 흥미롭고 창의적입니다. 엔터테인먼트, 예술 창작, 가상 현실 및 기타 분야에서 사용할 수 있으며 사용자에게 재미 있고 상상력이 풍부한 공간을 제공합니다.

이 프로젝트는 개인 학습용으로만 사용되며 상업적이거나 불량한 분야에 적용하지 마십시오.

전반적인 디자인

이 부분에는 시스템의 전체 구조도와 시스템 흐름도가 포함됩니다.

시스템 전체 구조도

시스템의 전체 구조가 그림에 나와 있습니다.

여기에 이미지 설명 삽입

시스템 흐름도

시스템 흐름은 그림에 나와 있습니다.

여기에 이미지 설명 삽입

운영 환경

이 섹션에는 Python 환경 및 관련 라이브러리 패키지 설치가 포함됩니다.

파이썬 환경

Python 3.6 이상 구성이 필요하며 Anaconda를 Windows 환경에 다운로드하여 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 sourceforge 라이브러리에서 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 분석 방법은 두 모양을 정규화하는 것입니다. 수학적으로 말하면, Platts 분석은 모양 A에서 모양 B로의 아핀 변환을 찾기 위해 최소 제곱법을 사용하는 것입니다.

이제 두 개의 마커 매트릭스가 얻어졌으며 각 행에는 특정 얼굴 특징에 해당하는 좌표 세트가 있습니다. 다음 단계는 두 번째 벡터의 점에 최대한 가깝게 맞도록 첫 번째 벡터를 회전, 이동 및 크기 조정하는 방법을 알아내는 것입니다. 두 번째 이미지는 동일한 변환으로 첫 번째 이미지에 오버레이될 수 있습니다.

T, s 및 R을 찾으면 식 (1)의 결과가 최소화됩니다.

E = 최소 ⁡ ∑ i = 1 68 ∥ s R pit + T − qi T ∥ 2 E=\min \sum_{i=1}^{68} \| s Rp_i^t +T-q_i^T \|^2이자형=나는 = 168s R p+-2

매개변수의 의미는 다음과 같습니다.

s: 배율 인수.
R: 회전 행렬(벡터를 곱할 때 방향이 바뀌지만 크기는 변하지 않고 키랄성을 유지하는 행렬).
구덩이 p_i^t: 매칭할 그림에서 68점의 좌표 벡터를 추출합니다.
T: 번역 벡터.
qit q_i^t:: 기준영상은 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.])])

본질은 첫 번째 사진과 두 번째 사진이 최대한 겹치도록 첫 번째 사진을 스케일링, 회전 및 이동하여 아핀 변환 행렬을 얻는 것입니다. OpenCV의 cv2.warpAffine 함수를 연결하여 이미지 2를 이미지 1에 매핑합니다.

4. 이미지 혼합

마스크를 사용하여 서로 다른 영역을 표현하는데, 얼굴에 속하는 영역의 픽셀 값은 1, 얼굴에 속하지 않는 영역의 픽셀 값은 0입니다. 추출 시 원본 이미지에 마스크를 직접 곱하여 얼굴을 구하고 나머지 영역의 픽셀 값은 0, 원본 이미지에 1-마스크를 곱하면 얼굴 영역은 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의 좌표 공간으로 변환될 수 있습니다. 두 개의 마스크를 하나로 결합하는 아이디어는 이미지 2의 속성을 드러내면서 이미지 1이 가려지도록 하는 것입니다.

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) 가우시안 블러

픽셀 에너지가 높은 부분에 대해서는 가중 평균법을 사용하여 픽셀 값을 다시 계산하여 에너지가 낮은 값이 됩니다. 이미지의 경우 고주파 부분이 저역 통과 필터를 통과한 후 전체 이미지가 저주파가 되어 이미지가 흐려지는 현상을 가우시안 블러(Gaussian Blur)라고 합니다.

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을 여는 기능과 동일하며 네 번째 단계는 왼쪽 하단의 얼굴 변경 버튼을 클릭하여 얼굴을 변경하는 것입니다. 얼굴 변경을 클릭하면 현재 파일 디렉토리에 얼굴이 변경된 사진이 생성됩니다.

여기에 이미지 설명 삽입

프로젝트 소스코드 다운로드

자세한 내용은 내 블로그 리소스 다운로드 페이지를 참조하십시오.

기타 정보 다운로드

인공 지능 관련 학습 경로 및 지식 시스템에 대해 계속 배우고 싶다면 내 다른 블로그 " Heavy | 완전한 인공 지능 AI 학습-기본 지식 학습 경로, 모든 자료는 지불 없이 네트워크 디스크에서 직접 다운로드할 수 있습니다. " 이 블로그
는 Github의 잘 알려진 오픈 소스 플랫폼, AI 기술 플랫폼 및 Datawhale, ApacheCN, AI Youdao 및 Dr. Huang Haiguang 등 관련 분야의 전문가를 참조합니다. 약 100G 관련 자료가 있으며, 모든 친구를 도와주세요.

추천

출처blog.csdn.net/qq_31136513/article/details/131330665