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

上海网站建设服务是什么落实网站建设管理

上海网站建设服务是什么,落实网站建设管理,oa系统平台,电子商务平台开发内容原文#xff1a;Mastering Computer Vision with TensorFlow 2.x 协议#xff1a;CC BY-NC-SA 4.0 译者#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】#xff0c;采用译后编辑#xff08;MTPE#xff09;流程来尽可能提升效率。 不要担心自己的形象#xff0c;… 原文Mastering Computer Vision with TensorFlow 2.x 协议CC BY-NC-SA 4.0 译者飞龙 本文来自【ApacheCN 深度学习 译文集】采用译后编辑MTPE流程来尽可能提升效率。 不要担心自己的形象只关心如何实现目标。——《原则》生活原则 2.3.c 第 1 节计算机视觉和神经网络概论 在本节中您将加深对理论的理解并学习有关卷积神经网络在图像处理中的应用的动手技术。 您将学习关键概念例如图像过滤特征映射边缘检测卷积运算激活函数以及与图像分类和对象检测有关的全连接和 softmax 层的使用。 本章提供了许多使用 TensorFlowKeras 和 OpenCV 的端到端​​计算机视觉管道的动手示例。 从这些章节中获得的最重要的学习是发展对不同卷积运算背后的理解和直觉-图像如何通过卷积神经网络的不同层进行转换。 在本节结束之前您将能够执行以下操作 了解图像过滤器如何转换图像第 1 章应用各种类型的图像过滤器进行边缘检测第 1 章使用 OpenCV 轮廓检测和定向梯度直方图HOG检测简单对象第 1 章使用尺度不变特征变换SIFT本地二进制模式LBP模式匹配以及颜色匹配来查找对象之间的相似性第 1 章和第 2 章使用 OpenCV 级联检测器进行面部检测第 3 章从 CSV 文件列表将大数据输入到神经网络中并解析数据以识别列然后可以将其作为x和y值馈入神经网络第 3 章面部关键点和面部表情识别第 3 章为面部关键点开发标注文件第 3 章使用 Keras 数据生成器方法将大数据从文件输入到神经网络第 4 章构建自己的神经网络并优化其参数以提高准确率第 4 章编写代码以通过卷积神经网络的不同层来变换图像第 4 章 本节包括以下章节 “第 1 章”“计算机视觉和 TensorFlow 基础知识”“第 2 章”“使用本地二进制模式的内容识别”“第 3 章”“使用 OpenCV 和 CNN 进行面部检测”“第 4 章”“图像深度学习” 一、计算机视觉和 TensorFlow 基础知识 随着深度学习方法增强了传统技术例如图像阈值过滤和边缘检测的应用计算机视觉在许多不同的应用中正在迅速扩展。 TensorFlow 是 Google 创建的一种广泛使用的功能强大的机器学习工具。 它具有用户可配置的 API可用于在本地 PC 或云中训练和构建复杂的神经网络模型并在边缘设备中进行大规模优化和部署。 在本章中您将了解使用 TensorFlow 的高级计算机视觉概念。 本章讨论计算机视觉和 TensorFlow 的基本概念以使您为本书的后续更高级章节做好准备。 我们将研究如何执行图像哈希和过滤。 然后我们将学习特征提取和图像检索的各种方法。 接下来我们将了解应用中的可视搜索其方法以及我们可能面临的挑战。 然后我们将概述高级 TensorFlow 软件及其不同的组件和子系统。 我们将在本章中介绍的主题如下 使用图像哈希和过滤检测边缘从图像中提取特征使用轮廓和 HOG 检测器的对象检测TensorFlow其生态系统和安装概述 技术要求 如果尚未安装请从这里安装 Anaconda。 Anaconda 是 Python 的包管理器。 您还需要使用pip install opencv-python为要执行的所有计算机视觉工作安装 OpenCV。 OpenCV 是用于计算机视觉工作的内置编程函数的库。 使用图像哈希和过滤检测边缘 图像哈希是一种用于查找图像之间相似性的方法。 散列涉及通过转换将输入图像修改为固定大小的二进制向量。 使用不同的转换有多种用于图像哈希的算法 永久哈希phash余弦变换差异哈希dhash相邻像素之间的差异 经过哈希转换后可以将图像与汉明距离快速比较。 以下代码显示了用于应用哈希转换的 Python 代码。 0的汉明距离表示相同的图像重复而较大的汉明距离表示图像彼此不同。 以下代码段导入 Python 包例如PILimagehash和distance。 imagehash是支持各种哈希算法的 Python 包。 PIL是 Python 图像库distance是 Python 包用于计算两个散列图像之间的汉明距离 from PIL import Image import imagehash import distance import scipy.spatial hash1 imagehash.phash(Image.open(…/car1.png)) hash2 imagehash.phash(Image.open(…/car2.png)) print hamming_distance(hash1,hash2)图像过滤是一种基本的计算机视觉操作它通过对输入图像的每个像素应用核或过滤器来修改输入图像。 以下是图像过滤所涉及的步骤从进入相机的光到最终的变换图像开始 使用拜耳过滤器形成彩色图案创建图像向量变换图像线性过滤 - 使用核的卷积混合高斯和拉普拉斯过滤器检测图像边缘 使用拜耳过滤器形成彩色图案 拜耳过滤器通过应用去马赛克算法将原始图像转换为自然的经过颜色处理的图像。 图像传感器由光电二极管组成光电二极管产生与光的亮度成比例的带电光子。 光电二极管本质上是灰度的。 拜耳过滤器用于将灰度图像转换为彩色图像。 来自拜耳过滤器的彩色图像经过图像信号处理ISP该过程涉及数周的各种参数手动调整以产生所需的人眼图像质量。 当前正在进行一些研究工作以将手动 ISP 转换为基于 CNN 的处理以生成图像然后将 CNN 与图像分类或对象检测模型合并以生成一个采用 Bayer 彩色图像并使用边界框检测对象的相干神经网络管道 。 此类工作的详细信息可以在 Sivalogeswaran Ratnasingam 在 2019 年发表的题为《深度相机用于图像信号处理的全卷积神经网络》的论文中找到。 本文的链接显示在此处。 这是一个拜耳过滤器的示例 在上图中我们可以观察到以下内容 拜耳过滤器由红色R绿色G和蓝色B通道以预定义的模式因此 G 通道的数量是 B 和 R 的两倍。GR 和 B 通道交替分布。 大多数通道组合是 RGGBGRGB 或 RGBG。每个通道只会让一种特定的颜色通过不同通道的颜色组合会产生如上图所示的图案。 创建图像向量 彩色图像是 RG 和 B 的组合。颜色可以表示为强度值范围从0到255。 因此每个图像都可以表示为三维立方体其中x和y轴表示宽度和高度而z轴表示三种颜色通道RGB代表每种颜色的强度。 OpenCV 是一个具有为 Python 和 C 编写的用于图像处理和对象检测的内置编程函数的库。 我们将从编写以下 Python 代码开始以导入图像然后我们将看到如何将图像分解为具有 RGB 的 NumPy 向量数组。 然后我们将图像转换为灰度并查看当我们仅从图像中提取一种颜色分量时图像的外观 import numpy as np import cv2 import matplotlib.pyplot as plt %matplotlib inline import matplotlib.pyplot as plt from PIL import Image image Image.open(../car.jpeg). # enter image path in .. plt.imshow(image) image_arr np.asarray(image) # convert image to numpy array image_arr.shape 前面的代码将返回以下输出 Output: (296, 465, 4) gray cv2.cvtColor(image_arr, cv2.COLOR_BGR2GRAY) plt.imshow(gray, cmapgray)下图显示了基于上述变换的彩色图像和相应的灰度图像 以下是我们将用于将图像转换为 RG 和 B 颜色分量的 Python 代码 plt.imshow(image_arr[:,:,0]) # red channel plt.imshow(image_arr[:,:,1]) # green channel plt.imshow(image_arr[:,:,2]) # blue channel下图显示了仅提取一个通道RG 或 B后的汽车变形图像 上图可以表示为具有以下轴的 3D 体积 x轴代表宽度。y轴代表高度。每个颜色通道代表图像的深度。 让我们看一下下图。 它以 3D 体积显示在x和y坐标不同的情况下汽车图像的 RG 和 B 像素值 值越高表示图像越亮 变换图像 图像变换涉及图像的平移旋转放大或剪切。 如果xy是图像像素的坐标则新像素的变换后图像坐标uv可以表示为 转换转换常数值的一些示例为c11 1c12 0并且c13 10 c21 0c22 1c23 10。结果方程变为u x 10和v y 10 旋转一些旋转常数值的示例是c11 1c12 0.5c13 0 c21 -0.5c22 1c23 0。 所得的等式变为u x 0.5y和v -0.5x y 旋转 平移旋转和平移组合常数的一些示例为c11 1c12 0.5c13 10 c21 -0.5c22 1c23 10。结果方程变为u x 0.5y 10和v -0.5x y 10 剪切一些剪切常数值示例为c11 10c12 0和c13 0c21 0c22 10c23 0。所得方程变为u 10x和v 10y 图像转换在计算机视觉中特别有用可以从同一图像中获取不同的图像。 这有助于计算机开发对平移旋转和剪切具有鲁棒性的神经网络模型。 例如如果在训练阶段仅在卷积神经网络CNN中输入汽车前部的图像在测试阶段将汽车旋转 90 度的角度则该模型将无法检测到该图像。 接下来我们将讨论卷积运算的机制以及如何应用过滤器来变换图像。 线性过滤 - 使用核的卷积 计算机视觉中的卷积是两个数组其中一个是图像另一个是小数组的线性代数运算以生成形状与原始图像数组不同的已滤波图像数组。 卷积是累积和关联的。 它可以用数学方式表示如下 前面的公式解释如下 F(x,y)是原始图像。G(x,y)是过滤后的图像。U是图像核。 根据核类型U输出映像将有所不同。 转换的 Python 代码如下 import numpy as np import cv2 import matplotlib.pyplot as plt %matplotlib inline import matplotlib.pyplot as plt from PIL import Image image Image.open(‘…/carshort.png) plt.imshow(image) image_arr np.asarray(image) # convert image to numpy array image_arr.shape gray cv2.cvtColor(image_arr, cv2.COLOR_BGR2GRAY) plt.imshow(gray, cmapgray) kernel np.array([[-1,-1,-1],[2,2,2],[-1,-1,-1]]) blurimg cv2.filter2D(gray,-1,kernel) plt.imshow(blurimg, cmapgray)前面代码的图像输出如下 左边是输入图像右边是通过对图像应用水平核而获得的图像。 水平核仅检测水平边缘这可以通过水平线的白色条纹看到。 有关水平核的详细信息请参见“图像梯度”部分。 前面的代码导入了用于机器学习和计算机视觉工作的必要 Python 库例如 NumPy 处理数组cv2用于 openCV 计算机视觉工作PIL 处理 Python 代码中的图像以及 Matplotlib 绘制结果。 然后它使用 PIL 导入图像并使用 OpenCV BGr2GRAY缩放函数将其转换为灰度。 它使用 NumPy 数组创建用于边缘过滤的核使用核模糊图像然后使用imshow()函数显示图像。 过滤操作分为三类 图像平滑图像梯度图像锐化 图像平滑 在图像平滑中通过应用低通过滤器来消除图像中的高频噪声例如 均值过滤器中值过滤器高斯过滤器 这使图像模糊并且通过施加其端值不改变正负号并且值没有明显不同的像素来执行。 图像过滤通常是通过在图像上滑动框式过滤器来完成的。 框式过滤器由n x m核除以n * m表示其中n是行数m是行数。 列。 对于3 x 3核其外观如下 假设此核已应用于先前描述的 RGB 图像。 作为参考此处显示3 x 3图像值 均值过滤器 在对图像执行盒核的卷积运算之后均值过滤器会使用平均值过滤图像。 矩阵相乘后的结果数组如下 平均值为42它将替换图像中166的中心强度值如下面的数组所示。 图像的剩余值将以类似的方式转换 中值过滤器 在对图像执行盒核的卷积运算之后中值过滤器用中值过滤图像值。 矩阵相乘后的结果数组如下 中值是48并替换图像中166的中心强度值如下数组所示。 图像的剩余值将以类似的方式转换 高斯过滤器 高斯核由以下方程式表示 是分布的标准差k是仁大小。 对于1的标准差σ和3 x 3核k 3高斯核看起来如下 在此示例中当应用高斯核时图像的转换如下 因此在这种情况下中心强度值为54。 将该值与中值和均值过滤器值进行比较。 OpenCV 图像过滤 通过将过滤器应用于真实图像可以更好地理解先前描述的图像过滤器概念。 OpenCV 提供了一种方法。 我们将使用的 OpenCV 代码可以在这个页面中找到。 重要代码在以下代码段中列出。 导入图像后我们可以添加噪点。 没有噪声图像过滤器效果将无法很好地显现。 之后我们需要保存图像。 对于均值和高斯过滤器这不是必需的但是如果我们不使用中值过滤器保存图像然后再次将其导回则 Python 将显示错误。 请注意我们使用plt.imsave而不是 OpenCV 保存图像。 使用imwrite直接保存将导致黑色图像因为在保存之前需要将图像规格化为 255 比例。 plt.imsave没有该限制。 之后我们使用blurmedianBlur和GaussianBlur通过均值中值和高斯过滤器来转换图像 img cv2.imread(car.jpeg) imgnoise random_noise(img, modesp,amount0.3) plt.imsave(car2.jpg, imgnoise) imgnew cv2.imread(car2.jpg) meanimg cv2.blur(imgnew,(3,3)) medianimg cv2.medianBlur(imgnew,3) gaussianimg cv2.GaussianBlur(imgnew,(3,3),0)下图显示了使用matplotlib pyplot绘制的结果图像 请注意在这三种情况下过滤器都会去除图像中的噪点。 在此示例中似乎中值过滤器是从图像中去除噪声的三种方法中最有效的方法。 图像梯度 图像梯度可计算给定方向上像素强度的变化。 像素强度的变化是通过对带有核的图像执行卷积运算获得的如下所示 选择核时两个极端的行或列将具有相反的符号正负因此在对图像像素进行乘和求和时会产生差运算符。 让我们看下面的例子 水平核 垂直核 此处描述的图像梯度是计算机视觉的基本概念 可以在x和y方向上计算图像梯度。通过使用图像梯度可以确定边缘和角落。边缘和角落包含有关图像形状或特征的许多信息。因此图像梯度是一种将低阶像素信息转换为高阶图像特征的机制卷积运算将其用于图像分类。 图像锐化 在图像锐化中通过应用高通过滤器差分算子可以消除图像中的低频噪声从而导致线条结构和边缘变得更加清晰可见。 图像锐化也称为拉普拉斯运算由二阶导数表示如下所示 由于存在差异算符因此相对于核中点的四个相邻单元始终具有相反的符号。 因此如果核的中点为正则四个相邻单元为负反之亦然。 让我们看下面的例子 请注意二阶导数相对于一阶导数的优势在于二阶导数将始终经过零交叉。 因此可以通过查看零交叉点0值来确定边缘而不是通过观察一阶梯度的梯度大小可以在图像之间和给定图像内变化来确定边缘。 混合高斯和拉普拉斯运算 到目前为止您已经了解到高斯运算会使图像模糊而拉普拉斯运算会使图像锐化。 但是为什么我们需要每个操作在什么情况下使用每个操作 图像由特征特征和其他非特征对象组成。 图像识别就是从图像中提取特征并消除非特征对象。 我们将图像识别为诸如汽车之类的特定物体因为与非特征相比其特征更为突出。 高斯滤波是一种从特征中抑制非特征的方法该方法会使图像模糊。 多次应用它会使图像更加模糊并同时抑制特征和非特征。 但是由于特征更强可以通过应用拉普拉斯梯度来提取它们。 这就是为什么我们将高斯核的 sigma 卷积两次或更多次然后应用 Laplacian 运算来清晰显示特征的原因。 这是大多数卷积操作中用于对象检测的常用技术。 下图显示了输入3 x 3图像部分核值卷积运算后的输出值以及结果图像 上图显示了各种高斯和倾斜核以及如何通过应用核来转换图像的3 x 3截面。 下图是上一个的延续 前面的表示根据卷积运算的类型清楚地显示了图像如何变得更加模糊或清晰。 对卷积运算的这种理解是基本的因为我们了解更多有关在 CNN 各个阶段使用 CNN 优化核选择的信息。 检测图像边缘 边缘检测是计算机视觉中基于亮度和图像强度变化来查找图像特征的最基本处理方法。 亮度的变化是由于深度方向照明或角落的不连续而导致的。 边缘检测方法可以基于一阶或二阶 下图以图形方式说明了边缘检测机制 在这里您可以看到图像的强度在中点附近从暗变亮因此图像的边缘在中间点。 一阶导数强度梯度在中点先升后降因此可以通过查看一阶导数的最大值来计算边缘检测。 但是一阶导数方法的问题在于取决于输入函数最大值可能改变因此不能预先确定最大值的阈值。 但是如图所示二阶导数始终在边缘处穿过零点。 Sobel 和 Canny 是一阶边缘检测方法而二阶方法是 Laplacian 边缘检测器。 Sobel 边缘检测器 Sobel 运算符通过计算图像强度函数的梯度以下代码中的Sobelx和Sobely来检测边缘。 通过将核应用于图像来计算梯度。 在以下代码中核大小ksize为5。 此后通过取梯度的比率sobely/sobelx来计算 Sobel 梯度SobelG Sobelxcv2.Sobel(gray,cv2.CV_64F,1,0,ksize5) Sobelycv2.Sobel(gray,cv2.CV_64F,0,1,ksize5) mag,direction cv2.cartToPolar(sobelx,sobely,angleInDegrees True) sobelG np.hypot(sobelx,sobely)Canny 边缘检测仪 Canny 边缘检测器使用二维高斯过滤器去除噪声然后应用具有非最大抑制的 Sobel 边缘检测来挑选x和y之间的最大比值。 在任何像素点进行梯度最后应用边缘阈值检测是否存在边缘。 以下代码显示了灰度图像上的 Canny 边缘检测。 min和max值是用于比较图像梯度以确定边缘的阈值 Canny cv2.Canny(gray,minVal100,maxVal200)下图显示了应用Sobel-xSobel-y和 Canny 边缘检测器后的汽车图像 我们可以看到Canny 在检测汽车方面的表现比 Sobel 好得多。 这是因为 Canny 使用二维高斯过滤器消除了噪声然后应用具有非最大抑制的 Sobel 边缘检测来挑选x和y之间的最大比值。 在任何像素点上进行梯度最后应用边缘阈值检测是否存在边缘。 从图像中提取特征 一旦我们知道了如何检测边缘下一个任务就是检测特征。 许多边缘合并形成特征。 特征提取是识别图像中的视觉图案并提取与未知对象的图像匹配的任何可辨别局部特征的过程。 在进行特征提取之前了解图像直方图很重要。 图像直方图是图像色彩强度的分布。 如果直方图相似则图像特征与测试图像匹配。 以下是用于创建汽车图像直方图的 Python 代码 import numpy as np import cv2 import matplotlib.pyplot as plt %matplotlib inline import matplotlib.pyplot as plt from PIL import Image image Image.open(../car.png) plt.imshow(image) image_arr np.asarray(image) # convert image to numpy array image_arr.shape color (blue, green, red) for i,histcolor in enumerate(color):carhistogram cv2.calcHist([image_arr],[i],None,[256],[0,256])plt.plot(carhistogram,colorhistcolor)plt.xlim([0,256])前面的 Python 代码首先导入必要的 Python 库例如cv2OpenCVNumPy用于数组计算PIL用于导入图像和 Matplotlib用于绘制图形。 之后它将图像转换成数组并循环遍历每种颜色并绘制每种颜色RG 和 B的直方图。 下图显示了汽车图像的直方图输出。x轴表示从0黑色到256白色的颜色强度值y轴表示出现的频率 直方图显示 RG 和 B 的峰值颜色强度在100附近第二个峰值在150附近。 这意味着汽车的平均颜色是灰色。 以200的强度值显示的0频率在图像的最右侧显示该车肯定不是白色的。 类似地以50的强度值出现的0频率显示图像不是完全黑色。 OpenCV 图像匹配 图像匹配是一种将两个不同的图像匹配以找到共同特征的技术。 图像匹配技术具有许多实际应用例如匹配指纹使地毯颜色与地板或墙壁颜色匹配使照片匹配以找到同一个人的两个图像或者比较制造缺陷以将它们分为相似的类别以进行更快的分析。 本节概述了 OpenCV 中可用的图像匹配技术。 这里描述了两种常用的方法 暴力破解BFMatcher和用于近似最近的邻居的快速库**FLANN。 在本书的稍后部分我们还将讨论其他类型的匹配技术例如“第 2 章”“使用局部二进制模式的内容识别”中的直方图匹配和。 “第 6 章”“使用迁移学习的视觉搜索”中的局部二进制模式。 在 BFMatcher 中将比较测试图像和目标图像各部分之间的汉明距离以实现最佳匹配。 另一方面FLANN 速度更快但只会找到最接近的邻居–因此它找到了很好的匹配项但不一定是最佳匹配项。 KNN 工具假定相似的事物彼此相邻。 它根据目标与源之间的距离找到最接近的第一近邻。 可以在这个页面上找到用于图像匹配的 Python 代码。 请注意在下图中BFMatcher 找到了更相似的图像。 该图是前面的代码preface_SIFT.ipynb返回的输出。 我们来看一下 上图显示了如何应用 BFMatcher 和 FLANN 的 KNN 匹配器将单个瓷砖匹配到整个浴室地板。 显然与 FLANN 匹配器红线相比BFMatcher蓝线找到更多的平铺点。 前面描述的图像匹配技术还可以用于查找两点之间的相对距离-一个点可以是参考点例如从中获取图像的汽车而另一个可以是道路上的另一辆汽车。 然后使用该距离来开发防撞系统。 使用轮廓和 HOG 检测器的对象检测 轮廓是图像中形状相似的封闭区域。 在本节中我们将使用轮廓来分类和检测图像中的简单对象。 我们将使用的图像由苹果和橙子组成我们将使用轮廓和 Canny 边缘检测方法来检测对象并将图像类名称写在边界框上。 该部分的代码可以在这个页面中找到。 以下各小节介绍了该方法。 轮廓检测 我们首先需要导入图像然后使用 Canny 边缘检测器在图像中找到边缘。 因为我们的对象的形状是带有圆角的圆所以效果很好。 以下是所需的详细代码 threshold 100 canny_output cv2.Canny(img, threshold, threshold * 2) contours, hierarchy cv2.findContours(canny_output, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)如前面的代码所示在 Canny 边缘检测之后我们应用了 OpenCV findContours()方法。 此方法具有三个参数 图像在本例中为 Canny 边缘检测器输出。检索方法有很多选择。 我们正在使用的是一种外部方法因为我们有兴趣在对象周围绘制边界框。轮廓近似法。 检测边界框 该方法本质上包括理解图像及其各种类别的特征以及对图像类别进行分类的开发方法。 请注意OpenCV 方法不涉及任何训练。 对于每个轮廓我们使用 OpenCV boundingRect属性定义一个边界框。 我们将使用两个重要的特征来选择边界框 兴趣区域的大小我们将消除尺寸小于20的所有轮廓。 请注意20不是通用编号它仅适用于此图像。 对于更大的图像该值可以更大。 兴趣区域的颜色在每个边界框中我们需要定义宽度从25%到75%的兴趣区域以确保我们不考虑圈子外的矩形的空白区域。 这对于最小化变化很重要。 接下来我们使用CV2.mean定义平均颜色。 我们将通过观察包围它的三个橙色图像来确定颜色的平均阈值和最大阈值。 以下代码使用 OpenCV 的内置方法通过cv2.boundingRect绘制边界框。 然后根据宽度和高度选择绘制兴趣区域ROI并找到该区域内的平均颜色 count0 font cv2.FONT_HERSHEY_SIMPLEX for c in contours:x,y,w,h cv2.boundingRect(c)if (w 20 and h 20):count count1ROI img[yint(h/4):yint(3*h/4), xint(h/4):xint(3*h/4)]ROI_meancolor cv2.mean(ROI)print(count,ROI_meancolor)if (ROI_meancolor[0] 30 and ROI_meancolor[0] 40 and ROI_meancolor[1] 70 and ROI_meancolor[1] 105and ROI_meancolor[2] 150 and ROI_meancolor[2] 200):cv2.putText(img, orange, (x-2, y-2), font, 0.8, (255,255,255), 2, cv2.LINE_AA)cv2.rectangle(img,(x,y),(xw,yh),(255,255,255),3)cv2.imshow(Contours, img)else:cv2.putText(img, apple, (x-2, y-2), font, 0.8, (0,0,255), 2, cv2.LINE_AA)cv2.rectangle(img,(x,y),(xw,yh),(0,0,255),3)cv2.imshow(Contours, img) 在前面的代码中请注意两个if语句-基于大小的w,h和基于颜色的ROI_meancolor[0,1,2] 基于大小的语句消除了所有小于20的轮廓。ROI_meancolor [0,1,2]表示平均颜色的 RGB 值。 在这里第三第四和第八行表示橙色if语句将颜色限制为B组件在30和40之间对于G则在70和105之间 ]组件以及R组件的150和200。 输出如下。 在我们的示例中34和8是橙色 1 (52.949200000000005, 66.38640000000001, 136.2072, 0.0) 2 (43.677693761814744, 50.94659735349717, 128.70510396975425, 0.0) 3 (34.418282548476455, 93.26246537396122, 183.0893351800554, 0.0) 4 (32.792241946088104, 78.3931623931624, 158.78238001314926, 0.0) 5 (51.00493827160494, 55.09925925925926, 124.42765432098766, 0.0) 6 (66.8863771564545, 74.85960737656157, 165.39678762641284, 0.0) 7 (67.8125, 87.031875, 165.140625, 0.0) 8 (36.25, 100.72916666666666, 188.67746913580245, 0.0)请注意OpenCV 将图像处理为BGR而不是RGB。 HOG 检测器 定向梯度的直方图HOG是有用的特征可用于确定图像的局部图像强度。 此技术可用于查找图像中的对象。 局部图像梯度信息可用于查找相似图像。 在此示例中我们将使用 scikit-image 导入 HOG并使用它绘制图像的 HOG。 如果尚未安装 scikit-image则可能需要使用pip install scikit-image安装它 from skimage.feature import hog from skimage import data, exposure fruit, hog_image hog(img, orientations8, pixels_per_cell(16, 16), cells_per_block(1, 1), visualizeTrue, multichannelTrue) hog_image_rescaled exposure.rescale_intensity(hog_image, in_range(0, 10)) cv2.imshow(HOG_image, hog_image_rescaled)下图说明了示例代码中前面代码的结果 在上图中我们可以观察到以下内容 左侧显示边界框而右侧显示图像中每个对象的 HOG 梯度。请注意每个苹果和橘子都可以正确检测到并且包围水果的边界框没有任何重叠。HOG 描述符显示一个矩形的边界框其中的梯度表示圆形图案。桔子和苹果之间的梯度显示出相似的图案唯一的区别是大小。 轮廓检测方法的局限性 在对象检测方面上一节中显示的示例看起来非常好。 我们无需进行任何训练并且只需对一些参数进行少许调整就可以正确检测出橙子和苹果。 但是我们将添加以下变体并查看我们的检测器是否仍然能够正确检测对象 我们将添加除苹果和橙子以外的对象。我们将添加另一个形状类似于苹果和橙子的对象。我们将改变光的强度和反射率。 如果我们执行上一部分中的相同代码它将检测每个对象就好像它是一个苹果一样。 这是因为所选的width和height参数太宽并且包括所有对象以及 RGB 值它们在此图像中的显示方式与以前不同。 为了正确检测对象我们将对if语句的大小和颜色进行以下更改如以下代码所示 if (w 60 and w 100 and h 60 and h 120):if (ROI_meancolor[0] 10 and ROI_meancolor[0] 40 and ROI_meancolor[1] 65 and ROI_meancolor[1] 105请注意前面的更改对if语句施加了以前不存在的约束。 RGB 颜色如下 1 (29.87429111531191, 92.01890359168242, 182.84026465028356, 0.0) 82 93 2 (34.00568181818182, 49.73605371900827, 115.44163223140497, 0.0) 72 89 3 (39.162326388888886, 62.77256944444444, 148.98133680555554, 0.0) 88 96 4 (32.284938271604936, 53.324444444444445, 141.16493827160494, 0.0) 89 90 5 (12.990362811791384, 67.3078231292517, 142.0997732426304, 0.0) 84 84 6 (38.15, 56.9972, 119.3528, 0.0) 82 100 7 (47.102716049382714, 80.29333333333334, 166.3264197530864, 0.0) 86 90 8 (45.76502082093992, 68.75133848899465, 160.64901844140394, 0.0) 78 82 9 (23.54432132963989, 98.59972299168975, 191.97368421052633, 0.0) 67 76上面的代码在更改后的图像上的结果如下所示 在上图中可以看到一个遥控器叉子刀子和一个塑料杯。 请注意苹果橘子和塑料杯的 HOG 功能如何相似这是预期的因为它们都是圆形的 塑料杯周围没有包围框因为未检测到。与苹果和橘子相比叉子和刀子的 HOG 角形非常不同。遥控器具有矩形的 HOG 形状。 这个简单的示例表明这种对象检测方法不适用于较大的图像数据集我们需要调整参数以考虑各种照明形状大小和方向条件。 这就是为什么我们将在本书其余部分中讨论 CNN 的原因。 一旦我们使用此方法在不同条件下训练图像无论对象的形状如何它将在新的条件下正确检测到对象。 但是尽管上述方法有局限性我们还是学习了如何使用颜色和大小将一个图像与另一个图像分开。 ROI_meancolor是一种用于检测边界框内对象平均颜色的强大方法。 例如您可以使用它根据边界框内的球衣颜色绿色苹果与红色苹果或任何类型的基于颜色的分离方法将一个团队的球员与另一个团队的球员区分开。 TensorFlow生态系统和安装概述 在前面的部分中我们介绍了计算机视觉技术的基础知识例如图像转换图像过滤使用核进行卷积边缘检测直方图和特征匹配。 这种理解及其各种应用应该为深度学习的高级概念打下坚实的基础这将在本书的后面部分进行介绍。 计算机视觉中的深度学习是通过许多中间隐藏层的卷积运算对许多不同图像特征例如边缘颜色边界形状等的累积学习以全面了解图像类型。 深度学习增强了计算机视觉技术因为它堆叠了有关神经元行为的许多计算层。 通过组合各种输入以基于数学函数和计算机视觉方法例如边缘检测产生输出来完成此操作。 TensorFlow 是一个端到端E2E机器学习平台其中图像和数据被转换为张量以由神经网络进行处理。 例如大小为224 x 224的图像可以表示为等级4的张量为128, 224, 224, 3其中128是神经网络的批量大小224是高度和宽度 3是颜色通道RG 和 B。 如果您的代码基于 TensorFlow 1.0那么将其转换为 2.0 版可能是最大的挑战之一。 请遵循这个页面上的说明以转换为 2.0 版。 大多数时候当您使用终端在 TensorFlow 中执行 Python 代码时转换问题会在低级 API 中发生。 Keras 是 TensorFlow 的高级 API。 以下三行代码是安装 Keras 的起点 from __future__ import absolute_import, division, print_function, unicode_literals import tensorflow as tf from tensorflow import keras如果不使用最后一行则可能必须对所有函数使用from tensorflow.keras导入。 TensorFlow 使用tf.data从简单的代码构建复杂的输入管道从而简化并加快了数据输入过程。 您将在 “第 6 章”“使用迁移学习的视觉搜索”中了解这一点。 在 Keras 中模型的各层以顺序的形式堆叠在一起。 这由modeltf.keras.Sequential()引入并使用model.add语句添加每一层。 首先我们需要使用model.compile编译模型然后可以使用model.train函数开始训练。 TensorFlow 模型将保存为检查点并保存模型。 检查点捕获模型使用的参数过滤器和权重的值。 检查点与源代码关联。 另一方面保存的模型可以部署到生产设置中不需要源代码。 TensorFlow 针对多个 GPU 提供分布式训练。 TensorFlow 模型输出可以使用 Keras API 或 TensorFlow 图可视化。 TensorFlow 与 PyTorch PyTorch 是另一个类似于 TensorFlow 的深度学习库。 它基于 Torch由 Facebook 开发。 在 TensorFlow 创建静态图的同时PyTorch 创建动态图。 在 TensorFlow 中必须首先定义整个计算图然后运行模型而在 PyTorch 中可以平行于模型构建来定义图。 TensorFlow 安装 要在 PC 上安装 TensorFlow 2.0请在终端中键入以下命令。 确保单击Enter pip install --upgrade pip pip install tensorflow除 TensorFlow 之外上述命令还将在终端中下载并提取以下包 Keras用 Python 编写的高级神经网络 API能够在 TensorFlow 的顶部运行protobuf用于结构化数据的序列化协议TensorBoardTensorFlow 的数据可视化工具PyGPUPython 功能用于图像处理GPU 计算以提高性能cctools适用于 Android 的本地 IDEc-ares函数库clangCCObjective-COpenCL 和 OpenCV 的编译器前端llvm用于生成前端和后端二进制代码的编译器架构theano用于管理多维数组的 Python 库grpcio用于 Python 的gRPC包用于实现远程过程调用libgpuarray可用于 Python 中所有包的常见 N 维 GPU 数组termcolorPython 中的颜色格式输出absl用于构建 Python 应用的 Python 库代码集合mock用虚拟环境替换真实对象以帮助测试gast用于处理 Python 抽象语法的库 在安装过程中在询问时按y表示是 Downloading and Extracting Packages Preparing transaction: done Verifying transaction: done Executing transaction: done如果一切都正确安装您将看到前面的消息。 安装后根据您的 PC 是 CPU 还是 CPU 和 GPU输入以下两个命令之一检查 TensorFlow 版本。 请注意对于所有计算机视觉工作最好使用 GPU 来加速图像的计算。 对于 Python 3.6 或更高版本请使用pip3对于 Python 2.7请使用pip pip3 show tensorflow pip3 show tensorflow-gpu pip show tensorflow输出应显示以下内容 Name: tensorflow Version: 2.0.0rc0 Summary: TensorFlow is an open source machine learning framework for everyone. Home-page: https://www.tensorflow.org/ Author: Google Inc. Author-email: packagestensorflow.org License: Apache 2.0 Location: /home/.../anaconda3/lib/python3.7/site-packages Requires: gast, google-pasta, tf-estimator-nightly, wrapt, tb-nightly, protobuf, termcolor, opt-einsum, keras-applications, numpy, grpcio, keras-preprocessing, astor, absl-py, wheel, six Required-by: gcn有时您可能会注意到即使在安装 TensorFlow 之后Anaconda 环境也无法识别已安装 TensorFlow。 在这种情况下最好在终端中使用以下命令卸载 TensorFlow然后重新安装它 python3 -m pip uninstall protobuf python3 -m pip uninstall tensorflow-gpu总结 在本章中我们学习了图像过滤如何通过卷积运算修改输入图像以产生检测特征的一部分称为边缘的输出。 这是计算机视觉的基础。 正如您将在以下各章中了解到的那样图像过滤的后续应用会将边缘转换为更高级别的图案例如特征。 我们还学习了如何计算图像直方图如何使用 SIFT 进行图像匹配以及如何使用轮廓和 HOG 检测器绘制边界框。 我们学习了如何使用 OpenCV 的边界框颜色和大小方法将一个类与另一个类隔离。 本章以 TensorFlow 简介作为结束这将为本书的其余章节奠定基础。 在下一章中我们将学习另一种称为模式识别的计算机视觉技术并将使用它来对具有模式的图像内容进行分类。 二、使用局部二进制模式的内容识别 局部二进制模式LBP于 1994 年由 Timo OjalaMatti Pietikäinen 和 David Harwood 在国际模式识别会议上在论文《Performance evaluation of texture measures with classification based on Kullback discrimination of distributions》中首次提出。 在本章中您将学习如何创建 LBP 图像类型的二进制特征描述符和 LBP 直方图以对纹理图像和非纹理图像进行分类。 您将了解可用于计算直方图之间的差异以找到各种图像之间的匹配的不同方法以及如何调整 LBP 参数以优化其表现。 本章将涵盖以下主题 使用 LBP 处理图像将 LBP 应用于纹理识别使面部颜色与基础色匹配 - LBP 及其局限性使用基础色匹配面部颜色 - 颜色匹配技术 使用 LBP 处理图像 LBP 是一种灰度图像阈值操作用于基于不同的模式对图像进行分类。 通过将邻域像素值与中心像素值进行比较来开发二进制模式并将其用于构建直方图块。 在以下部分中我们将详细描述 LBP 操作。 生成 LBP 模式 LBP 模式生成的主要步骤如下 将 RGB 图像A转换为灰度图像G。对于图像G中每个具有强度I[c](x, y)的像素选择P相邻点p[0], p[1], ..., p[P-1]其半径[I[0], I[1], ..., I[P-1]具有相应的强度。R。 半径以像素为单位定义为两个像素之间的差。 像素和相邻点代表图像G的滑动窗口W。对于半径R 1P变为 8如下所示。 滑动窗口W[0]用W[0] [I[c], I[0], I[1], I[P-1]]表示为数组。 在这里点 0 到P-1代表围绕中心像素c的P个点的强度 确定半径R和相邻点P之间的关系以使附近的每个像元恰好具有一个像素。 如上图中的前三个圆圈所示周长中的每个像元恰好具有一个像素而最后一个像元在周长中填充了多个像素。 从前三个圆圈我们可以表示为了使每个单元格都有一个像素点数P可以表示为(8R 16) / 3。 下图显示了线性关系和离群值离群值由左起第四个圆圈显示在相邻单元格中有重叠点 计算相邻像素和中心像素之间的强度差并删除第一个值 0。该数组可以表示如下 W[1] ~ [I[0] - I[c], I[1] - I[c], ..., I[P-1] - I[c]] 现在对图像进行阈值处理。 为此如果强度差小于 0则将值分配为 0如果强度差大于 0则将值分配为 1如以下等式所示 应用阈值函数f之后的差数组如下 W[2] [f(I[0] - I[c]), f(I[1] - I[c]), ..., f(I[P-1] - I[c]) 例如假设第一个差异小于 0 且第二个和最后一个差异大于 0则数组可以表示如下 W[2] [0, 1, ... 1] 将差数组W[2]乘以二项式权重2^p将二进制数组W[2]转换​​为表示十进制数组W[LBP]的代码 3 请注意本节中描述的五个步骤将在接下来的几节中引用。 下图显示了在灰度图像的滑动窗口上 LBP 操作的图形表示 在上图中我们可以看到以下内容 起始的3 x 3核只是图像的一部分。接下来的3 x 3是二进制表示形式。左上角的值为 1因为我们正在比较 120 和 82。顺时针旋转因为我们将 51 与 82 进行了比较所以最后一个值为 0。接下来的3 x 3核只是2^n操作。第一个值是 12^0最后一个值是顺时针为 1282^7。 了解 LBP 直方图 LBP 数组W[3]以直方图形式表示如下 W4 histogram(W3, binsP, rangeW3(min) to W3(max)) 对训练后的图像和测试图像重复上一节中的“步骤 1”至 5以创建图像W_train, W_test的 LBP 直方图每个都包含P个箱子然后使用直方图比较方法对其进行比较。 直方图比较方法 可以使用不同的直方图比较方法来计算直方图之间的距离。 这些如下 交叉方法 在 Python 中这表示如下 minima np.minimum(test_hist,train_hist) intersection np.true_divide(np.sum(minima),np.sum(train_hist))卡方方法 欧几里得方法 城市街区方法 Bhattacharya 方法 Wasserstein 方法 给定W_test N(μ_test, σ_test)和W_train N(μ_train, σ_train)此处μ是分布的平均值第一矩o第二矩是分布的标准差而ρ[QQ]为两个分布W_test和W_train的分位数彼此之间的相关性。 前面的距离度量具有以下特征 每种方法的距离绝对值都不相同。除 Wasserstein 方法外所有方法的测试直方图和训练直方图值之间的最小距离都相似。 Wasserstein 方法根据位置均值差异大小标准差差异和形状相关系数计算距离。 下面显示了给定半径R 5时的原始灰度图像和相应的 LBP 图像 接下来我们将评估半径变化对图像清晰度的影响。 为此需要通过将半径值从 1 更改为 10 来执行 Python 代码。下图显示了对 LBP 图像清晰度的最终影响。 根据相关性P (8R 16) / 3获得到多个点的半径。请注意随着半径的增加图像中的图案变得更加清晰。 围绕半径 5 和点 20-25该图案在主拱的主要图案和次要图案之间变得更加清晰。 在很大的半径上辅助图案变得不太明显 从前面的图像中还可以清楚地看到以下内容 选择R和P对于模式识别很重要。可以通过P (8R 16) / 3来选择初始值但是对于给定的R超过此值的P的值并不意味着不良表现如先前示例中的R 5P 25所示。选择的模式明显优于R 4P 16示例并且与R 5.5P 20非常相似。 另外请注意此处的示例仅提供适用于此图像的准则。 对于不同尺寸的图像请从此示例中学习首先选择P的初始值然后调整R和P以获得所需模式。 LBP 的计算成本 与传统的神经网络方法相比LBP 在计算上更便宜。 LBP 的计算成本由 Li LiPaul FieguthWang Xiaogang WangMatti Pietikäinen 和 Dewen Hu 在他们的论文《使用新的稳健性基准评估 LBP 和深纹理描述符》中提出。 论文的详细信息可以在这里找到。 作者确定了在 2.9 GHz Intel Quad-Core CPU 和 16 GB RAM 上对 480 张图像进行特征提取所花费的平均时间这些图像的大小为128 x 128。 该时间不包括训练时间。 研究发现与被认为中等的 AlexNet 和 VGG 相比LBP 特征提取非常快。 将 LBP 应用于纹理识别 既然我们了解了 LBP 的基础知识我们将把它应用于纹理识别示例。 对于此示例已将 11 张训练后的图像和 7 张尺寸为50 x 50的测试图像分为以下几类 训练图像图案图像7普通图像4测试图像图案图像4普通图像3 执行“生成 LBP 模式”部分的“步骤 1”至 5 然后将每个测试图像的 LBP 直方图与所有训练图像进行比较以找到最佳匹配。 尽管已使用了不同的直方图比较方法但是对于此分析将使用卡方检验作为确定匹配的主要方法。 具有正确匹配项的最终摘要输出用绿线显示而错误匹配项将用红线显示。 实线是最短距离的第一个匹配项而虚线是下一个最佳匹配项。 如果用于下一个最佳匹配的直方图之间的距离比最小距离远得多则仅显示一个值最小距离这表明系统对此输出具有相当高的置信度。 下图显示了使用 LBP 在测试和训练灰度图像之间的匹配过程。 实线表示最接近的匹配而虚线表示第二最接近的匹配。 第三张测试图像从左起只有一个匹配项这意味着当图像转换为灰度时模型对其预测非常有信心。 第二个第三个和第六个训练图像从右侧开始没有相应的测试图像匹配 在这里我们可以看到基于有限的训练数据11 个样本LBP 通常会产生很好的匹配在考虑的七个测试样本中只有一个错误。 要了解在上一张图像中如何完成相关性我们需要绘制 LBP 直方图并比较训练图像和测试图像之间的直方图。 下图分析每个测试图像并将其直方图与相应测试图像的直方图进行比较以找出最匹配的图像。 n_points 25表示 LBP 中有 25 点。 使用 LBP 直方图的主要优点是可实现平移的归一化从而使其旋转不变。 我们将逐一分析每个直方图。 直方图的x轴为 25表示点数25而y轴为 LBP 直方图块。 下图中显示的两个图像都具有图案并且看起来相似 先前图像的直方图分析显示了相似的模式使用 LBP 可以显示正确的匹配。 下图中显示的两个图像都具有图案并且看起来相似。 实际上它们是从不同的方向和不同的阴影获取的同一张地毯图像 先前图像的直方图分析显示了相似的模式使用 LBP 可以显示正确的匹配。 下图中显示的两个图像具有图案但是它们来自不同的地毯 先前图像的直方图分析显示了相似的模式。 它们的样式看起来相似但图像实际上不同。 因此这是匹配不良的一个示例。 下一张图像中的第一张图像具有图案与我们已经看到的图像相比它是一种较弱的图案而经过训练的图像则完全没有图案但是在地毯上似乎有污渍 先前图像的直方图分析显示了相似的模式。 它们的样式看起来相似但图像实际上不同。 这是比赛不佳的另一个例子。 由于红地毯上的污渍LBP 似乎认为图像相似。 下图显示了 LBP 将灰色地毯与前面相同的红色地毯相匹配 LBP 直方图显示了类似的趋势–这是合理的因为 LBP 是一种灰度图像识别技术。 下图显示了 LBP 将硬木地板与地毯相匹配 请注意训练图像没有硬木地板因此 LBP 发现具有叶子形状的地毯是与具有木纹的木地板最接近的匹配。 最后一个 LBP 图片显示相似的图片几乎没有图案 在这里LBP 预测似乎是正确的。 比较顶部直方图和底部直方图以可视化直方图如何比较测试图像和训练图像。 可以在这个页面中找到详细的 Python 代码。 使面部颜色与基础颜色匹配 - LBP 及其局限性 由于我们在纹理识别方面使用 LBP 取得了相对良好的成功因此让我们尝试另一个示例来了解 LBP 的局限性。 在此示例中从浅色到深色测试的七种面部颜色将与 10 种基础色训练相匹配这些基础色是50 x 50的图像。 与纹理识别示例类似将应用“生成 LBP 模式”部分中的“步骤 1”至 5然后将每个面部彩色图像 LBP 直方图与与所有基础彩色图像 LBP 直方图一起比较来找到最佳匹配。 尽管已使用不同的直方图比较方法但对于此分析将使用卡方检验作为确定匹配的主要方法。 下图显示了最终的摘要输出 如我们所见LBP 的效果不佳所有脸部颜色都导致底色为 4 或 8。 为了理解这种情况已绘制了 RGB灰度和 LBP 图像的两个级别一个带有R2.5, P12另一个带有R5.5, P20。 这是由两个因素引起的 面部颜色从 RGB 到灰度的转换会导致图像中不必要的亮度这在比较过程中会产生误导。LBP 转换采用这些模式并生成无法正确解释的任意灰色阴影。 下图显示了两个图像-面部颜色 1 和 7-分别代表肤色和深色皮肤的颜色以及 LBP 不同步骤的结果。 每个图像都会转换为灰度这表明两个图像的中间都有一个亮点而原始彩色图像无法看到该亮点。 然后将两个 LBP 操作应用于图像一个半径为 2.5另一个半径为 5.5。 在这里我们可以看到在应用 LBP 之后有很多相似之处这是原始彩色图像所没有的。 让我们看一下下面的图片 解决第一个问题的可能方法是应用高斯滤波我们已在“第 1 章”“计算机视觉和 TensorFlow 基本原理”中进行了研究以抑制该模式。 下图可以看到应用高斯过滤器然后进行 LBP 的结果 即使在应用过滤器之后也无法清晰地区分浅灰和深灰这两种灰色阴影。 由此可以得出结论LBP 并不是用于面部颜色识别的好方法。 使脸部颜色与基础颜色匹配 – 颜色匹配技术 对于这种方法RGB 图像不会转换为灰度 而是使用以下 Python 代码针对每种情况重复确定七种面部颜色和 10 种基础颜色中的每一种的颜色强度值 facecol1img Image.open(/…/faceimage/facecol1.JPG) facecol1arr np.asarray(facecol1img) (mfc1, sfc1) cv2.meanStdDev(facecol1arr) statfc1 np.concatenate([mfc1, sfc1]).flatten() print (%s statfc1 %(statfc1))输出具有六个元素。 前三个是 RGB 平均值而后三个是 RGB 值的标准差。 面部和底色之间的强度差计算如下 让我们看一下下面的图像它代表了脸部和底色 矩阵中差异最小的值是最佳匹配。 我们可以看到对于每种脸部颜色匹配如对角线上的最小限度点所示可得出合理的值这表明颜色匹配技术应该是与基础色进行脸部颜色匹配的首选方法 。 总结 在本章中我们学习了如何获取图像像素并将其与给定半径内的相邻像素阈值化然后执行二进制和积分运算以创建 LBP 模式。 LBP 模式是无监督机器学习的一个很好的例子因为我们没有用输出训练分类器。 相反我们学习了如何调整 LBP 的参数半径和点数以达到正确的输出。 发现 LBP 是用于纹理分类的非常强大且简单的工具。 但是当图像为非纹理图像时LBP 无法返回良好的结果我们学习了如何开发 RGB 颜色匹配模型来匹配彩色的非纹理图像例如面部和基础色。 要创建 LBP 表示必须将图像转换为灰度。 在下一章中我们将结合各种边缘检测方法来识别人脸眼睛和耳朵介绍积分图像的概念。 然后我们将介绍卷积神经网络并使用它来确定面部关键点和面部表情。 三、使用 OpenCV 和 CNN 的人脸检测 面部检测是计算机视觉的重要组成部分并且是近年来发展迅速的领域。 在本章中您将从 Viola-Jones 面部和关键特征检测的简单概念开始然后继续介绍基于神经网络的面部关键点和面部表情检测的高级概念。 本章将以 3D 人脸检测的高级概念作为结尾。 本章将涵盖以下主题 应用 Viola-Jones AdaBoost 学习和 Haar 级联分类器进行人脸识别使用深度神经网络预测面部关键点使用 CNN 预测面部表情3D 人脸检测概述 应用 Viola-Jones AdaBoost 学习和 Haar 级联分类器进行人脸识别 2001 年微软研究院的保罗·维奥拉和三菱电机的迈克尔·琼斯通过开发名为 Haar 级联分类器 的分类器开发了一种检测图像中人脸的革命性方法。Haar 级联分类器基于 Haar 特征这些特征是矩形区域中像素值差异的总和。 校准差值的大小以指示面部给定区域例如鼻子眼睛等的特征。 最终的检测器具有 38 个级联分类器这些分类器具有 6,060 个特征包括约 4,916 个面部图像和 9,500 个非面部图像。 总训练时间为数月但检测时间非常快。 首先将图像从 RGB 转换为灰度然后应用图像过滤和分割以便分类器可以快速检测到对象。 在以下各节中我们将学习如何构造 Haar 级联分类器。 选择类似 Haar 的特征 Haar 级联分类器算法基于这样的思想即人脸的图像在脸部的不同区域具有强度的独特特征例如脸部的眼睛区域比眼睑底部暗鼻子区域比旁边的两个面部区域更亮。 类似于 Haar 的特征由黑色和白色的相邻矩形表示如下图所示。 在此图像中存在几个潜在的类似 Haar 的特征两个矩形三个矩形和四个矩形 请注意矩形部分放置在面部的特征上。 由于眼睛区域的强度比脸部暗因此矩形的黑色区域靠近眼睛白色区域低于眼睛。 同样由于鼻子区域比周围的环境明亮鼻子上出现白色矩形而两侧则是黑色矩形。 创建一个完整的图像 积分图像可用于一次快速计算矩形特征像素值。 为了更好地理解积分图像让我们看一下其计算的以下细分 可以将 Haar 样特征的值计算为白色区域中的像素值之和与黑色区域中的像素值之和之差。像素I的总和xy可以由当前像素位置左上方和上方所有像素的值[ixy包括当前像素值可以表示为 在下图中I(x, y)是由九个像素值组成的最终积分图像值62515111190779079和73。 将所有这些总和得出 684 的值 下图显示了脸部的眼睛区域的像素强度和相应的积分图像 上图显示矩形区域的像素强度总和是通过将上方和左侧的所有像素值相加得出的例如917通过将866这是73, 79, 90, 111, ..., 68的总和和10149和18。 注意917也可以通过将717求和然后将其加到5064和68和18的总和来获得。 前面的像素方程式的总和可以重写如下 在积分图像中可以通过将四个数组如前面的方程式所示相加来计算图像中任何矩形区域的面积而不是针对所有单个像素的总和进行六个内存访问。 Haar 分类器的矩形总和可以从前面的方程式获得如以下方程式所示 前面的等式可以重新安排如下 下图显示了转换为整数图像像素值的图像像素值 右侧的积分图像就是左侧像素值的总和-所以113 62 51依此类推。 黑色阴影区域像素值表示黑色 Haar 矩形如前所述。 为了计算阴影区域的强度值我们取整数强度值 1,063然后从中减去 268。 进行 AdaBoost 训练 图像被划分为T窗口在其中应用了类似 Haar 的特征并如前所述计算其值。 AdaBoost 通过迭代T窗口的训练集从大量弱分类器中构建出一个强分类器。 在每次迭代中基于多个正样本面部和多个负样本非面部来调整弱分类器的权重以评估分类错误的项目的数量。 然后对于下一次迭代将为错误分类的项目的权重分配更高的权重以增加检测到这些权重的可能性。 最终的强分类器hx是根据弱分类器的误差加权的组合。 弱分类器每个弱分类器都具有一个特征f。 它具有极性p和阈值θ 强分类器最终的强分类器hx具有最小的误差E[t]并由以下给出 在此E[t] log(1 / E[t])和E[t] E[t] / (1 - E[t]) 权重W[t]初始化如下 在此P和N分别是正样本和负样本的数量。 权重值更新如下 每个弱分类器都会计算一个特征。 请注意弱分类器无法单独进行分类但是将其中几个组合在一起可以很好地进行分类。 注意级联分类器 前面描述的每个强分类器形成一个级联其中每个弱分类器代表一个阶段可以快速删除负子窗口并保留正子窗口。 来自第一个分类器的肯定响应表示已检测到脸部区域例如眼睛区域然后算法继续进行下一个特征例如鼻子区域以触发第二个区域的分类器的评估依此类推。 任何时候的负面结果都会导致该阶段立即被拒绝。 下图说明了这一点 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xSHTT58k-1681784327300)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/master-cv-tf-2x/img/5d972796-d061-4cea-aa39-5d6e98320b04.png)] 此图显示负特征已被立即消除。 随着分类从左向右移动其准确率会提高。 训练级联检测器 开发了整个训练系统以最大程度地提高检测率并最大程度地降低假阳性率。 Viola 和 Jones 通过为级联检测器的每个阶段设置目标检测率和假阳性率实现了以下目标 级联检测器每一层中的特征数量都会增加直到达到该层的目标检测率和假阳性目标为止。如果总体假阳性率不够低则添加另一个阶段。矩形特征将添加到当前阶段直到达到其目标速率。当前阶段的假阳性目标被用作下一阶段的阴性训练集。 下图显示了 OpenCV Python Haar 级联分类器用于分类正面和眼睛以检测面孔和眼睛。 左图和右图均显示它可以正确检测到脸部 然而在第一图像中由于左眼的眩光而仅检测到右眼而在第二图像中检测到双眼。 Viola-Jones 级联检测方法查找强度梯度眼睛区域比下面的区域暗在这种情况下由于眼镜右镜片的眩光它无法在右眼中检测到 可在这个页面中找到用于摄像头视频中的面部和眼睛检测的 OpenCV Python 代码。 请注意为了使代码起作用您需要在文件夹中指定 Haar 级联检测器所在的路径。 到目前为止我们已经了解了 Haar 级联分类器以及如何使用内置的 OpenCV 代码将 Haar 级联分类器应用于面部和眼睛检测。 前述概念基于使用积分图像检测类似 Haar 的特征。 该方法非常适合面部眼睛嘴巴和鼻子的检测。 但是可以将不同的面部表情和皮肤纹理用于情感快乐与悲伤或年龄确定等。 Viola-Jones 方法不适用于处理这些不同的面部表情因此我们需要使用 Viola-Jones 方法进行面部检测然后应用神经网络确定面部边界框内的面部关键点。 在下一节中我们将详细学习此方法。 使用深度神经网络预测面部关键点 在本节中我们将讨论面部关键点检测的端到端管道。 面部关键点检测对于计算机视觉来说是一个挑战因为它要求系统检测面部并获取有意义的关键点数据将这些数据绘制在面部上并开发出神经网络来预测面部关键点。 与对象检测或图像分类相比这是一个难题因为它首先需要在边界框内进行面部检测然后再进行关键点检测。 正常的对象检测仅涉及检测代表对象周围矩形边界框的四个角的四个点但是关键点检测需要在不同方向上的多个点超过 10 个。 可以在这个页面上找到大量的关键点检测数据及其使用教程。 Kaggle 关键点检测挑战涉及一个 CSV 文件该文件包含指向 7,049 个图像96 x 96的链接每个图像包含 15 个关键点。 在本部分中我们将不使用 Kaggle 数据但将向您展示如何准备自己的数据以进行关键点检测。 有关该模型的详细信息请参见这里。 准备用于关键点检测的数据集 在本节中您将学习如何创建自己的数据。 这涉及编写代码并执行代码以使 PC 中的网络摄像头点亮。 将您的脸部移动到不同的位置和方向然后按空格键在裁剪掉图像中的所有其他内容后它将保存您的脸部图像。 此过程的关键步骤如下 首先我们从指定 Haar 级联分类器的路径开始。 它应该位于您的OpenCV/haarcascades目录中。 那里将有很多.xml文件因此请包含frontalface_default.xml的路径 face_cascade cv2.CascadeClassifier(path tohaarcascade_frontalface_default.xml)接下来我们将使用videoCapture(0)语句定义网络摄像头操作。 如果您的计算机已插入外部摄像机则可以使用videoCapture(1) cam cv2.VideoCapture(0)相机帧使用cam.read()读取数据然后在每个帧内使用“步骤 1”中定义的 Haar 级联检测器检测面部。 使用(x,y,w,h)参数在检测到的面部周围绘制一个边框。 使用cv2.imshow参数屏幕上仅显示检测到的面部 while(True):ret, frame cam.read()faces face_cascade.detectMultiScale(frame, 1.3, 5)for (x,y,w,h) in faces:if w 130:detected_face frame[int(y):int(yh), int(x):int(xw)]cv2.imshow(test, detected_face)if not ret:breakk cv2.waitKey(1)接下来将图像调整为img_size将其定义为299并将结果图像保存在数据集目录中。 注意在本练习中我们使用299的图像大小但是可以更改。 但是如果您决定更改它请确保在标注文件的创建以及最终模型中进行更改以避免标注和图像之间的不匹配。 现在在此 Python 代码所在的目录中创建一个名为dataset的文件夹。 请注意每次按空格键时图像文件号都会自动增加 faceresize cv2.resize(detected_face, (img_size,img_size))img_name dataset/opencv_frame_{}.jpg.format(img_counter)cv2.imwrite(img_name, faceresize)为不同面部表情的不同人创建约 100 幅或更多图像对于该测试我总共拍摄了 57 张图像。 如果您有更多图像则检测会更好。 请注意Kaggle 面部点检测使用 7,049 张图像。 拍摄所有图像并使用 VGG 标注器执行面部关键点标注您可以从这里获得该标注器。 您可以使用其他选择的标注工具但是我发现此工具免费非常有用。 它绘制边界框以及不规则形状和绘制点。 在本练习中我加载了所有图像并使用点标记在图像中绘制了 16 个点如下图所示 上图中的 16 个点代表左眼1-3右眼4-6鼻子7嘴唇8-11和外面12-16。 请注意当我们以数组形式显示图像关键点时它们将被表示为 0–15 而不是 1–16。 为了获得更高的准确率您只能捕获面部图像而不是任何周围环境。 处理关键点数据 VGG 标注器工具会生成一个输出 CSV 文件该文件需要进行两次预处理才能为每个图像的 16 个关键点分别生成(x, y)坐标。 对于大数据处理来说这是一个非常重要的概念您可以将其用于其他计算机视觉任务主要有以下三个原因 我们的 Python 代码不会直接在目录中搜索大量图像文件而是会在输入 CSV 中搜索数据路径。对于每个 CSV 文件有 16 个相应的关键点需要处理。这是使用 Keras ImageDataGenerator和flow_from_directory方法浏览目录中每个文件的替代方法。 为了澄清此内容本节分为以下两个小节 在输入 Keras-Python 代码之前进行预处理Keras–Python 代码中的预处理 让我们详细讨论每个。 输入 Keras-Python 代码之前的预处理 VGG 标注器工具会生成一个输出 CSV 文件该文件需要以我们的 TensorFlow 代码可接受的格式进行预处理。 标注的输出是一个 CSV 文件该 CSV 文件以行格式显示每个关键点每个图像有 16 行。 我们需要对该文件进行预处理以便每个图像有一行。 共有 33 列指示 32 个关键点值和1图像值如下所示 (x0, y0), (x1, y1), (x2, y2), …, (x15, y15)图像文件名 您可以使用自定义 Python 程序对此进行转换尽管此处未显示。 GitHub 页面包含已处理的 CSV 文件在这里供您参考。 Keras–Python 代码中的预处理 在本节中我们将以X和Y数据的形式读取 CSV 文件其中X是与每个文件名相对应的图像而Y具有 16 个关键点坐标的 32 个值。 然后我们将每个关键点的Y数据切片为 16 Yx和Yy坐标。 详细步骤如下所示 使用标准 Python 命令阅读上一部分的 CSV 文件。 在此我们使用位于faceimagestrain目录中的两个 CSV trainimgface.csv和testimgface.csv。 如果需要可以使用其他文件夹 train_path faceimagestrain/trainimgface.csv test_path faceimagestrain/testimgface.csv train_data pd.read_csv(train_path) test_data pd.read_csv(test_path)接下来我们在 CSV 文件中找到与图像文件相对应的列。 在以下代码中图像文件的列名称为image coltrn train_data[image] print (coltrn.shape[0])接下来我们初始化两个图像数组imgs和Y_train。 我们读取train_data数组以向image列添加路径并在for循环中读取coltrn.shape[0]定义的 50 个图像文件中的每个图像文件并将其附加到图像数组中。 使用OpenCV BGR2GRAY命令将读取的每个图像转换为灰度。 在同一for循环中我们还使用training.iloc[i,:]命令读取 32 列中的每一列并将其附加到Y_train的数组中 imgs [] training train_data.drop(image,axis 1) Y_train [] for i in range (coltrn.shape[0]):p os.path.join(os.getcwd(), faceimagestrain/str(coltrn.iloc[i]))img cv2.imread(p, 1)gray_img cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)imgs.append(gray_img)y training.iloc[i,:]Y_train.append(y)最后使用以下代码将图像转换为称为X_train的 NumPy 数组这是输入 Keras 模型所必需的 X_train np.asarray(imgs) Y_train np.array(Y_train,dtype float) print(X_train.shape, Y_train.shape)对测试数据重复相同的过程。 现在我们已经准备好训练和测试数据。 在继续之前我们应该可视化图像中的关键点以确保它们看起来不错。 使用以下命令完成此操作 x0Y_trainx.iloc[0,:] y0Y_trainy.iloc[0,:] plt.imshow(np.squeeze(X_train[0]),cmapgray) plt.scatter(x0, y0,color red) plt.show()在前面的代码中np.squeeze用于删除最后一个尺寸因此图像中只有x和y值。 plt.scatter在图像顶部绘制关键点。 输出如下图所示 上图显示了叠加在图像顶部的 16 个关键点表示图像和关键点对齐。 左图和右图表示训练和测试图。 此视觉检查对于确保所有预处理步骤都不会导致不正确的面对点对齐至关重要。 定义模型架构 该模型涉及使用卷积神经网络CNN处理面部图像及其 16 个关键点。 有关 CNN 的详细信息请参阅“第 4 章”“图像深度学习”。 CNN 的输入是训练图像和测试图像及其关键点其输出将是与新图像相对应的关键点。 CNN 将学习预测关键点。 下图显示了模型架构的详细信息 先前模型的代码如下 model Sequential() model.add(Conv2D(32, (3, 3), input_shape(299,299,1), paddingsame, activationrelu)) model.add(MaxPooling2D(pool_size(2, 2))) model.add(Conv2D(64, (3, 3), activationrelu)) model.add(Conv2D(64, (3, 3), activationrelu)) model.add(MaxPooling2D(pool_size(2, 2))) model.add(Dropout(0.2)) model.add(Conv2D(128, (3, 3), activationrelu)) model.add(Conv2D(128, (3, 3), activationrelu)) model.add(MaxPooling2D(pool_size(2, 2))) model.add(Dropout(0.2)) model.add(Conv2D(256, (3, 3), activationrelu)) model.add(Conv2D(256, (3, 3), activationrelu)) model.add(MaxPooling2D(pool_size(2, 2))) model.add(Dropout(0.2)) model.add(Flatten()) model.add(Dense(500, activationrelu)) model.add(Dense(500, activationrelu)) model.add(Dense(32))该代码拍摄一张图像并应用 32 个大小为(3, 3)的卷积过滤器然后激活和最大池化层。 它重复相同的过程多次并增加过滤器的数量然后是平坦且密集的层。 最终的密集层包含 32 个元素分别代表我们要预测的关键点的x和y值。 为关键点预测训练模型 现在我们已经定义了模型在本小节中我们将编译模型重塑模型的输入并通过执行以下步骤开始训练 我们将从定义模型损失参数开始如下所示 adam Adam(lr0.001) model.compile(adam, lossmean_squared_error, metrics[accuracy])然后对数据进行整形以输入到 Keras 模型。 重塑数据很重要因为 Keras 希望以 4D 形式显示数据-数据数50图像宽度图像高度 1灰度 batchsize 10 X_train X_train.reshape(50,299,299,1) X_test X_test.reshape(7,299,299,1) print(X_train.shape, Y_train.shape, X_test.shape, Y_test.shape)模型X和Y参数说明如下 X_train (50, 299, 299, 1) 1 的训练数据图像宽度图像高度灰度Y_train (50, 32)训练数据关键点数-在这里我们有x和y值的 16 个关键点使其成为 32X_test (7, 299, 299, 1) 1 个测试数据图像宽度图像高度灰度Y_test (7, 32)测试数据关键点-在这里我们为x和y值有 16 个关键点使其成为 32 训练是通过model.fit命令启动的如下所示 history model.fit(X_train, Y_train, validation_data(X_test, Y_test), epochs20, batch_sizebatchsize)训练步骤的输出如下图所示 该模型在大约 10 个时间周期内获得了相当好的准确率但损失项约为 7000。我们需要收集更多的图像数据以将损失项降至 1 以下 我们将使用model.predict根据测试数据X_test预测模型输出y_val。 测试数据X_test是图像但是它们已经以模型可以理解的数组形式进行了预处理 y_val model.predict(X_test)请注意此处y_val对于每个预处理的图像数组输入都有 32 个点。 接下来我们将 32 个点细分为代表 16 个关键点的x和y列 yvalx y_val[::1,::2] yvaly y_val[:, 1::2]最后使用以下代码在图像上方绘制预测的 16 个关键点 plt.imshow(np.squeeze(X_test[6]),cmapgray) plt.scatter(yvalx[6], yvaly[6], color red) plt.show()请注意对于 50 张图片模型预测效果不是很好 这里的想法是向您展示该过程以便您随后可以通过收集更多图像在此代码的基础上进行构建。 随着图像数量的增加模型精度将提高。 尝试为不同的人和不同的方向拍摄图像。 如“第 9 章”“使用多任务深度学习的动作识别”中所述可以将此处描述的技术扩展为与身体关键点检测一起使用。 此外“第 11 章”“通过 CPU/GPU 优化在边缘设备上进行深度学习”在 Raspberry Pi 上针对 OpenVINO 提供了一个部分其中提供了 Python 代码基于 OpenVINO 工具包预训练模型的集成来预测和显示 35 个面部关键点 。 使用 CNN 预测面部表情 面部表情识别是一个具有挑战性的问题因为面部光线和表情嘴巴眼睛睁开的程度等各不相同并且还需要开发一种架构并选择可以持续获得较高对比度的参数。 准确率。 这意味着挑战不仅在于在一个照明条件下为一个人正确确定一个面部表情而且要在所有照明条件下正确识别所有戴着或不戴眼镜帽子等的人的所有面部表情。 以下 CNN 示例将情感分为七个不同的类别愤怒反感害怕快乐悲伤惊讶和中立。 面部表情识别所涉及的步骤如下 导入函数-SequentialConv2DMaxPooling2DAvgPooling2DDenseActivationDropout和Flatten。导入ImageDataGenerator-通过实时增强定向生成一批张量图像。确定分类的批量大小和周期。数据集-训练测试和调整大小(48, 48)。建立 CNN 架构如下图所示。使用fit-generator()函数训练开发的模型。评估模型。 下图显示了 CNN 架构 下图显示了模型的结果。 在大多数情况下它可以正确预测面部表情 很清楚地检测到强烈的情感笑脸或生气的脸。 CNN 模型能够正确预测各种情感甚至微妙的情感。 3D 人脸检测概述 3D 面部识别涉及测量面部中刚性特征的几何形状。 通常是通过使用飞行时间测距相机生成 3D 图像或从对象的 360 度方向获取多个图像来获得的。 传统的 2D 相机将 3D 空间转换为 2D 图像这就是为什么深度感应是计算机视觉的基本挑战之一的原因。 基于飞行时间的深度估计基于光脉冲从光源传播到物体再返回到相机所需的时间。 同步光源和图像获取深度。 飞行时间传感器能够实时估计全深度帧。 飞行时间的主要问题是空间分辨率低。 3D 人脸识别可以分为以下三个部分 3D 重建的硬件设计概述3D 重建和跟踪概述参数化跟踪概述 3D 重建的硬件设计概述 3D 重建涉及相机传感器照明和深度估计。 3D 重建中使用的传感器可以分为三类 多视图设置具有受控照明的经过校准的密集立体摄像机数组。 从每个立体对中使用三角剖分重构面部几何形状然后在加强几何一致性的同时进行聚合。RGB 照相机组合多个 RGB 照相机以基于飞行时间方法计算深度。RGBD 摄像机RGBD 摄像机同时捕获颜色和深度-例如 Microsoft KinectPrimesense Carmine 和 Intel Realsense。 3D 重建和跟踪概述 3D 面部重建包括通过构造 CNN 通过使深度回归来从对应的 2D 图像估计 3D 面部的坐标。 下图以图形方式说明了这一点 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oZINNSj6-1681784327301)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/master-cv-tf-2x/img/59370f0a-70ba-46da-a36c-85616d149f32.png)] 实时 3D 曲面贴图的一些流行算法描述如下 Kinect Fusion使用 Kinect 深度传感器的实时 3D 构造。 Kinect 是一种商品传感器平台其中包含 30 Hz 的基于结构的飞行时间深度传感器。动态融合使用单个 Kinect 传感器使用体积 TSDF截断有符号距离融合技术的动态场景重建系统。 它需要一个嘈杂的深度图并通过估计体积 6D 运动场来重建实时 3D 运动场景。Fusion4D这使用多个实时 RGBD 摄像机作为输入并使用体积融合以及使用密集对应字段的非刚性对齐来处理多个图像。 该算法可以处理较大的帧到帧运动和拓扑更改例如人们快速脱下外套或从左到右更改其面部方向。Motion2Fusion此方法是用于实时每秒 100 帧重建的 360 度表现捕获系统。 它基于具有学习的 3D 嵌入的非刚性对齐策略快速匹配策略用于 3D 对应估计的机器学习以及用于复杂拓扑更改的后向/向前非刚性对齐策略。 参数化跟踪概述 面部跟踪模型将投影的线性 3D 模型用于摄像机输入。 它执行以下操作 跟踪从前一帧到当前帧的视觉特征对齐 2D 形状来跟踪特征根据深度测量计算 3D 点云数据最小化损失函数 总结 尽管由于各种肤色方向面部表情头发颜色和光照条件而引起的复杂性面部识别仍然是计算机视觉的成功故事。 在本章中我们学习了面部检测技术。 对于每种技术您都需要记住面部检测需要大量训练有素的图像。 人脸检测已在许多视频监控应用中广泛使用并且 Google亚马逊微软和英特尔等公司的基于云的设备和边缘设备均可使用标准 API。 我们将在“第 11 章”“对具有 CPU/GPU 优化功能的边缘设备进行深度学习”中了解基于云的 API并在“第 4 章”“图像深度学习”和第 5 章“神经网络架构和模型”。 在本章中简要介绍了用于面部检测和表情分类的 CNN 模型。 在下一章中将详细说明 CNN。 这将帮助您了解 CNN 的构造块为何选择某些功能块以及每个块在最终对象检测指标中的作用。 之后我们将参考 “第 3 章”“使用 OpenCV 和 CNN 进行面部检测”的示例以评估如何优化 CNN 参数以更好地进行面部检测。 四、用于图像的深度学习 边缘检测的概念在“第 1 章”“计算机视觉和 TensorFlow 基础知识”中进行了介绍。 在本章中您将学习如何使用边缘检测在体积上创建卷积运算以及不同的卷积参数例如过滤器大小尺寸和操作类型卷积与池化如何影响卷积体积宽度与深度。 本章将为您提供有关神经网络如何查看图像以及图像如何使用可视化对图像进行分类的非常详细的概述。 您将从建立第一个神经网络开始然后在图像通过其不同层时对其进行可视化。 然后您将网络模型的准确率和可视化与诸如 VGG 16 或 Inception 之类的高级网络进行比较。 请注意本章和下一章将提供神经网络的基础理论和概念以及当今实际使用的各种模型。 但是这个概念是如此广泛以至于不可能将您需要了解的所有内容都放在这两章中。 因此为了便于阅读将为每章讨论的主题引入其他概念从“第 6 章”“使用迁移学习的视觉搜索”开始请参考这些章节以防您不得不阅读本书。 在本章中我们将介绍以下主题 了解 CNN 及其参数优化 CNN 参数可视化神经网络的各个层 了解 CNN 及其参数 卷积神经网络CNN是一种自学习网络它通过观察不同类别的图像来对类似于人类大脑学习方式的图像进行分类。 CNN 通过应用图像滤波并处理各种过滤器大小数量和非线性运算的方法来学习图像的内容。 这些过滤器和操作应用于多个层以便在图像转换过程中每个后续层的空间尺寸减小并且其深度增大。 对于每个过滤应用所学内容的深度都会增加。 首先从边缘检测开始然后识别形状然后识别称为特征的形状集合依此类推。 当我们理解信息时这类似于人脑。 例如在阅读理解测试中我们需要回答关于段落的五个问题每个问题都可以视为一类需要从段落中获得特定信息的必须回答的问题 首先我们浏览整个通道这意味着空间维度是完整的通道而深度我们对通道的理解很小因为我们只是浏览了整个通道。 接下来我们浏览问题以了解每个类的特征问题即在文章中寻找的内容。 在 CNN 中这等效于考虑要使用哪些卷积和池化操作来提取特征。 然后我们阅读文章的特定部分以找到与全类相似的内容并深入探讨这些部分–在这里空间维度很小但深度很大。 我们重复此过程 2 至 3 次以回答所有问题。 我们将继续加深我们的理解深度并更加专注于特定领域缩小维度直到我们有一个很好的理解为止。 在 CNN 中这等效于逐渐增加深度并缩小尺寸–卷积操作通过更改过滤器数量来更改深度 合并会缩小尺寸。 为了节省时间我们倾向于跳过段落以找到与答案匹配的相关段落。 在卷积中这等效于跨步跨步会缩小尺寸但不会更改深度。 下一步是将问题与文章的答案相匹配。 我们通过在精神上使问题的答案保持一致来做到这一点。 在这里我们不会做得更深入–我们将问题和答案并排放置以便我们进行匹配。 在 CNN 中这等效于展平并使用全连接层。 在此过程中我们可能会有过多的信息–我们将其删除以便仅与段落中的问题相关的信息可供我们使用。 在 CNN 中这等效于丢弃。 最后一个阶段实际上是进行匹配练习以回答问题。 在 CNN 中这等效于 Softmax 操作。 CNN 的图像过滤和处理方法包括执行多种操作所有这些操作都可以通过以下方式进行 卷积Conv2D卷积 – 3 x 3过滤器卷积 – 1 x 1过滤器池化填充跨步激活全连接层正则化丢弃内部协方差平移和批量归一化Softmax 下图说明了 CNN 及其组件 让我们研究一下每个组件的功能。 卷积 卷积是 CNN 的主要构建块。 它包括将图像的一部分与核过滤器相乘以产生输出。 卷积的概念在“第 1 章”“计算机视觉和 TensorFlow 基础知识”中进行了简要介绍。 请参考该章以了解基本概念。 通过在输入图像上滑动核来执行卷积操作。 在每个位置执行逐元素矩阵乘法然后在乘法范围内进行累加和。 每次卷积操作之后CNN 都会从图像中学到更多信息–它首先是学习边缘然后是下一次卷积中的形状然后是图像的特征。 在卷积操作期间过滤器的大小和过滤器的数量可以改变。 通常在通过卷积合并和跨步操作减小特征映射的空间尺寸之后增加过滤器的数量。 当过滤器尺寸增加时特征映射的深度也会增加。 下图说明了当我们有两个不同的边缘检测核选择时的 Conv2D 上图显示了以下要点 如何通过在输入图像上滑动3 x 3窗口来执行卷积操作。逐元素矩阵乘法和总和结果用于生成特征映射。随着多次卷积运算而堆叠的多个特征映射将生成最终输出。 卷积 – 3 x 3过滤器 在前面的示例中我们在二维图像灰度上应用了3 x 3卷积。 在本节中我们将学习具有三个通道红色绿色和蓝色RGB的三维图像如何使用卷积运算的3 x 3边缘过滤器对进行变换。 下图以图形方式显示了此转换 上图显示了如何使用3 x 3过滤器边缘检测器在宽度减小和深度增加从 3 到 32方面转换3 x 3图像的图的一部分。 核f[i]中 27 个3 x 3 x 3单元中的每一个都乘以输入A[i]。 然后将这些值与整流线性单元ReLU激活函数b[i]相加在一起来形成单个元素Z如以下等式所示 通常在卷积层中有许多执行不同类型边缘检测的过滤器。 在前面的示例中我们有 32 个过滤器这将导致 32 个不同的栈每个栈由5 x 5层组成。 3 x 3过滤器将在本书的其余部分中广泛用于神经网络开发。 例如您将在 ResNet 和 Inception 层中看到大量使用它我们将在“第 5 章”“神经网络架构和模型”中进行讨论。 TensorFlow 中可以将大小为3 x 3的 32 个过滤器表示为.tf.keras.layers.Conv2D(32, (3,3))。 在本章的后面您将学习如何将此卷积与 CNN 的其他层一起使用。 卷积 – 1 x 1过滤器 在本节中我们将学习1 x 1卷积的重要性及其用例。 1 x 1卷积过滤器是图像的直倍数如下图所示 在上图中在上一节输出的5 x 5图像上使用了5 x 5卷积过滤器值 1但实际上它可以是任何数字。 在这里我们可以看到使用5 x 5过滤器可以保留其高度和宽度而深度则增加到过滤器通道的数量。 这是5 x 5过滤器的基本优点。 三维核f[i]中三个1 x 1 x 3单元中的每一个都与输入的相应三个单元相乘 A[i]。 然后将这些值与 ReLU 激活函数b[i]一起加在一起以形成单个元素Z 上图显示1 x 1过滤器使深度增加而相同的1 x 1过滤器可用于减小值如下图所示 上图显示了1 x 1 x 128图像过滤器如何将卷积深度减少到 32 个通道。 1 x 1卷积在所有 128 个通道中与5 x 5输入层执行逐元素乘法–将其在深度维度上求和并应用 ReLU 激活函数在5 x 5输出中创建单个点表示 128 的输入深度。本质上通过使用这种机制卷积 整个深度的和它会将三维体积折叠为具有相同宽度和高度的二维数组。 然后它应用 32 个过滤器以创建5 x 5 x 32输出如前所示。 这是有关 CNN 的基本概念因此请花一些时间来确保您理解这一点。 本书将使用1 x 1卷积。 稍后您将了解到池化会减小宽度而1 x 1卷积会保留宽度但可以根据需要收缩或扩展深度。 例如您将看到在网络和 Inception 层中使用了1 x 1卷积在“第 5 章”“神经网络架构和模型”中。具有1 x 1的 32 过滤器 的卷积可以在 TensorFlow 中表示为.tf.keras.layers.Conv2D(32, (1,1))。 池化 池化是卷积之后的下一个操作。 它用于减小尺寸和特征映射的大小宽度和高度而无需更改深度。 轮询参数的数量为零。 池的两种最受欢迎​​的类型如下 最大池化平均池化 在最大池化中我们在特征映射上滑动窗口并获取窗口的最大值而在进行平均池化时我们获取窗口中的平均值。 卷积层和池化层一起执行特征提取的任务。 下图显示了在7 x 7图像上使用的最大和平均池化操作 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wr5CM14c-1681784327303)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/master-cv-tf-2x/img/e008ce29-8194-4fe6-baa0-058c073a2f98.png)] 请注意由于合并3 x 3窗口如何缩小由绿线显示为单个值从而导致5 x 5矩阵尺寸更改为5 x 5矩阵。 填充 填充用于保留特征映射的大小。 通过卷积可能会发生两个问题并且填充会同时解决两个问题 每次卷积操作时特征映射的大小都会缩小。 例如在上图中由于卷积一个7 x 7的特征映射缩小为5 x 5。由于边缘上的像素仅更改一次因此边缘上的信息会丢失而中间的像素会通过多次卷积操作进行多次更改。 下图显示了在7 x 7输入图像上使用大小为 1 的填充操作 请注意填充如何保留尺寸以便输出与输入的尺寸相同。 跨步 通常在卷积中我们将核移动一步对那一步应用卷积依此类推。 跨步使我们可以跳过一步。 让我们来看看 当跨步为 1 时我们应用普通卷积而不跳过。当跨步为 2 时我们跳过一步。 这会将图像大小从7 x 7减小到3 x 3请参见下图 在这里每个3 x 3窗口显示跳过一个步骤的结果。 大步的结果是缩小尺寸因为我们跳过了可能的xy位置。 激活 激活层为神经网络增加了非线性。 这是至关重要的因为图像和图像中的特征是高度非线性的问题而 CNN 中的大多数其他功能Conv2D池化全连接层等仅生成线性变换。 激活函数在将输入值映射到其范围时生成非线性。 没有激活函数无论添加多少层最终结果仍然是线性的。 使用了多种类型的激活函数但最常见的激活函数如下 SigmoidTanhReLU 下图显示了上述激活函数 每个激活函数都显示非线性行为当输入大于 3 时Sigmoid 和 Tanh 接近 3而 ReLU 继续增加。 下图显示了不同的激活函数对输入大小的影响 与 Tanh 和 Sigmoid 激活函数相比ReLU 激活函数具有以下优点 与 ReLU 相比Sigmoid 和 Tanh 的梯度问题学习缓慢的人消失了因为它们在输入值大于 3 时都接近 1。对于小于 0 的输入值Sigmoid 激活函数仅具有正值。ReLU 函数对计算有效。 全连接层 全连接层也称为密集层通过对它们施加权重和偏差来将当前层中的每个连接神经元连接到上一层中的每个连接神经元。 权重和偏差的向量称为过滤器。 这可以用以下等式表示 如“卷积”部分中所述过滤器可以采用边缘过滤器的形式来检测边缘。 在神经网络中许多神经元共享同一过滤器。 权重和过滤器允许全连接层充当分类器。 正则化 正则化是一种用于减少过拟合的技术。 为此可以在模型误差函数中添加一个附加项模型输出-训练值以防止模型权重参数在训练过程中取极端值。 CNN 中使用三种类型的正则化 L1 正则化对于每个模型权重w一个附加参数λ |w|添加到模型目标。 这种正则化过程使优化过程中的权重因子稀疏接近零。L2 正则化对于每个模型权重w附加参数1/2 λw^2被添加到模型目标 。 这种正则化使得权重因子在优化过程中扩散。 可以期望 L2 正则化比 L1 正则化具有更好的表现。最大范数正则化这种类型的正则化为 CNN 的权重添加了最大限制因此|w| c其中c可以为 3 或 4。即使学习率很高最大范数约束也可以防止神经网络过拟合。 丢弃 丢弃是一种特殊的正则化类型指的是忽略神经网络中的神经元。 具有dropout 0.2的全连接层意味着仅 80% 的全连接神经元连接到下一层。 在当前步骤中神经元被丢弃但在下一步中处于活动状态。 丢弃可防止网络依赖少量神经元从而防止过拟合。 丢弃应用于输入神经元但不应用于输出神经元。 下图显示了带有和不带有丢弃的神经网络 以下是丢弃的优点 丢弃迫使神经网络学习更强大的特征。每个周期的训练时间较少但是迭代次数增加了一倍。丢弃可提高准确率-约 1-2%。 内部协方差平移和批量归一化 在训练过程中每层输入的分布会随着上一层的权重因子的变化而变化从而导致训练变慢。 这是因为它要求较低的学习率和权重因子选择。 谢尔盖·艾菲Sergey Ioffe和克里斯汀·塞格迪Christian Szegedy在题为《批量归一化通过减少内部协方差漂移加速深度网络训练》的论文中称这种现象内部协方差漂移。 有关详细信息请参阅这里。 批量归一化通过从当前输入中减去上一层的批量平均值并将其除以批量标准差来解决协方差移位的问题。 然后将此新输入乘以当前权重系数再乘以偏置项以形成输出。 下图显示了带有和不带有批量规范化的神经网络的中间输出特征 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qJ1gh7qa-1681784327304)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/master-cv-tf-2x/img/9f7bea49-6361-4095-b359-0cea59b897c5.png)] 当应用批量归一化时我们在大小为m的整个迷你批量中计算均值μ和方差σ。 然后利用这些信息我们计算归一化的输入。 微型批量的输出计算为比例γ乘以归一化输入再加上偏移量β。 在 TensorFlow 中这可以表示如下。 除方差ε外所有项均在上图中进行了解释方差ε是归一化输入计算中的ε项以避免被零除 tf.nn.batch_normalization(x,mean,variance,offset,scale,variance_epsilon,nameNone)麻省理工学院的 Shibani SanturkarDimitris TsiprasAndrew Ilyas 和 Aleksander Madry 在其论文中详细阐述了批量规范化的优势。 可以在这个页面中找到该论文的详细信息。 该论文的作者发现批量归一化并不能减少内部协方差漂移。 批量归一化的学习速度可以归因于归一化输入的平滑性这归因于归一化输入而不是常规输入数据的使用规则数据可能由于扭结尖锐的边缘和局部最小值或最大值而具有较大的差异。 这使梯度下降算法更加稳定从而允许它使用更大的步长以实现更快的收敛。 这样可以确保它不会出现任何错误。 Softmax Softmax 是在 CNN 的最后一层中使用的激活函数。 它由以下等式表示其中P是每个类别的概率n是类别的总数 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PEMfCDo6-1681784327305)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/master-cv-tf-2x/img/87a750bf-5242-423b-86b0-af8851ad2df5.png)] 下表显示了使用前面描述的 Softmax 函数时七个类中每个类的概率 这用于计算每个类别的分布概率。 优化 CNN 参数 CNN 具有许多不同的参数。 训练 CNN 模型需要许多输入图像并执行处理这可能非常耗时。 如果选择的参数不是最佳参数则必须再次重复整个过程。 这就是为什么理解每个参数的功能及其相互关系很重要的原因这样可以在运行 CNN 之前优化其值以最大程度地减少重复运行。 CNN 的参数如下 图像尺寸为(n x n)过滤器为(f[h], f[w])f[h]为应用于图像高度的过滤器f[w]为应用于图像宽度的过滤器过滤器数量为n[f]填充为p跨步为s输出大小为{(n 2p - f)/s 1} x {(n 2p - f)/s 1}参数数量为(f[h] x f[w] 1) x n[f] 关键任务是选择上述参数过滤器大小f过滤器数量nf跨步s填充 CNN 每一层的值p激活a和偏差。 下表显示了各种 CNN 参数的特征映射 上表的每个参数说明如下 输入图像第一输入层是大小为(48 x 48)的灰度图像因此深度为1。 特征映射大小48 x 48 x 1 2,304。 它没有参数。第一卷积层 CONV1 (filter shape 5*5, stride1)层的高度宽度为(48-51) 44特征映射大小为44 x 44 x 64 123904参数数为(5 x 5 1) x 64 1,664。第一池化层POOL1池化层没有参数。剩余的卷积和池化层剩余的计算 – CONV2, CONV3, CONV4, CONV5, POOL2 – 遵循与第一卷积层相同的逻辑。全连接FC层对于全连接层(FC1, FC2)参数的数量为[(current layer n * previous layer n) 1] 128 * 1,024 1 131,073。丢弃DROP对于丢弃将丢弃 20% 的神经元。 剩余的神经元为1,024 * 0.8 820。 第二次删除的参数数为820 x 820 1 672401。CNN 的最后一层始终是 Softmax对于 Softmax参数数为7 x 820 1 5,741。 在“第 3 章”“使用 OpenCV 和 CNN 进行面部检测”的第一张图中用于面部表情识别的神经网络类别有 7 个类别其准确率约为 54%。 在以下各节中我们将使用 TensorFlow 输出优化各种参数。 我们从基准情况开始然后尝试通过调整此处描述的参数进行五次迭代。 该练习应该使您对 CNN 的参数以及它们如何影响最终模型的输出有很好的了解。 基准案例 基线情况由神经网络的以下参数表示 实例数35,888实例长度2,30428,709 个训练样本3,589 个测试样本 模型迭代如下 Epoch 1/5256/256 [] - 78s 306ms/step - loss: 1.8038 - acc: 0.2528Epoch 2/5256/256 [] - 78s 303ms/step - loss: 1.6188 - acc: 0.3561Epoch 3/5256/256 [] - 78s 305ms/step - loss: 1.4309 - acc: 0.4459Epoch 4/5256/256 [] - 78s 306ms/step - loss: 1.2889 - acc: 0.5046Epoch 5/5256/256 [] - 79s 308ms/step - loss: 1.1947 - acc: 0.5444接下来我们将优化 CNN 参数以确定哪些参数在更改准确率时影响最大。 我们将分四次迭代运行此实验。 迭代 1 – CNN 参数调整 删除一个Conv2D 64 和一个Conv2D 128以使 CNN 仅具有一个Conv2D 64 和一个Conv2D 128 Epoch 1/5256/256 [] - 63s 247ms/step - loss: 1.7497 - acc: 0.2805Epoch 2/5256/256 [] - 64s 248ms/step - loss: 1.5192 - acc: 0.4095Epoch 3/5256/256 [] - 65s 252ms/step - loss: 1.3553 -acc: 0.4832Epoch 4/5256/256 [] - 66s 260ms/step - loss: 1.2633 - acc: 0.5218Epoch 5/5256/256 [] - 65s 256ms/step - loss: 1.1919 - acc: 0.5483结果放下Conv2D层不会对表现产生不利影响但也不能使其更好。 接下来我们将保留我们在此处所做的更改但是我们会将平均池转换为最大池。 迭代 2 – CNN 参数调整 删除一台Conv2D 64 和一台Conv2D 128以使 CNN 仅具有一台Conv2D 64 和一台Conv2D 128。 另外将平均池转换为最大池如下所示 Epoch 1/5256/256 [] - 63s 247ms/step - loss: 1.7471 - acc: 0.2804Epoch 2/5256/256 [] - 64s 252ms/step - loss: 1.4631 - acc: 0.4307Epoch 3/5256/256 [] - 66s 256ms/step - loss: 1.3042 - acc: 0.4990Epoch 4/5256/256 [] - 66s 257ms/step - loss: 1.2183 - acc: 0.5360Epoch 5/5256/256 [] - 67s 262ms/step - loss: 1.1407 - acc: 0.5691结果同样此更改对准确率没有明显影响。 接下来我们将大大减少隐藏层的数量。 我们将更改输入层并完全删除第二个Conv2D和关联的池。 在第一个Conv2D之后我们将直接移至第三个Conv2D。 迭代 3 – CNN 参数调整 第二个卷积层完全掉落 输入层从5 x 5更改为3 x 3 model.add(Conv2D(64, (3, 3), activationrelu, input_shape(48,48,1)))第三卷积层保持不变。 该层如下 model.add(Conv2D(128, (3, 3), activationrelu)) model.add(AveragePooling2D(pool_size(3,3), strides(2, 2)))密集层没有变化。 输出如下 Epoch 1/5256/256 [] - 410s 2s/step - loss: 1.6465 - acc: 0.3500Epoch 2/5256/256 [] - 415s 2s/step - loss: 1.3435 - acc: 0.4851Epoch 3/5256/256 [] - 412s 2s/step - loss: 1.0837 - acc: 0.5938Epoch 4/5256/256 [] - 410s 2s/step - loss: 0.7870 - acc: 0.7142Epoch 5/5256/256 [] - 409s 2s/step - loss: 0.4929 - acc: 0.8242结果计算时间很慢但精度达到最佳状态即 82%。 迭代 4 – CNN 参数调整 在此迭代中所有参数均与上一个迭代中的参数相同除了strides 2它在第一个Conv2D之后添加。 接下来我们将所有内容保持不变但是在第一个Conv2D之后添加一个池化层 model.add(Conv2D(64, (3, 3), activationrelu, input_shape(48,48,1))) model.add(AveragePooling2D(pool_size(3,3), strides(2, 2))) model.add(Conv2D(128, (3, 3), activationrelu)) model.add(AveragePooling2D(pool_size(3,3), strides(2, 2)))在此迭代中不会更改密集层。 计算时间更快但准确率下降了 Epoch 1/5256/256 [] - 99s 386ms/step - loss: 1.6855 - acc: 0.3240Epoch 2/5256/256 [] - 100s 389ms/step - loss: 1.4532 - acc: 0.4366Epoch 3/5256/256 [] - 102s 397ms/step - loss: 1.3100 - acc: 0.4958Epoch 4/5256/256 [] - 103s 402ms/step - loss: 1.1995 - acc: 0.5451Epoch 5/5256/256 [] - 104s 407ms/step - loss: 1.0831 - acc: 0.5924结果类似于基线迭代中的结果即 1 和 2。 从这个实验中我们可以得出以下有关 CNN 参数优化的结论 减少Conv2D的数量并以stride 2消除一个合并层具有最显着的效果因为它提高了准确率大约 30%。 但是这是以速度为代价的因为 CNN 的大小没有减小。合并类型平均合并与最大合并对测试准确率的影响不明显。 产生最高准确率的 CNN 架构如下 请注意与原始架构相比该架构要简单得多。 在下一章中您将了解一些最新的卷积模型以及为什么要使用它们。 然后我们将回到这个优化问题并学习如何更有效地选择参数以获得更好的优化。 可视化神经网络的各个层 在本章中我们了解了如何将图像转换为边缘然后转换为特征映射并且通过这样做神经网络能够通过组合许多特征映射来预测类。 在前几层中神经网络可视化线和角而在后几层中神经网络识别复杂的模式例如特征映射。 可以分为以下几类。 建立自定义图像分类器模型并可视化其层训练现有的高级图像分类器模型并可视化其层 让我们看一下这些类别。 建立自定义图像分类器模型并可视化其层 在本节中我们将开发自己的家具分类器网络。 这将分为三类沙发床和椅子。 基本过程描述如下。 该示例的详细代码可以在 GitHub 上找到。 请注意在“第 6 章”“使用迁移学习的视觉搜索”中我们将执行更高级的编码并使用相同的三个类提供详细的说明。 神经网络输入和参数 在本部分中模型输入各种 Keras 库和 TensorFlow。 在下面的代码中可以看到。 现在先加少许盐。 这将在“第 6 章”“使用迁移学习的视觉搜索”中全面说明 from __future__ import absolute_import, division, print_function, unicode_literals, import tensorflow as tf, from tensorflow.keras.applications import VGG16\n from keras.applications.vgg16 import preprocess_input,from keras import models from tensorflow.keras.models import Sequential, Model from tensorflow.keras.layers import Dense, Conv2D, Flatten, Dropout, GlobalAveragePooling2D, MaxPooling2D from tensorflow.keras.preprocessing.image import ImageDataGenerator\n, from tensorflow.keras.optimizers import SGD, Adam import os import numpy as np import matplotlib.pyplot as plt输入图像 在本节中我们定义训练和验证目录路径并使用os.path.join函数和类名在训练和验证目录中定义目录。 之后我们使用len命令计算每个类目录中的图像总数 train_dir furniture_images/train train_bed_dir os.path.join(train_dir, bed) num_bed_train len(os.listdir(train_bed_dir))训练目录中的图像总数是通过将每个类别中的图像总数相加得出的。 验证使用相同的方法最后导致输出为训练和验证目录中图像的总数。 训练期间神经网络将使用此信息。 定义训练和验证生成器 训练生成器和验证生成器使用一种称为图像数据生成和流的方法。 他们在目录上使用它输入张量图像。 有关此过程的详细信息请参阅 Keras 文档。 一个典型的例子如下。 如 Keras 文档中所述图像数据生成器具有许多参数但此处仅使用其中一些。 预处理输入将图像转换为张量。 输入旋转范围将图像旋转 90 度并垂直翻转以进行图像增强。 我们可以使用在“第 1 章”“计算机视觉和 TensorFlow 基础知识”中学习到的图像变换并使用rotation命令。 图像增强可以增加训练数据集从而在不增加测试数据量的情况下提高模型的准确率 train_datagen ImageDataGenerator(preprocessing_functionpreprocess_input,rotation_range90,horizontal_flipTrue,vertical_flipTrue)构建模型 准备好图像后我们就可以开始构建模型了。 Keras 顺序模型使我们能够做到这一点。 这是彼此堆叠的模型层的列表。 接下来我们通过堆叠卷积激活最大池丢弃和填充来构建顺序模型如以下代码所示 model Sequential([Conv2D(96, 11, paddingvalid, activationrelu,input_shape(img_height, img_width,3)), MaxPooling2D(),Dropout(0.2),Conv2D(256, 5, paddingsame, activationrelu),MaxPooling2D(),Conv2D(384, 3, paddingsame, activationrelu),Conv2D(384, 3, paddingsame, activationrelu), Conv2D(256, 3, paddingsame, activationrelu),MaxPooling2D(), Dropout(0.2),Conv2D(1024, 3, paddingsame, activationrelu), MaxPooling2D(),Dropout(0.2),Flatten(),Dense(4096, activationrelu), Dense(3)])该模型的基本思想与 AlexNet 相似将在“第 5 章”“神经网络架构和模型”中进行介绍。 该模型大约有 16 层。 编译和训练模型 接下来我们编译模型并开始训练。 编译option指定三个参数 优化器我们可以使用的优化器是adamrmspropsgdadadeltaadagradadamax和nadam。 有关 Keras 优化器的列表请参考这里 sgd代表随机梯度下降。 顾名思义它使用梯度值作为优化程序。adam代表自适应力矩。 它在最后一步中使用梯度来调整梯度下降参数。 Adam 运作良好几乎不需要调整。 在本书中将经常使用它。adagrad适用于稀疏数据并且几乎不需要调整。 对于adagrad不需要默认学习率。 损失函数用于图像处理的最常用损失函数是二进制交叉熵分类交叉熵均方误差或sparse_categorical交叉熵。 当分类任务是二进制时例如处理猫和狗图像或停车标志与无停车标志图像时将使用二进制交叉熵。 当我们有两个以上的类时例如配有床椅子和沙发的家具店将使用分类交叉熵。 稀疏分类交叉熵与分类交叉熵类似不同之处在于该类被其索引代替-例如我们将传递 0、1 和 2 而不是将床椅子和沙发作为类 指定类时出现错误可以使用稀疏分类交叉熵来解决此问题。 Keras 中还有许多其他损失函数。 有关更多详细信息请参阅这里。 指标这些指标用于设置准确率。 在下面的代码中我们使用adam优化器。 编译模型后我们使用 Keras model.fit()函数开始训练。 model.fit()函数将序列生成器用作我们先前定义的输入图像向量。 它还需要周期数迭代参数每个周期的步骤每个周期的批量数验证数据和验证步骤。 请注意将在“第 6 章”“使用迁移学习的视觉搜索”中详细描述每个参数 model.compile(optimizeradam,losstf.keras.losses.BinaryCrossentropy(from_logitsTrue), metrics[accuracy])history model.fit(train_generator,epochsNUM_EPOCHS,steps_per_epochnum_train_images // batchsize,validation_dataval_generator, validation_stepsnum_val_images // batchsize)训练持续 10 个周期。 在训练过程中模型的准确率随周期数的增加而增加 WARNING:tensorflow:sample_weight modes were coerced from...to[...]Train for 10 steps, validate for 1 stepsEpoch 1/1010/10 [] - 239s 24s/step - loss: 13.7108 - accuracy: 0.6609 - val_loss: 0.6779 - val_accuracy: 0.6667Epoch 2/1010/10 [] - 237s 24s/step - loss: 0.6559 - accuracy: 0.6708 - val_loss: 0.5836 - val_accuracy: 0.6693Epoch 3/1010/10 [] - 227s 23s/step - loss: 0.5620 - accuracy: 0.7130 - val_loss: 0.5489 - val_accuracy: 0.7266Epoch 4/1010/10 [] - 229s 23s/step - loss: 0.5243 - accuracy: 0.7334 - val_loss: 0.5041 - val_accuracy: 0.7292Epoch 5/1010/10 [] - 226s 23s/step - loss: 0.5212 - accuracy: 0.7342 - val_loss: 0.4877 - val_accuracy: 0.7526Epoch 6/1010/10 [] - 226s 23s/step - loss: 0.4897 - accuracy: 0.7653 - val_loss: 0.4626 - val_accuracy: 0.7604Epoch 7/1010/10 [] - 227s 23s/step - loss: 0.4720 - accuracy: 0.7781 - val_loss: 0.4752 - val_accuracy: 0.7734Epoch 8/1010/10 [] - 229s 23s/step - loss: 0.4744 - accuracy: 0.7508 - val_loss: 0.4534 - val_accuracy: 0.7708Epoch 9/1010/10 [] - 231s 23s/step - loss: 0.4429 - accuracy: 0.7854 - val_loss: 0.4608 - val_accuracy: 0.7865Epoch 10/1010/10 [] - 230s 23s/step - loss: 0.4410 - accuracy: 0.7865 - val_loss: 0.4264 - val_accuracy: 0.8021输入测试图像并将其转换为张量 到目前为止我们已经开发了图像目录并准备和训练了模型。 在本节中我们将图像转换为张量。 我们通过将图像转换为数组来从图像中生成张量然后使用 NumPy 的expand_dims()函数扩展数组的形状。 随后我们对输入进行预处理以准备图像使其具有模型所需的格式 img_path furniture_images/test/chair/testchair.jpg img image.load_img(img_path, target_size(150, 150)) img_tensor image.img_to_array(img) img_tensor np.expand_dims(img_tensor, axis0) img_tensor preprocess_input(img_tensor) featuremap model.predict(img_tensor)最后我们使用 Keras model.predict()函数输入图像张量然后将张量转换为特征映射。 现在您知道了如何通过将图像张量传递给我们刚刚开发的模型来计算特征映射。 可视化激活的第一层 为了计算激活我们计算每个层的模型输出。 在此示例中共有 16 层因此我们使用model.layers[:16]指定所有 16 层。 我们用于执行此操作的代码如下 layer_outputs [layer.output for layer in model.layers[:16]] activation_modelfig Model(inputsmodel.input, outputslayer_outputs) activationsfig activation_modelfig.predict(img_tensor)为了使用激活我们使用 Keras Model函数式 API当给定a时该 API 计算计算b所需的所有层 model Model(inputs[a1, a2], outputs[b1, b2, b3])对于我们的练习输入是我们先前计算的图像张量而输出是激活层。 接下来我们使用以下命令可视化第一层其中activationsfig[0]表示第一层。 要绘制它我们使用plt.matshow()。 在这里95是第一神经网络层的倒数第二个激活过滤器 first_layer_activation activationsfig[0] print(first_layer_activation.shape) plt.matshow(first_layer_activation[0, :, :, 95], cmapviridis)可视化多层激活 按照之前的操作我们运行for循环并使用plt.imshow方法在给定神经网络层的第一个中间和最后一个过滤器值中显示激活层 for i in range(0,12):current_layer_activation activationsfig[i]ns current_layer_activation.shape[-1]plt.imshow(current_layer_activation[0, :, :, 0], cmapviridis)plt.imshow(current_layer_activation[0, :, :, int(ns/2)], cmapviridis)plt.imshow(current_layer_activation[0, :, :, ns-1], cmapviridis)下图显示了椅子图像的最终输出值 在上图中n表示给定层的最大过滤器数。 n的值在不同的层可以不同。 例如对于第一层n的值为96而对于第四层其为256。 下表显示了自定义神经网络不同层的参数输出形状和过滤器 如您所见每个层都有许多不同的激活过滤器因此对于我们的可视化我们正在查看给定层的第一个过滤器中间过滤器和最后一个过滤器的可视化值。 最初的第一层代表椅子但是随着我们深入模型的层结构变得越来越抽象。 这意味着图像看起来不太像椅子而更像代表类的东西。 此外您可以看到某些层根本没有激活这表明模型的结构变得复杂且效率不高。 自然而然产生的一个大问题是神经网络如何处理来自最后一层的看似抽象的图像并从中提取出一个类 这是人类无法做的事情。 答案在于全连接层。 如上表所示共有 16 层但是i的可视化代码在(0, 12)范围内因此我们仅可视化前 12 层。 如果您尝试可视化更多则会收到错误消息。 在第 12 层之后我们展平该层并映射该层的每个元素-这称为全连接层。 这本质上是一个映射练习。 该神经网络将全连接层的每个元素映射到特定类别。 对所有类都重复此过程。 将抽象层映射到类是机器学习练习。 通过这样做神经网络能够预测类别。 下图显示了床图像的输出值 就像椅子的图像一样初始激活从类似于床的输出开始但是当我们深入网络时我们开始看到床与椅子相比的独特特征。 下图显示了沙发图像的输出值 就像椅子和床的示例一样前面的图从具有不同特征的顶层开始而最后几层则显示了特定于该类的非常抽象的图像。 请注意第 4、5 和 6 层很容易被替换因为这些层根本没有激活。 训练现有的高级图像分类器模型并可视化其层 我们发现我们开发的模型约有 16 层其验证准确率约为 80%。 由此我们观察了神经网络如何看到不同层的图像。 这带来了两个问题 我们的自定义神经网络与更高级的神经网络相比如何与我们的自定义神经网络相比高级神经网络如何看待图像 所有的神经网络都以相似或不同的方式看到图像吗 为了回答这些问题我们将针对两个高级网络 VGG16 和 InceptionV3 训练分类器并在网络的不同层上可视化椅子图像。 “第 5 章”“神经网络架构和模型”提供了网络的详细说明而“第 6 章”“使用迁移学习的视觉搜索”提供了代码的详细说明。 因此在本节中我们将只专注于可视化部分。 在完成“第 5 章”“神经网络架构和模型”和“第 6 章”之后您可能需要重新访问编码部分 以便您对代码有深刻的了解。 VGG 16 中的层数为 26。您可以在这个页面上找到有关此代码的代码。 请注意前面的代码同时运行自定义网络和 VGG 16 模型。 在此练习中请勿运行标记为自定义网络的单元以确保仅执行 VGG16 模型。 Keras 有一个简单的 API可以在其中导入 VGG16 或 InceptionV3 模型。 这里要注意的关键是 VGG 16 和 InceptionV3 均在具有 1,000 个类的 ImageNet 数据集上进行了训练。 但是在这种情况下我们将使用三个类来训练该模型以便我们可以仅使用 VGG 16 或 Inception 模型。 Keras 将针对不兼容的形状抛出错误[128,1000]与[128,3]相对其中128是批量大小。 要解决此问题请在模型定义中使用include_top False该模型将删除最后的全连接层并仅用三个类将它们替换为我们自己的层。 同样“第 6 章”“使用迁移学习的视觉搜索”对此进行了详细描述。 在训练 135 个步骤并验证 15 个步骤后VGG 16 模型的验证准确率约为0.89 Epoch 1/10135/135 [] - 146s 1s/step - loss: 1.8203 - accuracy: 0.4493 - val_loss: 0.6495 - val_accuracy: 0.7000Epoch 2/10135/135 [] - 151s 1s/step - loss: 1.2111 - accuracy: 0.6140 - val_loss: 0.5174 - val_accuracy: 0.8067Epoch 3/10135/135 [] - 151s 1s/step - loss: 0.9528 - accuracy: 0.6893 - val_loss: 0.4765 - val_accuracy: 0.8267Epoch 4/10135/135 [] - 152s 1s/step - loss: 0.8207 - accuracy: 0.7139 - val_loss: 0.4881 - val_accuracy: 0.8133Epoch 5/10135/135 [] - 152s 1s/step - loss: 0.8057 - accuracy: 0.7355 - val_loss: 0.4780 - val_accuracy: 0.8267Epoch 6/10135/135 [] - 152s 1s/step - loss: 0.7528 - accuracy: 0.7571 - val_loss: 0.3842 - val_accuracy: 0.8333Epoch 7/10135/135 [] - 152s 1s/step - loss: 0.6801 - accuracy: 0.7705 - val_loss: 0.3370 - val_accuracy: 0.8667Epoch 8/10135/135 [] - 151s 1s/step - loss: 0.6716 - accuracy: 0.7906 - val_loss: 0.4276 - val_accuracy: 0.8800Epoch 9/10135/135 [] - 152s 1s/step - loss: 0.5954 - accuracy: 0.7973 - val_loss: 0.4608 - val_accuracy: 0.8533Epoch 10/10135/135 [] - 152s 1s/step - loss: 0.4926 - accuracy: 0.8152 - val_loss: 0.3550 - val_accuracy: 0.8933下图显示了在椅子上使用 VGG 16 模型后神经网络的可视化效果 上图显示了 VGG 16 模型如何在前 16 层看到椅子。 请注意与我们的自定义模型相比VGG 16 模型效率更高因为每一层都在执行某种类型的图像激活。 不同层的图像特征不同但总体趋势是相同的–随着我们深入层图像将转换为更抽象的结构。 接下来我们使用 Inception V3 模型执行相同的练习。 在“第 6 章”“使用迁移学习的视觉搜索”中描述了此代码。 下图显示了 Inception V3 模型如何形象化椅子图像 Inception V3 模型的验证准确率约为 99%。 如您所见与 VGG16 相比Inception V3 模型中的层数更多。 先前的图像难以可视化。 下图显示了第一层最后一层和一些选择的中间层 前面的图像清楚地显示了当我们更深入地进入神经网络时椅子图像如何失去锐度并变得越来越模糊。 最终图像看起来不太像椅子。 神经网络可以看到许多相似的椅子图像并根据它们来解释椅子。 在本节中我们描述了如何在训练过程中查看中间激活层以了解如何在神经网络上变换特征映射。 但是如果您想了解神经网络如何将特征和隐藏层转换为输出请参阅 TensorFlow 神经网络游乐场。 总结 CNN 是事实上的图像分类模型这是因为 CNN 能够自己学习每个类别的独特特征而无需推导输入和输出之间的任何关系。 在本章中我们了解了 CNN 的组件这些组件负责学习图像特征然后将其分类为预定义的类。 我们了解了卷积层如何彼此堆叠以从简单的形状例如边缘学习以创建复杂的形状例如眼睛以及特征映射的维数如何因卷积和合并层而改变。 我们还了解了非线性激活函数Softmax 和全连接层的功能。 本章重点介绍如何优化不同的参数以减少过拟合的问题。 我们还构建了用于分类目的的神经网络并使用我们开发的模型来创建图像张量该图像张量被神经网络用于开发可视化的激活层。 可视化方法可帮助我们了解如何在神经网络中变换特征映射以及神经网络如何使用全连接层从此变换后的特征映射中分配类别。 我们还学习了如何将自定义神经网络可视化与高级网络例如 VGG16 和 Inception V3的可视化进行比较。 在下一章中您将学习一些最著名的神经网络模型以便对 CNN 参数选择有更深入的了解。
http://www.dnsts.com.cn/news/168478.html

