概述
介绍我们使用的深度学习模型和ReLu6
介绍如何使用深度学习生成模糊背景
介绍
背景模糊效果是一种常见的图像效果,主要用于拍摄特写镜头上。它可以给我们的图像增加了一种深度感,突出关注图像的某一部分。
为了获得这种效果,我们通常使用一些照片编辑应用程序,例如Photoshop,Gimp,Picsart,Snapseed等,但随着时间的推移,我们在计算机视觉和使用深度学习的图像处理方面取得了显着改善,我们可以使用深度学习来获得这种效果。
在本文中,会引导你完成完整的实现以及代码和一些理论方面的知识,以便更好地理解相关内容。
目录
实现原理
我们使用的深度学习模型
ReLu6
实施
得分
结论
1. 实现原理
基本上,我们的整个目标是基于称为图像分割的卷积神经网络的高级实现。我们都熟悉CNN,它用于基于图像输入标签数量图像分类,但是,假设为此必须在给定图像中标识特定对象,我们必须使用对象检测和图像分割的概念。
这是图像分类和检测的经典示例,其中如果在单个图像中有多个类别的对象可用,那么我们在进行对象检测的过程中,一旦找到了多个对象的坐标,则给定图像将经过ROIPooling(region of interest pooling),对这些对象进行分类,并在每个标识的对象周围绘制边框。
由于边界框仅显示对象在图像内部的位置,所以不会提供有关对象形状的任何信息。
简而言之,图像分割是将图像像素分为小部分或片段,并根据相似的信息或属性将它们分组并为其分配标签的过程,这有助于捕获像素级别的非常小的细节。分割会为图像中的每个已识别对象创建一个像素级模板,请看下面的图片,其主要目的是以这种方式训练神经网络,使其可以提供图像的像素级模板。要了解更多详细信息,请单击以下链接
https://towardsdatascience.com/going-deep-into-object-detection-bed442d92b34
2. 我们使用的深度学习模型
在了解图像分割概念知乎,接下来让我们看一下要使用的模型,即在coco数据集上训练的mobilenetv2。
mobilenetv2是一种轻量级模型,可以在手机等低功耗设备上使用,这是2017年发布的mobilenetv1模型的第二个版本。
现在让我们简要了解模型架构。
v2是基于v1的,因此它继承了相同的深度方向的可分离卷积,其中包括深度方向的卷积和点方向的卷积,从而降低了卷积操作的成本。
深度卷积简单地说,假设一幅图像包含3个通道,那么每个内核将分别在每个通道上迭代。
例如,你有一张(10 x 10 x 3)的图像和(3 x 3 x 1)的3个滤波器,那么结果输出将是一个(8 x 8 x 1)这样的滤波器,之后所有其他滤波器的输出滤波器堆叠在一起,形成由(8 x 8 x 3)组成的特征图。
在逐点卷积中,我们采用(8 x 8 x 3)的先前特征图,并应用大小为(1 x 1 x 3)的过滤器,如果应用了15个此类滤波器,则最终结果将叠加起来形成(8 x 8 x 15)的特征图。
mobilenetv2对v1进行了一些改进,例如实现了反向残差,线性瓶颈和残差连接。
Source-MachineThink.Net
v2总共包含3个卷积层,其中第一个是扩展层,第二个是深度层,第三个是投影层。
扩展层:此层接收输入数据并将低维数据扩展为高维,以便保留重要信息并将其输出提供给深度层。扩展因子是一个超参数,可根据试验次数进行调整。
深度层:该层从扩展层接收输入,并执行深度和点向卷积,将特征图提供给投影层。
投影层:该层负责缩小数据的尺寸,以便仅有限数量的数据在网络中进一步传递,此时输入尺寸与输出尺寸匹配,这也称为“瓶颈”层”。
Source-MachineThink.Net
残差连接是基于ResNet的网络的新增功能,有助于控制通过网络的渐变流,使用时输入数据的维数与输出数据的维数相同。
3. ReLu6
该网络中的每个层都带有ReLu6,而不是带有批量标准化的ReLu。ReLu6将值的范围限制在0到6之间,这是一个线性激活函数。通过限制小数点左边的3位信息,还有助于将精度保持在小数点右边。
研究人员表示,最后一层(即投影层)的输出不具有激活功能,因为其输出是低维数据。
根据研究人员的说法,在最后一层中添加任何非线性函数都可能导致有用信息的丢失。
4. 实施
现在,我们对图像分割和使用的mobilenetv2有了一个大概的了解,接下来让我们来看一下如何去实现。
先决条件:该代码使用TensorFlow版本1.x,因此你需要拥有版本1.x才能正常工作,如果你使用的是2.x,则执行时会出错,因此建议你仅使用Google Collab来执行。
在GitHub上的笔记本中逐行解释快速介绍代码的所有重要方面和完整实现。
https://github.com/patrickn699/Background_Blur.git
为了演示,我们将使用以下尺寸为(596 x 900)的图片
步骤1:下载经过预先训练的模型。
由于模型是经过预训练的,因此只需下载并将我们的图像传递给它,它会返回分割后的图像。
-
MODEL_NAME =
'mobilenetv2_coco_voctrainaug' #@参数[
'mobilenetv2_coco_voctrainaug',
'mobilenetv2_coco_voctrainval',
'xception_coco_voctrainaug',
'xception_coco_voctrainval'] _DOWNLOAD_URL_PREFIX =
' http://download.tensorflow.org/models/'
-
_MODEL_URLS = {
-
'mobilenetv2_coco_voctrainaug':
-
'deeplabv3_mnv2_pascal_train_aug_2018_01_29.tar.gz',
-
'mobilenetv2_coco_voctrainval':
-
'deeplabv3_mnv2_pascal_trainval_2018_01_29.tar.gz',
-
'xception_coco_voctrainaug':
-
'deeplabv3_pascal_train_aug_2018_01_04.tar.gz',
-
'xception_coco_voctrainval':
-
'deeplabv3_pascal_trainval_2018_01_04.tar.gz',
-
}
-
_TARBALL_NAME =
'deeplab_model.tar.gz'model_dir = tempfile.mkdtemp()
-
tf.gfile.MakeDirs(model_dir)下载路径= os.path.join(model_dir,_TARBALL_NAME)
-
打印(“正在下载模型,这可能需要一段时间...”)
-
urllib.request.urlretrieve(_DOWNLOAD_URL_PREFIX + _MODEL_URLS [MODEL_NAME],
-
download_path)
-
打印(
'下载完成!正在加载DeepLab模型...')MODEL = DeepLabModel(download_path)
-
打印(
'模型加载成功!')
-
步骤2:用于可视化从输入中获取的分割图像的功能。
-
def run_visualization():
-
""
"Inferences DeepLab model and visualizes result."
""
-
try:
-
original_im = Image.open(IMAGE_NAME)
-
except IOError:
-
print(
'Cannot retrieve image. Please check url: ' + url)
-
returnprint(
'running deeplab on image')
-
resized_im, seg_map = MODEL.run(original_im)
-
vis_segmentation(resized_im, seg_map)
-
return resized_im, seg_map
-
2.1:使用前面显示的图像调用上述功能。
-
IMAGE_NAME =
'download2.jpg'
-
resized_im, seg_map = run_visualization()
-
分割后输出。
2.2:现在,我们读取输入图像并将其转换为numpy数组。
-
print(type(resized_im))
-
numpy_image = np.
array(resized_im)
-
步骤3:分离背景和前景。
在此步骤中,我们创建图像的副本,然后,通过将背景中的值替换为0,并在已创建蒙版的位置保留255,将背景和前景与分割后的图像分开,此处7表示汽车类别。
-
person_not_person_mapping = deepcopy(numpy_image)
-
person_not_person_mapping[seg_map !=
7] =
0
-
person_not_person_mapping[seg_map ==
7] =
255
-
3.1:可视化分离的蒙版图像
-
plt.imshow(person_not_person_mapping)
-
正如上一步中所述,背景已被黑色替换,汽车蒙版已变为白色,同样,通过替换这些值,我们也没有丢失任何重要信息。
3.2:调整蒙版图像的大小使其等于原始图像。
在分割过程之后,图像的大小减小了,在我们的例子中,图像的大小减小为(300 x 500),因此我们将图像的大小调整为原始大小,即(900 x 596)。
-
orig_imginal = Image.open(IMAGE_NAME)
-
orig_imginal = np.
array(orig_imginal)mapping_resized = cv2.resize(person_not_person_mapping,
-
(orig_imginal.shape[
1],
-
orig_imginal.shape[
0]),
-
Image.ANTIALIAS)
-
mapping_resized.shape
-
3.3:二值化
由于调整了大小,图像生成的值在0,1,2…255之间,为了再次将值限制在0–255之间,我们必须使用Otsu的Binarization技术对图像进行二值化。简而言之,Otsu的Binarization是一种寻找灰度图像阈值的自适应方法,它遍历0-255范围内的所有可能阈值,并找到给定图像的最佳可能阈值。
在内部,它基于一些统计概念(例如方差),以根据所选阈值找出类别。一旦选择了最佳阈值,则大于阈值的像素值将被视为白色像素,小于阈值的像素值将被视为黑色像素。
更多有关信息:
https://medium.com/@hbyacademic/otsu-thresholding-4337710dc519
-
gray = cv2.cvtColor(mapping_resized, cv2.COLOR_BGR2GRAY)
-
blurred = cv2.GaussianBlur(gray,(
15,
15),
0)
-
ret3,thresholded_img = cv2.threshold(blurred,
0,
255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
-
plt.imshow(thresholded_img)
-
输出将保持不变,与上一个没有任何区别。
步骤4:为阈值图像添加颜色。
现在我们完成了二值化,是时候将灰度图像转换为RGB图像了。
-
mapping = cv2.cvtColor(thresholded_img, cv2.COLOR_GRAY2RGB)
-
np.unique(mapping)
-
在输出中,将颜色应用于图像后,它包含两个唯一的像素值,即0,255。
我们将在接下来的步骤中应用背景模糊。
4.1:对原始图像应用模糊处理。
接下来,让我们将背景模糊效果应用于原始输入图像。
-
blurred_original_image = cv2.GaussianBlur(orig_imginal,
-
(
251,
251),
0)
-
plt.imshow(blurred_original_image)
-
4.2:获得背景模糊。
在这个步骤中,我们使用简单的代码片段对输入图像的背景进行模糊处理。
-
layered_image = np.where(mapping != (
0,
0,
0),
-
orig_imginal,
-
blurred_original_image)
-
plt.imshow(layered_image)
-
在上面的代码片段中,我们所做的只是简单地填充像素强度值为0的模糊图像,即填充所有黑色像素和填充像素强度值为255(白色像素)的原始图像,这产生了一个漂亮的散景效果,如下图所示。
4.3:最后保存图像。
现在剩下要做的就是保存散景图像了!
-
im_rgb = cv2.cvtColor(layered_image, cv2.COLOR_BGR2RGB)
-
cv2.imwrite(
"Potrait_Image.jpg", im_rgb)
-
5. 得分
本文是参考Bhavesh Bhatt的视频而写的,在 GitHub 页面上提供了带有逐行注释的完整代码。
https://github.com/patrickn699/Background_Blur.git
6. 结论
总而言之,获得背景模糊只是深度学习可以做的事情之一,随着技术的进步,深度学习模型从分类到生成深层伪造的模型做的越来越好了,在不久的未来,相信会有更大的发展。
☆ END ☆
如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 mthler」,每日朋友圈更新一篇高质量博文。
↓扫描二维码添加小编↓
转载:https://blog.csdn.net/woshicver/article/details/114314894