使用Python构建一个深度学习应用程序
在本教程中,我们将使用Mediapipe、Gradio和Python建立一个自拍的分割模型。
通过使用预先建立的机器学习模型,自拍分割模型可以让我们快速、轻松地从照片中剥离出背景。
前提条件
要完全理解本教程,你需要熟悉以下内容。
- Python编程语言
- [MediaPipe]
- [Gradio]
- [OpenCV]
你需要使用Jupyter Notebook或Google Colab。要跟上进度,请使用Google Colab。
简介
自拍的分割模型允许我们使用预先建立的机器学习模型快速而容易地从照片中剥离出背景。
它是基于改进的MobileNetV3。这是一个最先进的移动计算机视觉网络模型,速度是MobileNetV2模型的两倍。
该模型从图像/视频中分割出一个物体。这使得人们可以替换背景或对视频或图像应用效果。
该模型可以在智能手机和笔记本电脑上实时运行,其预期用例包括创建自拍效果和视频会议。
安装Mediapipe、Gradio、OpenCV和Matplotlib
Mediapipe 是一个免费和开源的机器学习(ML)管道,在Python和其他语言中提供预建的ML解决方案。
它提供的ML解决方案包括人脸检测、头发分割、物体检测和自拍分割。
这些ML解决方案可在安卓、iOS、桌面/云端、网络和物联网设备上运行。我们将使用Mediapipe来抓取自拍的分割模型。
Gradio 是一个允许我们在Jupyter Notebook/Google Colab内建立独立应用程序的库。在本教程中,我们将把我们的自拍模型整合到Gradio应用程序中。
OpenCV 是一个广泛使用的Python库,允许人们解决计算机视觉方面的任务。我们将使用这个库从我们的网络摄像头获取实时信息。
Matplotlib 是一个用于创建静态、动画和互动可视化的Python包。我们将使用它来实现我们的图像的可视化。
pip install gradio mediapipe opencv-python matplotlib
如果你使用的是Jupyter笔记本,请确保在pip 命令前包含一个感叹号! ,如下图所示。
!pip install gradio mediapipe opencv-python matplotlib
现在我们已经安装好了,我们需要把它们导入到我们的Colab中。
import mediapipe as mp
import cv2
import numpy as np
由于视频传输将是实时的,我们使用OpenCV来访问我们计算机的网络摄像头来转发传输。
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
cv2.imshow('Webcam feed', frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
这是使用OpenCV获取视频信号的标准方法。VideoCapture() 方法被用来创建一个视频捕获对象。
数字0 表示我们要使用一个网络摄像机。如果它没有选择你的网络摄像头或得到一个错误,试着把这个数字改为1 或2 。
一旦我们捕获了我们的视频设备,我们就使用while ,从我们的网络摄像头饲料中连续循环。
然后,这些捕获的feeds被解包并存储在ret 和frame 变量中。OpenCV的imshow() 方法然后用Webcam feed 将它们渲染在屏幕上。如果你愿意的话,你可以给你的名字换一个。
使用OpenCV应用自拍的分割方法
mp_selfie = mp.solutions.selfie_segmentation
上面的代码实例化了selfie_segmentation 模型,并将其保存在一个叫做mp_selfie 的变量中。
我们现在去把selfie_segmentation 模型应用到OpenCV饲料中,如下图所示。
cap = cv2.VideoCapture(0)
# Create with statement for model
with mp_selfie.SelfieSegmentation(model_selection=0) as model:
while cap.isOpened():
ret, frame = cap.read()
# Apply segmentation
frame.flags.writeable = False
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = model.process(frame)
frame.flags.writeable = True
cv2.imshow('Webcam feed', frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
这段代码mp_selfie.SelfieSegmentation(model_selection=0) as model 允许我们在OpenCV中使用名为model 的变量应用SelfieSegmentation 。
默认情况下,OpenCV将帧保存为blue-green-red (BGR)格式。如果你的图像或视频资料显示你的脸是蓝色的,请不要惊讶。
我们用命令将其转换为red-green-blue (RGB)标准格式,cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) ,将其传递给我们的模型。
我们把这个结果保存在一个叫做frame 的变量中。然后我们将这个frame 传递给我们的模型,并将结果保存在res 变量中。
请注意,这不会被渲染。至少现在还没有。我们将只看到变量
res中的结果。
要检查结果,请使用以下命令。
res.segmentation_mask
输出。
array([[6.5710924e-28, 5.9139829e-28, 3.2855462e-28, ..., 0.0000000e+00,
0.0000000e+00, 0.0000000e+00],
[1.5529340e-22, 1.3976405e-22, 7.7646702e-23, ..., 3.4236475e-31,
6.8472963e-32, 0.0000000e+00],
[4.3136934e-22, 3.8823240e-22, 2.1568467e-22, ..., 9.5101311e-31,
1.9020266e-31, 0.0000000e+00],
...,
[5.5132825e-17, 4.9619541e-17, 2.7566413e-17, ..., 4.1491491e-19,
8.2982972e-20, 3.9673376e-35],
[2.3155784e-16, 2.0840205e-16, 1.1577892e-16, ..., 1.7426278e-18,
3.4852552e-19, 1.6662817e-34],
[3.3079694e-16, 2.9771723e-16, 1.6539847e-16, ..., 2.4894664e-18,
4.9789340e-19, 2.3804025e-34]], dtype=float32)
上面的结果是一个人在一个网络摄像头框架内的概率。你可以尝试检查你的网络摄像头的画面会给出的概率。
我们现在可以继续处理这些结果。
处理结果
我们首先安装pyplot 和gridspec 。pyplot 帮助我们绘图,而gridspec 使我们能够在布局中使用网格。
Gridspec 在这里,我们可以很容易地设置子图。
from matplotlib import pyplot as plt
from matplotlib import gridspec
# Layout
plt.figure(figsize=(15,15))
grid = gridspec.GridSpec(1,2)
# Setup axes
ax0 = plt.subplot(grid[0])
ax1 = plt.subplot(grid[1])
ax0.imshow(frame)
ax1.imshow(res.segmentation_mask)
plt.show()
设置布局是很重要的,因为它将决定我们最终的绘图方式。在我们的例子中,我们把它设置为15px乘15px。
对于我们的网格,我们将其设置为一行两列。这意味着我们将在这些列中显示一张图片。
接下来,我们创建两个变量,ax0 和ax1 来存储我们的子图。然后将其传递给OpenCV的imshow() 方法来处理帧和分割掩码。
这应该可以并排显示我们的基线图像和分割掩码的结果。
现在让我们应用一个遮罩来排除所有没有被分割突出的成分。
background = np.zeros(frame.shape, dtype=np.uint8)
mask = np.stack((res.segmentation_mask,)*3, axis=-1) > 0.5
segmented_image = np.where(mask, frame, background)
plt.imshow(segmented_image)
在上面的代码中,我们使用numpy 创建了一个黑色的背景图像,并将结果存储在一个名为background 的变量中。
该代码创建了一个numpy array ,并将其填充为零。frame.shape 告诉numpy将这些零分配给我们现有的图像形状。
相反,为了得到一个白色的背景,你可以输入np.ones() 。
与其说分割遮罩只有一个通道,不如说我们将它乘以3,让遮罩应用于所有三个通道。
最后,我们返回只有50%概率的结果。numpy.where() 函数返回一个输入数组中满足给定条件的元素的索引。
你可以在这里阅读更多关于它的信息。
现在让我们来创建Gradio应用程序。
将自拍模型整合到Gradio应用程序中
总结一下,我们将把自拍模型整合到Gradio应用程序中。这将使该模型能够在网络用户界面上被访问。
import gradio as gr
def segment(image):
with mp_selfie.SelfieSegmentation(model_selection=0) as model:
res = model.process(image)
mask = np.stack((res.segmentation_mask,)*3, axis=-1) > 0.5
return np.where(mask, image, cv2.blur(image, (40,40)))
webcam = gr.inputs.Image(shape=(640, 480), source="webcam")
webapp = gr.interface.Interface(fn=segment, inputs=webcam, outputs="image")
webapp.launch()
在上面的代码中,我们首先导入Gradio。然后我们设置了一个函数,segment ,我们希望Gradio能在上面运行。
该函数返回三个值,mask ,输入图片,image ,以及我们的背景,background 。
请注意,并不是一定要有一个黑色的背景。你可以使用一个背景图片,或者你可以在背景上应用模糊处理。
要进行模糊处理,用cv2.blur() 方法替换参数,background 。
然后我们指定网络摄像头作为我们的Gradio应用程序的输入。最后,我们使用launch() 方法来启动Gradio应用程序。
收尾工作
简而言之,这就是集成在Gradio中的自拍分割应用。有相当多的信息需要掌握,但我希望你能理解它。
因此,你可以利用从这篇文章中获得的知识来制作其他高质量的机器学习应用程序。