相关文章:

  • 网站功能与内容设计的步骤网站开发各年的前景
  • 购物网站建设 成都新乡网站建设制作
  • 网站出现风险如何处理方法京东云wordpress
  • 沭阳县建设局网站用php做的网站论文
  • 织梦五彩婚纱源码网_婚庆策划网站php源码官方网站开发哪家便宜
  • 网站设计编程有哪些创建个人邮箱
  • 手机网站建设服务哪家好优帮云查询数据云查询
  • 嘉兴做微网站多少钱网络广告和传统广告的区别
  • 摄影后期教程网站上海公司黄页网站
  • 网站制作公司报价sae 网站备案
  • 广州做餐饮的招聘网站泉州seo网站推广
  • 网站空间网上怎么找承包小工程
  • 随州网站建设外包公司北京软件开发公司排行
  • 网站的二级目录怎么做动漫设计一般用什么软件
  • 做网站霸屏公司销售好做吗html背景图片代码
  • 网站建设 成都今网科技WordPress到底好不好用
  • 长沙网站搭建公司联系方式帮做暑假作业网站
  • 怎么在网站上做链接wordpress 获取文章评论
  • 山东住房建设部官方网站seo云优化公司
  • wordpress入站密码大连公共资源交易中心
  • 自己设计logo网站郑州平面设计公司排名
  • 成都网站优化推广方案wordpress自动文章排版
  • 优化大师官方免费下载长沙seo优化价格
  • 网站搭建响应式农业网站建设
  • 区块链网站建设方案珠海溢动网络科技有限公司
  • 折800网站源码wordpress插件安装目录
  • 东营市做网站的公司广州商城型网站建设
  • 上市公司做家具网站网站开发预留接口
  • 百度网站快速优化公司官网建设
  • 大连建设学院网站网站开发接单网站