使用张量流的图像分类器
如何创建图像分类器的分步指南
如果你不知道卷积神经网络是如何工作的,看看我下面的博客,它解释了 CNN 中的层和它的目的
关于卷积神经网络如何工作的直觉
medium.com](https://medium.com/dataseries/introduction-to-convolutional-neural-networks-5a227f61dd50)
我们将在猫狗数据集上工作,这意味着我们的网络将预测提供的图像是猫还是狗。您可以在下面找到数据集和代码的链接
训练 DL 模型的猫狗数据集
www.kaggle.com](https://www.kaggle.com/tongpython/cat-and-dog) [## ajaymuktha/深度学习
这个知识库包含了神经网络算法——ajaymuktha/deep learning
github.com](https://github.com/ajaymuktha/DeepLearning/blob/master/Convolutional%20Neural%20Networks/cnn.py)
为了便于计算,我从数据集中提取了大约 10,000 张图像,制作了一个验证文件夹,并放置了一些猫和狗的随机图像,以测试训练后的分类器。
数据集包含两个文件夹 Train 和 T **est。**训练文件夹包含两个文件夹,由用于训练的猫和狗的图像组成。测试文件夹也由两个文件夹组成,这两个文件夹由用于评估模型的猫和狗的图像组成。训练集由 8000 幅猫狗图像组成,测试集由 2000 幅猫狗图像组成
安装 Tensorflow
如果你的 PC 或笔记本电脑没有 GPU,你可以使用 Google Colab,或者使用 Jupyter Notebook。如果您使用您的系统,请升级 pip,然后安装 TensorFlow,如下所示
tensorflow.org
导入依赖项
在上面几行代码中,我只是导入了这个过程中需要的所有库
数据再处理
训练集的预处理
我们将在训练图像上应用一些变换以避免过度拟合,如果我们不执行,我们将在训练集和测试集的准确性之间得到很大的差异。
我们执行一些几何变换,如水平翻转图像,垂直翻转,放大,缩小和许多其他可以执行的操作,我们应用它,这样我们的模型就不会过度学习我们的训练图像。我们使用 ImageDataGenerator 类执行上述方法。
train_datagen 是 ImageDataGenerator 类的实例,它将对训练集中的图像应用所有变换,rescale 方法将对图像中的所有像素应用特征缩放,使其在 0 到 1 的范围内。现在我们需要将它连接到我们的训练数据集。
flow_from_directory 将把图像增强过程连接到我们的训练集。我们需要提到我们的训练集的路径。目标尺寸是应该输入神经网络的图像尺寸。批量大小被定义为一批中图像的数量,类模式将是二进制的,因为我们只有两个输出,要么是猫,要么是狗。
预处理测试集
我们不为测试集应用变换,因为我们只使用它们来评估,对我们的测试集做的唯一任务是重新缩放图像,因为在训练部分,我们定义了可以馈入网络的图像的目标大小。
现在我们定义从目录中导入测试图像的测试集。我们定义的批量大小、目标大小和班级模式与训练集中提到的相同。
构建 CNN
卷积神经网络是一系列连续的层,所以这里我们用一个连续的类来定义它
卷积层
我们使用添加一个方法来添加层,首先我们添加卷积层 Conv2D 类,我们需要在其中传递三个参数
filters →图像需要应用的特征检测器的数量,也称为内核。
内核大小 →需要根据行数和列数为您的特征检测器定义一个内核大小。
input_shape →每当我们在任何深度学习模型中添加第一层时,我们都需要指定 input_shape,因为我们在处理图像时需要提供我们上面在训练集中提到的目标大小,3 是指 RGB 通道。
激活 _ 功能 →我们需要指定触发机制的激活功能。
联营
这里,我们考虑最大池类,我们需要指定两个参数
pool_size →这是我们为卷积层中获得的特征检测器申请的帧的大小。
步幅→帧在所有四个方向上应该移动的量
现在,我们将第二个卷积层应用于我们的网络
变平
这里,我们将所有卷积和最大池层转换为一维,这将成为全连接层的输入。
全连接层
我们传递到稠密层的参数是作为单元的隐藏神经元的数量,我们使用的激活函数是 relu。
输出层
输出单元的数量将是 1,因为我们将只预测一个类,并且激活函数将是 sigmoid 激活函数。
训练 CNN
编译 CNN
我们考虑采用两个参数的编译方法,一个是编译器 adam,一个是损失函数 binary_crossentropy,我们选择度量作为精确度。
训练 CNN
我们将使用 fit 方法通过训练集进行训练,并使用测试集来评估模型。我们将运行 25 个时期。
预言;预测;预告
让我们通过拍摄一个随机图像来进行预测,为此,我们导入基本的库 NumPy …和 image 来执行图像操作。我们使用 load_img 函数来加载 PIL 格式的图像,我们提到了测试图像的路径,并且它应该与训练图像具有相同的大小。然后,我们使用 img_array 函数将图像转换为模型期望的数组进行预处理。
我们的 CNN 模型被训练成一批图像,而不是一个单独的图像,所以我们需要增加一个额外的维度。我们将增加一个额外的维度来访问单独的图像。我们使用 NumPy 中的 expand_dim 函数来实现。
我们对测试图像使用 predict 方法,还从批量大小中访问图像的标签,并使用 if-else 条件来检查图像是猫还是狗。
这就是现在,希望你喜欢这个关于猫和狗分类的教程,在我的下一个博客中,我将向你解释递归神经网络的重要性,并从头实现它的一个应用。
如果你想知道人工神经网络如何与应用程序一起工作,请查看我下面的博客:
你深度学习的第一步
towardsdatascience.com](/introduction-to-artificial-neural-networks-ac338f4154e5) [## 用 Tensorflow 构建人工神经网络
如何使用 TensorFlow 构建神经网络的分步教程
towardsdatascience.com](/building-an-ann-with-tensorflow-ec9652a7ddd4)
用 PyTorch 实现图像聚类
报纸上的蘑菇,作者图片
用于蘑菇照片聚类的深度卷积神经网络的逐行教程实现
使用深度卷积神经网络(DCNN)的监督图像分类现在是一个既定的过程。通过预训练的模板模型加上微调优化,许多有意义的应用都可以获得非常高的精确度,例如最近对医学图像的研究,该研究使用模板 Inception v3 模型,对日常物体的图像进行预训练,在前列腺癌诊断上达到 99.7%的精确度。
对于无监督的图像机器学习来说,目前的技术水平远没有解决。
聚类是无监督机器学习的一种形式,其中项目的集合——在这种情况下是图像——根据数据集合本身中的某种结构进行分组。最终出现在同一聚类中的图像应该比不同聚类中的图像更相似。
图像数据可能很复杂——变化的背景、视野中的多个对象——所以一对图像比另一对图像更相似意味着什么并不明显。没有一个基础事实标签,通常不清楚是什么让一种聚类方法比另一种更好。
一方面,无监督的问题因此比有监督的问题更模糊。优化没有既定的正确答案。另一方面,最有趣的东西是从模糊的问题、假设的产生、问题的发现、修补中产生的。为数据和分析工作流的这些领域提供新功能的工具值得我们花费时间和精力。
我将描述一种最近的图像聚类方法的实现(庄等 自 2019 年起 局部聚集)。这是近年来发表的许多可能的 DCNN 聚类技术之一。
我使用 PyTorch 库来展示这个方法是如何实现的,并在整篇文章中提供了几个详细的代码片段。完整的代码可在回购中获得。
尽管图像聚类方法不像它们的监督兄弟一样在标准库中容易获得,PyTorch 仍然能够顺利实现这个非常复杂的方法。因此,我能够探索、测试和轻轻戳一下 DCNNs 在应用于集群任务时能做什么这个谜一样的问题。
我的目标是展示如何从几个概念和方程出发,使用 PyTorch 得出可以在计算机上运行的非常具体的东西,并指导进一步的创新和对任何任务的修补。
我将把这个应用到真菌的图像上。为什么是真菌?你以后会明白的。
但是首先…实现一个 VGG 自动编码器
在讨论聚类方法之前,我将实现一个自动编码器(AE)。AEs 有各种各样的应用,包括降维,而且本身也很有趣。它们在图像聚类中的作用将在后面变得清楚。
用 PyTorch 库实现基本 AEs 并不困难(参见的和的中的两个例子)。我将实现特定的 AE 架构,这是 SegNet 方法的一部分,它建立在 VGG 模板卷积网络之上。VGG 定义了一种架构,最初是为监督影像分类而开发的。
AE 的架构如下图所示。
作者图片
图像自动编码的步骤是:
- 输入图像(左上)通过以下方式处理
- 一个编码器,由带归一化和 ReLU 激活的卷积层(绿色)和最大池层(紫色)组成,直到
- 获得一个较低维度的代码,然后由
- 一个解码器,由带归一化和 ReLU 激活的转置卷积层(浅绿色)和非卷积层(浅紫色)加上一个不带归一化或激活的最终卷积层(黄色)组成,直到
- 获得与输入尺寸相同的输出图像。
是时候将这种设计写入代码了。
我首先创建一个编码器模块。第一行,包括初始化方法,如下所示:
编码器的架构与 VGG-16 卷积网络的特征提取层相同。因此,该部分在 PyTorch 库,torchvision.models.vgg16_bn
中很容易获得,参见代码片段中的第 19 行。
与 VGG 的规范应用不同,代码是而不是进入分类层的。最后两层vgg.classifier
和vgg.avgpool
因此被丢弃。
编码器的层需要一次调整。在解码器的非池化层中,来自编码器的最大池化层的池化索引必须可用,这在前面的图像中用虚线箭头表示。VGG-16 的模板版本不生成这些指数。然而,可以重新初始化池层来实现这一点。这就是EncoderVGG
模块的_encodify
方法所要完成的。
由于这是一个 PyTorch 模块(从nn.Module
继承而来),所以需要一个forward
方法通过EncoderVGG
的实例来实现小批量图像数据的向前传递:
该方法按顺序执行编码器中的每一层,并在创建池索引时收集它们。在执行编码器模块之后,代码连同一个有序的池索引集合一起被返回。
接下来是解码器。
这是 VGG-16 网络的“转置”版本。我使用惊吓引号,因为解码器层看起来很像反向的编码器,但严格来说,它不是一个逆或转置。
解码器模块的初始化有点复杂:
_invert_
方法在编码器的层上反向迭代。
编码器中的卷积(图像中的绿色)被解码器中相应的转置卷积(图像中的浅绿色)替换。nn.ConvTranspose2d
是 PyTorch 中的库模块,它对数据进行上采样,而不是像更广为人知的卷积运算那样进行下采样。更多解释见此处。
编码器中的 max-pooling(紫色)被相应的 unpooling(浅紫色)替换,或者nn.MaxUnpool2d
表示 PyTorch 库模块。
解码器forward
是:
代码是输入,还有编码器创建的池索引列表。每当执行非池化层时,池化索引一次取一个,相反。这样,关于编码器如何执行最大池化的信息被传送到解码器。
因此,在镜像编码器层的转置层之后,forward
的输出是与输入到编码器的图像的张量形状相同的张量。
完整的自动编码器模块实现为编码器和解码器实例的基本组合:
产生与相应输入非常相似的输出的 AE 的一组参数是一组好的参数。我使用 AE 的输入和输出之间每个像素的每个通道的均方误差来量化这一点,作为目标函数,或 PyTorch 库中的nn.MSELoss
。
使用定义的 AE 模型加上可微分的目标函数,PyTorch 的强大工具被部署用于反向传播,以获得梯度,随后是网络参数优化。培训是如何实施的我就不赘述了(好奇的读者可以看看回购中的ae_learner.py
)。
编码器按特征压缩图像,并且是聚类的起点
在训练 AE 之后,它包含可以在较低维度中近似表示图像数据集的重现的较高级特征的编码器。对于真菌的图像数据集,这些特征可以是在几个蘑菇图像之间共享的形状、边界和颜色。换句话说,编码器体现了蘑菇形加上典型背景的紧凑表示。
因此,就这些高级特征而言非常相似的两幅图像应该对应于比任何一对随机码都更接近的码,例如通过欧几里德距离或余弦相似性来测量。
另一方面,图像向低维的压缩是高度非线性的。因此,大于某个相当小的阈值的两个代码之间的距离被认为对相应的图像没有什么影响。这对于创建定义明确、清晰的集群来说并不理想。
作为 AE 一部分的编码器是一个起点。编码器接下来将被改进,通过利用学习到的蘑菇状和来创建代码,从而将图像压缩成代码,这些代码也形成固有的良好集群。
关于局部聚集损失的几个词和方程
局部聚集 (LA)方法定义了一个目标函数来量化一组代码的聚集程度。目标函数不像有监督的机器学习方法那样直接引用关于图像内容的基本事实标签。更确切地说,目标函数量化了编码图像数据本质上如何服从明确定义的聚类。
以这种方式获得的明确定义的聚类应该创建有意义的聚类,这不是不言而喻的,也就是说,看起来相似的图像通常是同一聚类的一部分。这就是为什么需要实现和测试。
首先,从 LA 出版物中获得一些关于实现什么的定义。
洛杉矶的集群目标是:
该方程中的 xᵢ 为图像张量, θ 表示编码器的参数。右手边的 vᵢ 是对应 xᵢ 的代码。两组 Cᵢ 和 Bᵢ 由集合中其他图像的编码组成,分别命名为近邻和背景近邻到 vᵢ 。
对于一组代码 A ,概率 P 被定义为:
换句话说,指数势定义了概率,其中一个代码 vⱼ 贡献的概率密度越大,与 vᵢ 的点积越大。因此,由与 vᵢ 相似(在点积意义上)的大部分其他代码组成的集合 A 定义了 vᵢ 可能是其成员的集群。
标量τ被称为温度,并且定义了点积相似性的标度。
对于给定的真菌图像集合, {xᵢ} ,目标是找到使集合的聚类目标最小化的参数 θ 。洛杉矶论文的作者提出了为什么这个目标有意义的论点。我不会在这里重复这个论点。简而言之,与该集群的互补码相比,分配给一个集群的代码越清晰,该集群目标的值就越低。
如何将 LA 目标实现为自定义损失函数?
在上面关于 AE 的部分中,描述了自定义编码器模块。缺少的是 LA 的目标函数,因为它不是 PyTorch 中库损失函数的一部分。
需要实现自定义损失函数模块。
损失函数模块的初始化将初始化多个 scikit-learn 库函数,这些库函数需要在forward
方法中定义背景和近邻集合。
NearestNeighbors
实例提供了计算数据点最近邻的有效方法。这将用于定义集合 B 。KMeans
实例提供了计算数据点集群的有效方法。这些将用于定义集合 C 。一旦处理了模块的执行,这将变得更加清楚。
说到这里:LocalAggregationLoss
的必用forward
法。
正向方法接受当前版本的编码器产生的小批量代码,加上所述代码在完整数据集中的索引。由于在创建小批量时通常会打乱数据,因此索引可以是一个不连续的整数列表,尽管其数量与小批量代码的大小相同(由assert
语句检查)。
forward
有两个主要部分。首先,评估相邻集 B、C 及其交集。第二,为给定的一批代码和集合计算概率密度,然后将概率密度聚集成如上定义的 LA 群集目标函数的对数概率的比率。
《前进》中的“记忆库”是什么?
LA 的创造者们采用了一种记忆库的技巧,他们将其归因于吴等人的另一篇论文。这是处理 LA 目标函数的梯度依赖于数据集的所有代码的梯度的一种方式。
所述函数的适当梯度将必须计算如下各项:
右手边所有代码的总和意味着必须计算大量的张量,并且为了反向传播而一直保存这些张量。迭代小批量图像对效率没有帮助,因为无论如何都必须计算代码相对于解码器参数的复杂梯度。
因为聚类的质量将一个图像与数据集的所有其他图像联系起来,而不是一个固定的基本事实标签,所以这种纠结是可以理解的。
记忆库技巧相当于将当前小批量中的代码之外的其他代码视为常量。因此,与其他代码的衍生物的纠缠消失了。只要近似的梯度足够好以引导优化朝向最小值,这就是有用的近似。
memory bank 类实现为:
它由与要聚类的数据集相同维数和相同数量的单元数据向量组成(由 Marsaglia 的方法在超球面上统一初始化)。因此,涉及具有生成 512 维代码的编码器的一千个图像的任务,意味着在 512 维的实坐标向量空间中的一千个单位向量的存储体。一旦一组新的向量连同相应的索引被提供给存储体,存储器就以某种混合速率memory_mixing_rate
被更新。该类还包含一个方便的方法,用于将整数索引集合转换为整个数据集的布尔掩码。
请注意,记忆库只处理数字。记忆库无法连接到 PyTorch 张量的反向传播机器。存储体被更新,但是通过运行平均值,而不是直接作为反向传播的一部分。
它是存储在LocalAggregationLoss
的memory_bank
属性中的MemoryBank
的一个实例。
背景邻居和近邻集合是如何创建的?
又回到了LocalAggregationLoss
的forward
法。我使用先前初始化的 scikit-learn 类实现了邻居集的创建。
_nearest_neighbours
和_intersecter
相当简单。前者依赖于寻找最近邻居的方法。它会考虑存储体中的所有数据点。
_close_grouper
对存储体中的数据点进行多次聚类。作为感兴趣点 vᵢ的相同聚类的一部分的那些数据点定义了近邻集合 Cᵢ.洛杉矶论文的作者鼓励使用多重聚类运行,其中聚类包含随机成分,因此通过执行多重运行,他们消除了噪声。
举例来说,下图中的红点是其他代码海洋中感兴趣的代码。记忆库当前状态的聚类将兴趣点放在其他点的聚类中(中间图像中的绿色)。最近邻定义了另一组相关数据点(右图中的紫色部分)。_nearest_neighbours
和_close_grouper
为小批量中的每个代码创建这两个集合,并将集合表示为布尔掩码。
作者图片
计算概率密度,使得 PyTorch 反向传播机器可以计算梯度
对于批中每个代码 vᵢ的两个集合(Bᵢ和 Bᵢ与 Cᵢ相交),是时候计算概率密度了。这个密度应该也可以用 PyTorch 方法来区分。
它的实现方式如下:
在第 14–16 行中,所有不同的点积都是在小批量的代码和存储体子集之间计算的。np.compress
将掩码应用于存储体向量。
torch.matmul
计算所有的点积,将小批量维度考虑在内。还要注意张量codes
包含了编码器数学运算的记录。因此,随着额外 PyTorch 操作的执行,该记录被扩展,最终,这使得 PyTorch 的反向传播机制、autograd
能够相对于编码器的所有参数来评估损耗标准的梯度。
从概念上讲,第 25–27 行也发生了同样的操作,但是在这个子句中,mini-batch 维被显式迭代。当 numpy 数组不能被广播时,这是需要的,这是粗糙数组的情况(至少目前是这样)。
将模型和损失放在一起
综上所述,类似于下面的代码可以让特定数据集、VGG 编码器和 LA 得到训练。
我在讨论中省略了如何准备数据(我放在fungidata
文件中的操作)。详情可在回购中找到。对于本讨论,将dataloader
视为返回真菌inputs['image']
的小批量图像以及它们在更大数据集inputs['idx']
内的相应索引就足够了。用来自作为自动编码器一部分的预训练编码器的标准化代码初始化存储体代码。
训练循环是功能性的,虽然被简化了,细节见la_learner
文件,虽然没有什么不寻常的被使用。
我使用稍微修改过的编码器版本,EncoderVGGMerged
。它是EncoderVGG
的子类。
这个类在编码器的结尾附加了一个应用于代码的合并层,所以它是一个一维向量。
我展示了应用于一个 RGB 64x64 图像作为输入的聚类的编码器模型。
作者图片
接下来,我展示了创建output
和loss
变量的模型的一个小批量图像的向前传递。
作者图片
图中的 LALoss 模块与存储体交互,考虑了小批量图像在大小为 N 的总数据集中的索引。它构建存储体的当前状态的聚类和最近邻,并将小批量代码与这些子集相关联。
backward
通道执行反向传播,从 LA 标准的损耗输出开始,然后遵循涉及代码的数学运算,通过链式法则,获得 LA 目标函数相对于编码器参数的近似梯度。
关于真菌图像的一句话
我将把这种方法应用于真菌的图像。我的理由:
- 我使用的软件库不是为这个特定任务开发或预先训练的。我希望测试使用通用库工具处理特定图像任务的场景。
- 真菌的外观在形状、颜色、大小、光泽、结构细节以及它们的典型背景(秋叶、绿色苔藓、土壤、采摘者的手)方面各不相同。信号和噪声都是变化的。
- 真菌图像位于明显物体和图像之间的最佳位置,人类凭直觉识别这些明显物体的原因我们很少能清楚地表达出来(例如狗、猫和汽车),而图像的信息内容需要深厚的领域专业知识才能掌握(例如肿瘤活检、锂电极形态学)。我相信这有助于理解方法。
- 丹麦真菌学会(2016 )提供了非常好的带注释的众包开放数据。(丹麦真菌记录数据库,由 Frø slev,t .,Heilmann-Clausen,J .,Lange,c .,ssø,t .,Petersen,J.H .,Sø chting,u .,Jeppesen,T.S .,Vesterholt,J。,在线www . svampeaatlas . dk)。
作为一个额外的奖励,真菌的生物学和文化是显著的——一个有趣的文化组成部分是决策启发法如何在蘑菇觅食者中进化,以便在可食用和致命之间导航。我可以想象一些非常有趣的机器学习的测试案例,这些测试案例基于从真菌照片中创建的图像数据。
数据库中的三幅图像如下所示。
从左到右:桌上的姬松茸(王子);叶间三条鸡油菌(金鸡油菌);草中鹅膏睫毛膏(飞木耳)。图片来自丹麦真菌记录数据库(见上文)。
说明性测试运行和探索
LA 的一个缺点是它涉及几个超参数。遗憾的是,我没有足够的 GPU 待命,所以我必须将自己限制在超参数和真菌图像选择的许多可能变化中的极少数。
我在这篇文章中的重点是概念和方程的实现(加上一个真菌图像数据的插件)。因此,我在这里追求例证和灵感,我将把进一步的结论留给高层次的观察。
我在鸡油菌和木耳蘑菇上训练 AE,裁剪为 224x224。利用随机梯度下降优化器,AE 最终收敛,尽管对于某些优化参数,训练陷入次优。经过训练的 AE 的输入和输出的一个例子如下所示。
作者图片
保真度有明显的损失,尤其是在周围的草地中,尽管在解码输出中清晰的红色帽子被粗略地恢复。
以 AE 的编码器为起点,针对 LA 物镜进一步优化编码器。使用相同的一组蘑菇形图像,温度为 0.07,混合率为 0.5(如在原始论文中),并且聚类的数量设置为要聚类的图像数量的大约十分之一。因为我的图像数据集相当小,所以我设置背景邻居来包括数据集中的所有图像。具有 LA 目标的编码器的训练最终收敛。
下面显示了一组说明性的图像:
来自丹麦真菌记录数据库的图片。
这是直观的,明确的白点帽飞木耳集群。但是,该群集也包含外观差异很大的图像。和检查其他集群,白点飞木耳帽偶尔出现在其他集群。
下面显示了另一个说明性的集群。
图片来自丹麦真菌记录数据库。
这些图像有一些共同之处,将它们与典型的图像区分开来:较暗的颜色,主要来自背景中的棕色树叶,尽管右下角较暗的蘑菇(黑色鸡油菌或黑色小号)很突出。
但同样,符合这一粗略标准的图像也出现在其他聚类中,这表明还有其他非线性关系编码,这使得上述图像对应于相对接近和不同的代码,而其他图像则没有。可解释性比平常更难。
我还注意到许多集群只包含一个图像。改变进入 k-means 聚类的聚类质心的数量会对此产生影响,但随后也会出现非常大的图像聚类,对于这些图像聚类,很难提供对共有特征的直观解释。
这些是其他运行生成的说明性结果。至少在我这里进行的几次有限的运行中,LA 的最小化创建了最多适度对应的图像簇,至少在我看来是自然的分组。
鉴于深度神经网络的灵活性,我希望有很多方法可以将图像压缩到清晰的聚类中,就我的眼睛而言,不能保证这些方法体现了有用的意义。与基础事实标签的情况不同,在基础事实标签的情况下,神经网络的灵活性在优化之前被引导向我们定义为有用的目标,优化器在这里可以自由地找到要利用的特征,以使聚类质量高。
也许需要一个不同的归纳偏差来更好地限制灵活性的部署,以便最小化 LA 目标函数?就我的视觉认知而言,也许 LA 目标函数应该与一个附加目标相结合,以防止它偏离一些可感知的范围?也许我应该使用标准化的图像,如某些医学图像、护照照片或固定透视相机,将图像中的变化限制在较少的高级特征上,这样编码就可以在聚类中利用这些特征?或者,我所担心的问题的真正答案可能是在这个问题上投入更多的 GPU,并找出超参数的完美组合?
当然都是猜测。不过,多亏了 PyTorch,从概念和方程到原型和创作的道路上的障碍比固定的模板解决方案要低。
脚注
- 常规的警告:我对 LA 的实现旨在与原始出版物一样,但是误解或错误的可能性永远不可能完全为零。
- 我没有花费任何精力来优化实现。我可能忽略了 PyTorch 和/或 NumPy 技巧,它们可以提高 CPU 或 GPU 的速度。
使用卷积自动编码器的图像彩色化
来源: unsplash
使用 Python 中的深度学习对来自老派视频游戏的图像进行着色的案例研究
最近,我完成了 Udacity 的机器学习工程师 Nanodegree 的顶点项目。因为我知道这个项目需要花费大量的时间和精力,所以我想做一些我真正感兴趣的事情。很长一段时间以来,我一直打算熟悉计算机视觉的一个领域,即图像彩色化。我是(从我记事起就是)一个电子游戏的狂热爱好者,这就是为什么在这个项目中,我想做一些贴近我内心的东西。
最近,我在互联网上看到一个的帖子,显示通过使用深度学习可以提高仿真视频游戏的质量。所谓仿真,我指的是在一个不同于游戏最初设计的系统上使用专用软件运行游戏。一个例子可能是在 PC 上玩任天堂 64 游戏。通过在仿真器软件中嵌入预先训练的神经网络,可以将分辨率升级到 4K 或者增加纹理的质量/清晰度。真正令人惊讶的是,这些解决方案适用于所有游戏,而不仅仅是他们直接接受训练的一两个游戏。
当然,对于顶点来说,做这么大规模的项目太过雄心勃勃,所以我不得不把它缩小一点。当我开始我的视频游戏冒险时,我玩的是 Game Boy Color,除了新的彩色游戏外,它也适用于上一代产品——灰度游戏男孩。从那个时代获得灵感,我试图使用深度学习来给灰度图像着色,因此模拟器(结合在许多类似游戏上训练的网络)可能会接近实时地给输出着色。
来源: unsplash
Nanodegree 专注于在使用 AWS 基础设施(SageMaker)的同时使用 PyTorch 构建和部署模型,但是本文中描述的所有模型也可以在本地或使用 Google Colab 进行训练。
在这篇文章中,我描述了我解决着色问题的方法,以及为了完成这个项目我必须采取的步骤。由于代码库相当长,我不会在文章中包含代码,而是让您参考包含复制项目所需的所有文件的 GitHub 库。
1.方法学
在展示实际的实现之前,我想对我在项目中遵循的方法提供一个高层次的概述。这就是为什么我认为首先熟悉以下概念是有意义的。
Lab 色彩空间
在我的上一篇文章中,我提供了用 Python 处理图像和不同颜色空间的快速介绍。我强烈建议在继续之前快速阅读,因为这将使理解一切变得更容易。为了以防万一,我也将在这里快速回顾一下。
到目前为止,最流行的图像表现方式是 RGB 。但是也有不同的方法可用,其中之一是 Lab 颜色空间(也称为 CIELAB)。
简而言之, Lab 颜色空间将颜色表示为三个值:
- L :从 0(黑色)到 100(白色)范围内的亮度,这实际上是一幅灰度图像——它不完全等同于将 RGB 转换为灰度,但已经足够接近了
- a :绿-红色谱,数值范围为-128(绿色)~ 127(红色)
- b :蓝黄色光谱,数值范围为-128(蓝色)~ 127(黄色)
从上面的描述中我们可以得出的直接结论是,通过使用 Lab 颜色空间,我们可以同时解决两个问题——我们将灰度图像作为输入,颜色通道的复杂性从三个减少到两个(与 RGB 相比)。
自动编码器
自动编码器是一种神经网络架构,类似于主成分分析等技术,它们都试图降低输入数据的维度。然而,正如我们将看到的,自动编码器可以做得更多。它们由两部分组成:
- 编码器-将输入数据转换为低维表示(也称为潜在向量/表示)。为了实现这个目标,编码器必须只学习数据中最重要的特征。
- 解码器—从低维表示中恢复输入。
下图显示了自动编码器网络的基本架构。
自动编码器的基本模式。来源:维基百科
在这个项目中,我训练自动编码器最小化损失函数,这是输入数据和解码输出之间的差异的度量。通常,潜在表示可以用作提取的特征,类似于来自 PCA 的主成分。然而,在我们的例子中,我们感兴趣的是解码输出。
训练自动编码器时要注意的一件重要事情是,当潜在表示大于输入数据时,它们有记住输入的倾向。
卷积神经网络
卷积层的目标是通过应用卷积滤波来提取潜在的特征。卷积层读取输入(例如 2D 图像)并将(特定形状的)内核拖到图像上。内核表示我们想要在图像中定位的特征。对于每一步,输入乘以核的值,然后对结果应用非线性激活函数。通过这种方式,原始输入图像被转换为过滤图。
来源: GitHub
卷积和池(聚合)层可以相互堆叠,以提供多层抽象。许多流行的图像分类架构都是以类似的方式构建的,如 AlexNet、VGG-16 或 ResNet。
另一方面,我强烈推荐下面的资源,用于交互式可视化卷积如何根据各种参数工作,如步幅、填充内核大小和膨胀。此外,安德烈·卡帕西的这段视频对 CNN 做了很好的介绍。
对于 capstone 项目,我将 CNN 与自动编码器结合起来,并有效地使用了一类称为卷积自动编码器的架构。这种网络的输入是灰度图像(1 个通道),而输出是表示颜色的 2 层( a / b 层的 Lab 表示)。
2.构建数据集
对于着色项目,我使用了我从小最喜欢的游戏之一— Wario Land 3 。为了获得数据集,我从 YouTube上截取了一段视频。我找到了一个 longplay (整个游戏的完整播放,只显示实际的游戏屏幕),所以下载后,我可以很容易地从视频中提取每 x- 帧,以获得完整的彩色图像数据集。我在之前的文章中详细记录了这个过程。
来源:维基百科
视频每秒播放 24 帧,我每 58 帧提取一次。这样做总共产生了 7640 幅图像。提取的帧存储为 JPG 图像,每个图像的大小为 288x320 像素。
在对图像进行更多的技术分析之前,值得一提的是,目前收集数据的方法存在哪些潜在问题。通过从显示整个游戏的视频中提取每第 x 帧,我们还可以得到:
- 所有游戏内菜单
- 介绍/标题屏幕
- 信用
- 画面转换——在游戏中切换画面/阶段时,下一个画面/阶段加载时通常会有一个短暂的淡出画面
总之,这会给数据集带来一些噪声。这个问题的一个潜在解决方案是剪掉视频的第一个/最后一个 X 秒,以删除介绍/演职员表。为了简单起见,我没有这样做,而是将所有帧留在数据集中。
是时候更详细地描述数据集了。首先,我呈现一个提取图像的预览:
捕获的图像为 288x320
Game Boy Color 的屏幕分辨率为 144x160(因此拍摄的视频已经放大了 2 倍)。转到调色板,Game Boy Color 的系统使用 15 位 RGB 调色板(多达 32,768 种可能的颜色)。实际上,不使用任何特殊的编程技术就可以呈现多达 56 种颜色,而完整的 32,768 种颜色需要一些技巧。
当前的标准是 24 位 RGB 颜色空间,其中每个颜色通道都表示为 0 到 255 之间的数字。这种表示总共产生大约 1670 万种颜色组合。
GBC 的颜色有点“有限”是我选择它作为目标平台的原因之一,因为这种图像比新一代游戏机或真实照片的图像更容易着色。
3.数据准备
在这一部分中,我主要关注应用于数据的转换。再次重申,下载的数据被编码为 RGB 图像。因此,每个图像都被表示为一个维数为[3,288,320]的数组,其中 0-255 范围内的数字描述了给定通道的强度。正如我之前提到的,使用实验室颜色空间的想法是为了降低问题的复杂性,所以自动编码器的实际输出是一个大小为[2,288,320]的数组。
在下图中,我展示了我之前展示的图像的实验室表示:
在讨论了 Lab 色彩空间之后,我描述了准备数据的两个步骤。
培训/验证分割
对于这个项目,我做了 90-10 的训练-验证分割。验证数据不用于训练,仅用于评估每个时期后的网络性能。
预处理步骤
所有的预处理步骤都在一个定制的 PyTorch ImageFolder
中完成,以使过程尽可能简单高效。我采取的步骤是:
- 将图像裁剪为 224 x224——在我尝试的一个架构中,ResNet-18 的前几层被用作编码器。为了将更改保持在最低限度,我将所有图像裁剪为 224x224(因为这是该架构中使用的图像大小)。然而,网络的输入必须改变以接受单通道图像。为了训练,我随机截取了一些图像。对于验证,中间裁剪,保证验证样本始终相同。
- 此外,训练图像有 50%的概率被水平翻转。
- 我基于 Lab 色彩空间将 RGB 输入图像转换为两幅图像——大小为 224x224 的灰度级( L 层)输入和作为输出的 a/b 层(形状:[2,224,224])。
- 在将图像编码为 Lab 之后,我将图层标准化,类似于在[1]和[2]中所做的。我将 L 通道除以 100,因此值在[0,1]的范围内。然后,我将 a/b 通道中的值除以 128,结果在[-1,1]范围内,适合 tanh 激活函数(网络最后一次激活)。我还试验了一种不同的变换——通过先加 128 然后除以 255,将 a/b 层归一化到范围[0,1]。在这种情况下, ReLU 或 Sigmoid 激活功能适用于最后一层。然而,从经验上看,第一种方法效果更好。
上述步骤中的所有数据分割和预处理都是使用预先指定的种子完成的,以确保项目的可重复性。
4.模型和培训
在这个项目中,我训练了三个不同的模型(名为 V0,V1,V2,尽管它们不是前面模型的明确扩展),尽管我也试验了许多不同的模型。下面我提供了模型的简短描述。
v 0 型—基准
该模型的架构基于[1]中提出的架构。作为一个例子,作者用它来说明一个关于给一个图像着色的观点。我决定使用这个模型作为我的基准,因为它是我在互联网上找到的最简单的彩色自动编码器。我相信这将是一个很好的基准,类似于评估高级分类器与基本分类器(如逻辑回归或决策树)的性能。
下图总结了该模型的架构:
模型 V0 的架构
在网络中,我没有使用池层来减少输入的维数。相反,我在一些卷积层中使用了步长 2。原因是池层增加了信息密度,但同时扭曲了图像。这在图像分类任务中可能无关紧要,在这些任务中,我们只关心图像中某些特征的存在,然而,对于着色网络来说,这是有区别的。此外,我使用填充来控制图像尺寸的减小。
上采样是使用不可学习的插值完成的。在这种情况下,这是一个 2 倍的上采样(实际上是图像大小的两倍),并使用了最近邻插值算法。
模特 V1
该模型基于[1]中介绍的“beta”架构。在满足于这种架构之前,我试图一字不差地重建“beta”版本,然而,该模型根本没有学习。我怀疑潜在的表现形式太大了,模型没有学习到任何有用的特征。这就是为什么我把它的通道数缩小了 2 倍。下图展示了该架构的细节:
我没有描述该网络的更多细节,因为它类似于 V0 模型。
模特 V2
最后一个模型是对[3]中提出的模型的一个微小修改。作者将 ResNet-18 的前几层组合起来作为编码器,它从灰度图像中提取特征(网络的输入也必须被修改以接受 1 通道图像)。为了简洁起见,我没有包括详细的规格,因为图像会很大。
然后,作者使用了一个类似于我们在[1]和[2]中已经看到的解码器。摘要如下。与以前的模型相比,该解码器的不同之处在于卷积后增加了批量归一化层。
训练详情
我通过寻找和实现一些着色的自动编码器开始了这个项目,然而,我后来不得不创建一个我将坚持的框架。原因是我有效地结合了一些不同的方法,每种方法都使用了稍微不同的方式来预处理图像,应用变换等。
为了使结果具有可比性,我满足于框架的一个变体,并以类似的方式训练所有的模型。
我在途中做出的一些决定包括:
- 统一的训练方法—相同损失(MSE)、优化器(RMSprop)、学习率(0.001)、最大历元数(30)等。
- 在实验室转换的基础上增加一个额外的标准化步骤,这就是为什么我不得不将网络中的一些最终激活函数修改为 tanh
- 使用一组变换(随机裁剪、水平翻转、居中裁剪)来扩充数据集。我的项目所基于的一些例子不包括任何转换。
我试图使代码尽可能灵活,以便于实验。这就是为什么为了方便起见, Lab 图像的归一化被参数化。
评估指标
很难选择一个好的评价标准,因为颜色在很大程度上是主观的,不同的版本可以被认为是可接受的。这就是为什么经常需要人工观察的原因。在文献中([1],[3]),用于训练彩色化神经网络的流行解决方案是使用均方误差(MSE)作为损失函数。在这个项目中,我遵循了同样的方法。
MSE 损失函数带来了一些问题,这是由彩色化问题是多峰的事实引起的——单个灰度图像可能对应于许多可接受的彩色图像。这导致当模型更喜欢选择不饱和的颜色时,因为它们比明亮、鲜艳的颜色更不容易出错(这会导致高 MSE 的惩罚)。
这就是为什么研究不同的评价函数绝对是一个值得探索的领域。一些论文[4]还探索了将图像彩色化作为分类问题(而不是建议的回归)来构建的想法,并使用诸如准确度之类的度量作为损失函数。
在本文中,我给出了不同时期(15、30 和最好的一个,以防不是最后一个)所选网络架构的 MSE。此外,我还展示了彩色图像以供视觉检查。
5.结果
为了评估彩色化自动编码器的性能,我首先分别针对 3 个模型中的每一个,检查训练/验证损失在各个时期的演变。
v 0 型
在图像中,我们可以看到损失开始趋于平稳,但是,如果训练更多的时期,损失可能仍然会减少。此外,在验证损失中有两个奇怪的峰值,这是[1]的作者在使用 ADAM 优化器时也注意到的。对他来说,使用 RMSprop 优化器解决了这个问题。
型号 V1
这些模型比 V0 模型开始时损失更高,可能是由于可学习参数的数量更多。不过最终还是在 30 个纪元内取得了较好的表现。此外,我们可以观察到随着训练时间的推移,验证损失有一个较小的峰值。
模特 V2
对于最复杂的模型(就可学习参数的数量而言),上图中唯一突出的是验证损失的巨大峰值。我没有太注意它,因为它只发生了一次,其余的训练是稳定的。虽然,知道它的确切原因会很有趣。
作为下一步,我比较所有模型在第 15、30 个时期和最佳时期(如果不是最后一个时期)的验证集 MSE。
总的来说,在考虑的模型中,V1 模型的验证损失最低。此外,V1 和 V2 模型都优于基准,这是有道理的,因为它的架构简单。
最后,我展示了视觉检查的结果。这些图像来自验证集(在训练期间没有看到),并且是从各个模型的最佳时期获得的。
V2 模型设法捕捉到了宝箱周围方块的颜色,然而,却错误地给宝箱本身着色。
V1 模型在地图着色方面做得最好,V2 的图像有点“恍惚”,图像中有各种亮点。
V1 模型在捕捉背景方面做得很好,而 V2 模型正在努力决定使用哪种颜色。
所有的模型都设法捕捉到了紫色的碎片。
最后一个比较棘手,因为地图的碎片实际上接近灰度。模特 V2 试图给地图上色,而 V1 基本上保持了原样,只正确地给框架上色。
V1 和 V2 非常接近捕捉森林的绿色,而记住破碎的块是紫色的。模型还正确地将树干染成了棕色。
模特们试图给上面的图像着色,但结果并不那么完美。一个潜在的原因是,这是一种独一无二的图像,所以很难使用任何潜在的特征来获得正确的颜色。
总而言之,这些模型在给灰度图像着色方面做得相当不错。神经网络似乎已经获得了一些图案,如紫色的破块、宝箱周围的紫色瓷砖、黄色的硬币、绿色的森林等。此外,更先进的模型(V1/V2)明显优于基准。然而,V2 模型是相当不稳定的,并且经常导致明亮和不匹配的颜色。
在 GitHub repo 中,我也尝试将 Wario Land 3 上训练的模型应用于来自 Wario Land 2 的图像,然而性能相当差。原因可能是游戏的风格有点不同,而且开发者没有重用以前游戏中的很多精灵/模型——这对玩家来说当然很好:)你可以在下面看到一些例子。
6。结论
总之,我真的很喜欢在这个项目中工作,我学到了很多东西。这个项目决不是完整和详尽的。图像着色绝对不是一件容易的事情,我没有从所有的角度去探索,主要是因为时间的限制。因此,我列出了一些进一步扩展的想法:
- 应用数据清理,例如,过滤掉具有高百分比纯白色/黑色像素的图像。这可能表明这些是一些屏幕转换,将它们包含在数据集中可能会给模型带来不必要的噪声。
- 该项目可以扩展到捕获一个以上的视频游戏,可能来自同一流派(例如,像 Wario Land 这样的平台游戏),以提高性能和覆盖潜在的过度拟合。
- 使用可训练的放大层(转置卷积层)而不是不可训练的层。
- 从预先训练好的网络中进行迁移学习。
- 用甘斯做实验。
我真的希望将来回到这个项目,至少尝试一下我上面提到的一些想法。
你可以在我的 GitHub 上找到本文使用的代码。一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。
参考
[1]https://blog . Floyd hub . com/colorizing-b-w-photos-with-neural-networks/
[2]f .巴尔达萨雷、D. G .莫林和 l .罗德斯-吉拉奥(2017 年)。深度考拉化:使用 CNN 和 inception-resnet-v2 的图像彩色化。arXiv 预印本 arXiv:1712.03400。
https://lukemelas.github.io/image-colorization.html
https://ezyang.github.io/convolution-visualizer/index.html
https://github.com/vdumoulin/conv_arithmetic
基于 K-均值聚类的图像压缩
使用 k 均值聚类算法的图像压缩的概述和实现,以及不同 k 值的压缩图像的比较
在 Unsplash 上拍摄的 ThisisEngineering RAEng
图像压缩是一种应用于数字图像的数据压缩,不会将图像质量降低到不可接受的水平。文件大小的减小允许在给定数量的磁盘或内存空间中存储更多的图像。它还减少了通过互联网发送图像或从网页下载图像所需的时间。
图像压缩是如何工作的?[1]
I 图像压缩算法利用视觉感知和图像数据的统计特性来提供卓越的结果。有两种图像压缩方法—无损和有损。让我们快速浏览一下它们。
无损压缩:
这是一种用来减小文件大小的方法,同时保持与压缩前相同的质量。无损压缩不会损害数据的质量,并且文件可以恢复到原始形式。在这种类型的压缩中,文件的大小不会改变。用于无损压缩的算法有:
- 行程编码
- 霍夫曼编码
- 算术编码
有损压缩:
有损压缩是一种消除不明显数据的压缩方法。为了使照片更小,有损压缩会丢弃照片中不太重要的部分。压缩文件无法完全还原为原始形式。在这种类型的压缩中,数据质量会受到影响,数据大小也会发生变化。有损压缩主要用于图像、音频和视频压缩,不同的有损压缩算法有:
- 离散余弦变换
- 分形压缩
- 变换编码
我们将使用 K 均值聚类技术进行图像压缩,这是一种压缩的**变换方法。**使用 K 均值聚类,我们将对图像中存在的颜色进行量化,这将进一步帮助压缩图像。
什么是 K-Means 聚类?
K-Means 算法是一种基于质心的聚类技术。这种技术将数据集聚类成 k 个不同的聚类。k-means 聚类算法中的每个聚类都由其质心点表示。
**左图:**数据集图,右图:三均值聚类结果图,(图 1)
上图(图 1)描述了如何使用 k=3 的 k 均值聚类算法为给定数据集形成 3 个聚类。
此外,阅读本文了解更多关于 k-Means 聚类算法的知识。
[## 了解 K-means、K-means++和 K-medoids 聚类算法
了解 K-means、K-means++和 K-Medoids 聚类算法及其关系的概述。这篇文章…
towardsdatascience.com](/understanding-k-means-k-means-and-k-medoids-clustering-algorithms-ad9c9fbf47ca)
K-Means 聚类技术是如何压缩图像的?
在彩色图像中,每个像素的大小为 3 字节(RGB),其中每种颜色的强度值可以从 0 到 255。根据组合学,可以表示的颜色总数是 256256256(等于 16,777,216)。实际上,我们在一幅图像中只能看到比上述数字少得多的几种颜色。因此 k-Means 聚类算法利用了人眼的视觉感知,并且使用很少的颜色来表示图像。具有不同强度值(RGB 值)的颜色对于人眼来说似乎是相同的。K-Means 算法利用了这一优势,并剔除了相似的颜色(在一个聚类中靠得很近)。下面是这种工作方式的一个例子:
从输入图像中选择一些像素,(图像 2)
在上面的图像(图像 2)中,选取了几个像素,并在后续图像中进行了扩展,以继续说明。
**左:**上面拾取的像素的最大化图像,**右:**两个附近的像素 x 和 y ,(图像 3)
从输入图像(图像 2)中拾取的像素在(图像 3)的左侧部分被扩展。在(图 3)的右侧,选取了两个邻近的像素(名称为“x”和“y”)。
如果“x”和“y”像素的 RGB 值分别为(130,131,140)和(127,132,137 ),那么下面是人眼如何看到这些两像素颜色的图示。下图显示的是从 w3schools 得到的 RGB 色彩强度。
**上图:**颜色为 RGB(130,131,140)下图:颜色为 RGB(127,132,137)(图 4)
在上面的图像(图像 4)中,观察到对于 RGB 值的一些变化,颜色对于人眼来说是相似的。因此,k-Means 聚类可以将这两种颜色结合在一起,并可以用一个与人眼几乎相同的质心点来表示。
图像的初始尺寸是 7501000 像素。对于每个像素,图像具有表示 RGB 强度值的三维。RGB 亮度值的范围从 0 到 255。由于亮度值有 256 个值(2 * 8),所以存储每个像素值所需的存储量是 38 位。
最后,图像的初始大小为(75010003*8)比特。
颜色组合的总数等于(256256256)(等于 16,777,216)。由于人眼无法一次感知如此多的颜色,所以我们的想法是将相似的颜色组合在一起,用更少的颜色来表现图像。
我们将使用 k-Means 聚类来寻找 k 个颜色,这些颜色将代表其相似的颜色。这些 k 色将是算法中的质心点。然后我们将每个像素值替换为它的质心点。与总的颜色组合相比,仅使用 k 值形成的颜色组合将非常少。我们将尝试不同的 k 值,并观察输出图像。
如果 k=64,则输出图像的最终大小将是(75010006 + 6438)位,因为强度值的范围是 2**6。
如果 k=128,则输出图像的最终大小将是(75010007 + 12838)位,因为强度值的范围是 2**7。
因此,观察到图像的最终尺寸在很大程度上比原始图像减小。
实施:
(作者代码)
实施的逐步演练:
- 图像输入(第 6-8 行) : 从磁盘加载图像。
- 重塑输入图像(第 15 行) : 输入图像的大小为(rows,cols,3),将所有像素值扁平化为大小为(rowscols)的单一维度,每个像素的维度为 3 代表 RGB 值。展平图像的大小将为(rowscols,3)。
- 聚类(第 18–19 行) : 实现 k-Means 聚类算法,找到代表其周围颜色组合的 k-形心点。
- 将每个像素替换为其质心点(第 22–23 行) : (行*列)数量的像素的所有颜色组合现在由其质心点表示。将每个像素的值替换为其质心点。
- 重塑压缩图像(第 26 行) : 将(rows*cols,3)维度的压缩图像重塑为原始(rows,cols,3)维度。
- 输出压缩图像(第 29–31 行) : 显示输出图像并保存到磁盘。
结果和观察:
原图:
原始图像
不同“k”值的压缩图像:
以上 8 幅图像描述了不同 k 值的压缩图像的结果
以下是所有输入和输出图像的详细信息:
输入图像( original_image.png )和输出压缩图像( compressed_image_k.png )的细节
从上图中观察到:
- 所有压缩图像( compressed_image_k.png )的尺寸与输入图像( original_image.png )的尺寸相同。
- 压缩图像的尺寸随着 k 的减小而减小。
- 对于 k=32,64,128,256 的值,输出的压缩图像看起来相当好并且失去颜色,并且人眼不可见。与 k=32 的原始图像相比,压缩图像的大小减小了几乎 3 倍。
- 对于 k=16,8 的值,输出的压缩图像丢失了许多颜色,并且有损压缩对于人眼是可见的。
- 对于 k=4,2 的值,输出的压缩图像丢失了几乎所有的颜色,并且图像的内容也丢失了。
参考文献:
[1]keycdn.com,(2018 . 11 . 21),什么是图像压缩?htps://www . key dn . com/support/what-is-image-compression
感谢您的阅读!
图像数据标签和注释—您需要知道的一切
了解不同类型的注释、注释格式和注释工具
贴有标签的蓝莓瓶(照片由王思然·哈德森在 Unsplash 上拍摄)
数据标记是监督机器学习任务中的一个重要步骤。 Garbage In Garbage Out 是机器学习社区常用的一个短语,意思是训练数据的质量决定了模型的质量。用于数据标记的注释也是如此。如果你给一个孩子看一个西红柿,并说这是一个土豆,下一次孩子看到一个西红柿,很可能他会把它归类为土豆。正如机器学习模型以类似的方式学习一样,通过查看示例,模型的结果取决于我们在训练阶段输入的标签。
数据标记是一项需要大量手工工作的任务。如果你能为你的项目找到一个好的开放数据集,那就是标签,运气在你这边!但大多数情况下,情况并非如此。很有可能要自己去经历数据标注的过程。
在本帖中,我们将探讨图像的注释类型、常用的注释格式以及一些可用于图像数据标注的工具。
图像注释类型
在开始图像注释之前,了解现有的不同注释类型是很有用的,这样您就可以为您的用例选择正确的类型。
以下是几种不同类型的注释:
**包围盒:**包围盒是计算机视觉中最常用的注释类型。边界框是用于定义目标对象位置的矩形框。它们可以由矩形左上角的𝑥和𝑦轴坐标以及右下角的𝑥和𝑦轴坐标来确定。边界框通常用于对象检测和定位任务。
被检测汽车的边界框(原始照片由 Patricia Jekki 在 Unsplash 上拍摄)
边界框通常由两个坐标(x1,y1)和(x2,y2)表示,或者由一个坐标(x1,y1)和边界框的宽度(w)和高度(h)表示。(见下图)
显示坐标 x1、y1、x2、y2、宽度(w)和高度(h)的边框(图片由 Unsplash 上的 an_vision 拍摄)
**多边形分割:**物体并不总是矩形的。根据这一想法,多边形分割是另一种类型的数据注释,其中使用复杂的多边形而不是矩形来以更精确的方式定义对象的形状和位置。
来自 COCO 数据集的图像的多边形分割(来源)
**语义分割:**语义分割是一种逐像素的标注,其中图像中的每个像素都被分配到一个类别。这些类别可以是行人、汽车、公共汽车、道路、人行道等。,且每个像素携带一个语义含义。
语义分割主要用于环境背景非常重要的情况。例如,它被用于自动驾驶汽车和机器人,因为模型可以了解他们正在操作的环境。
来自 Cityscapes 数据集的图像的语义分割(来源
3D 长方体: 3D 长方体类似于具有关于对象的附加深度信息的边界框。因此,有了 3D 长方体,你可以获得物体的 3D 表示,允许系统在 3D 空间中区分体积和位置等特征。
3D 长方体的一个用例是在自动驾驶汽车中,它可以使用深度信息来测量物体与汽车的距离。
图像上的三维长方体标注(原图由何塞·卡巴贾尔在 Unsplash 上拍摄)
**关键点和界标:**关键点和界标注释用于通过在图像上创建点来检测小物体和形状变化。这种类型的注释对于检测面部特征、面部表情、情绪、人体部位和姿势是有用的。
COCO 数据集的关键点注释示例(来源
**直线和样条:**顾名思义,这种类型的注释是通过使用直线和样条来创建的。它通常用于自动驾驶汽车的车道检测和识别。
道路上的线标注(原图由卡斯滕·沃思在 Unsplash 上拍摄)
图像注释格式
谈到图像注释,没有单一的标准格式。以下是几种常用的注释格式:
COCO: COCO 有五种注释类型:用于对象检测、关键点检测、素材分割、全景分割、图像字幕。使用 JSON 存储注释。
对于对象检测,COCO 遵循以下格式:
annotation{"id" : int,"image_id": int,"category_id": int,"segmentation": RLE or [polygon],"area": float,"bbox": [x,y,width,height],"iscrowd": 0 or 1,}categories[{"id": int,"name": str,"supercategory": str,}]
Pascal VOC: Pascal VOC 在 XML 文件中存储注释。下面是一个用于对象检测的 Pascal VOC 注释文件的例子。
<annotation>
<folder>Train</folder>
<filename>01.png</filename>
<path>/path/Train/01.png</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>224</width>
<height>224</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>36</name>
<pose>Frontal</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<occluded>0</occluded>
<bndbox>
<xmin>90</xmin>
<xmax>190</xmax>
<ymin>54</ymin>
<ymax>70</ymax>
</bndbox>
</object>
</annotation>
YOLO: 在 YOLO 标注格式中,为同一目录下的每个图像文件创建一个同名的.txt
文件。每个.txt
文件包含相应图像文件的注释,即对象类别、对象坐标、高度和宽度。
<object-class> <x> <y> <width> <height>
对于每个对象,创建一个新行。
以下是 YOLO 格式的注释示例,其中图像包含两个不同的对象。
0 45 55 29 67
1 99 83 28 44
图像注释工具
以下是可用于注释图像的工具列表:
摘要
在这篇文章中,我们讨论了什么是数据注释/标签,以及为什么它对机器学习很重要。我们查看了 6 种不同类型的图像注释:包围盒、多边形分割、语义分割、3D 长方体、关键点和界标、线条和样条线,以及 3 种不同的注释格式:COCO、Pascal VOC 和 YOLO。我们还列出了一些可用的图像注释工具。
在下一篇文章中,我们将详细介绍如何注释图像数据。
敬请期待!
你常用什么图像标注类型?你用哪种格式来注释你的图像? 在下面留下你的想法作为评论。
原载于*www.xailient.com/blog*。**
找一个预先训练好的人脸检测模型。点击这里下载。
查看这篇文章了解更多关于创建一个健壮的对象检测模型的细节。
参考文献:
有许多类型的计算机视觉图像注释,每一种注释技术…
hackernoon.com](https://hackernoon.com/illuminating-the-intriguing-computer-vision-uses-cases-of-image-annotation-w21m3zfg) [## 计算机视觉的最佳图像注释平台(对每个平台的诚实评论)
需要标注计算机视觉数据集?我们人类在循环中可以分享一些关于最佳注释的见解…
hackernoon.com](https://hackernoon.com/the-best-image-annotation-platforms-for-computer-vision-an-honest-review-of-each-dac7f565fea) [## 24 款最佳计算机视觉图像注释工具| Lionbridge AI
图像注释是在图像中手动定义区域并为这些区域创建基于文本的描述的过程
lionbridge.ai](https://lionbridge.ai/articles/image-annotation-tools-for-computer-vision/)
关于作者
Sabina Pokhrel 在 Xailient 工作,这是一家计算机视觉初创公司,已经建立了世界上最快的边缘优化物体探测器。*
基于吉布斯采样的图像去噪
概念和代码实现
作者照片
在本教程中,我将向你展示如何实现吉布斯采样算法去噪图像。
我们的目标是通过使用吉布斯采样(一种马尔可夫链蒙特卡罗(MCMC)方法)从受损图像(右)中去除噪声来恢复真实图像(左)。
本教程分为三个部分:
- MCMC 和 Gibbs 抽样的理论概念
- 这个问题的数学推导
- Python 中的代码实现
MCMC 和 Gibbs 抽样
马尔可夫链蒙特卡罗(MCMC)是一种采样方法,用于通过从概率分布中随机采样并构建马尔可夫链来近似感兴趣参数的后验分布。
Gibbs 采样是一种 MCMC 算法,它生成样本的马尔可夫链,每个样本都与其直接邻居一起计算。例如,在贝叶斯网络中,每个样本仅依赖于其父节点、共同父节点和子节点;在马尔可夫随机场中,每个样本都与其马尔可夫毯相关联。这个独立性属性简化了问题,因为为了获得状态 s 的样本值,我们只需要条件概率 P(s|s_neighbors) 。
MCMC 算法通常有一个预烧期,在此期间样本可能不准确。因此,在预烧期后收集样本,并使用蒙特卡罗方法估计后验概率。
数学演绎
吉布斯采样的应用之一是图像去噪。对于我们的图像去噪问题,给定一个有噪声的图像 X ,目标是将其恢复到原始图像 Y ,未知。
我们知道一个噪声图像数组 X = {xij} ,其中xij∈{-1,+1} 表示第 I 行第 j 列的像素,图像是黑白的, xij = 1 对应黑色, xij = -1 对应白色。
原始图像(无噪声) Y 与有噪声图像 X 大小相同,其中yij∈{-1,+1} 表示添加噪声前 xij 的值。
去噪可以被视为概率推断,其中我们通过最大化后验分布 p(Y|X) 来执行最大后验(MAP)估计。由贝叶斯定理我们得到:p(Y | X)= p(X | Y)p(Y)/p(X)。在日志空间,这可以重写为:
既然给定了 X,最大化 log p(Y|X) 本质上等价于最小化*—log p(X | Y)—log p(Y)**,这就是这个问题中的损失函数。*
用于图像去噪的经典结构是成对 MRF,如下图所示。每个节点 yij 与其对应的输出 xij 和 4 个直接邻居(上、下、左、右)相连。因此,给定像素 yij、 的 5 个邻居,我们可以确定 yij 的概率分布,而无需查看其他像素。请注意,边缘上的像素具有较少的邻居。例如,y11 的邻居是 y12、y21 和 x11。为了方便起见,我们可以在实现算法时用 0 填充边缘,这样所有像素都有 5 个邻居。
假设我们的后验偏好是黑色,我们想要最大化的后验是 p(Y=1|Y_neighbors) ,其中 Y= { yij }对于 i = 1,…,N,j = 1,…,M 。 Y 和 X 的联合概率为:
其中 ita( η )和 beta( β )是我们的超参数,Z 是归一化常数。 N(ij) 是 yij 除 xij 外的对应邻居。
使用贝叶斯规则,我们可以从联合分布中得到后验分布,如下所示:
我们还可以得到损失函数*—log p(X | Y)——log p(Y),*写为:
我们称之为能量,因为损失相当于玻尔兹曼分布中的能量,其中具有较低能量的状态总是具有较高的概率。
有了所有的数学方程式,现在我们可以开始了!
在下一节中,我们将学习如何在 Python 中实现 Gibbs 采样来恢复图像。
代码实现
首先,我编写了一些伪代码来演示吉布斯采样的高级逻辑:
现在让我们深入研究代码!
函数denoise_image()
是入口函数。它调用另一个函数 get_posterior 来获得估计的后验概率 p(Y=1|Y_neighbor) 。将阈值设置为 0.5,我们可以从后验得到恢复的图像数组 Y。接下来,我们剥离图像数组的边缘并返回它。下面的 load_image 函数解释了为什么我们需要剥离数组。
在load_image()
中,我们首先将 PNG 图像读入一个 numpy 数组,然后将 RGB 图像转换为灰度,并将像素重新缩放为{-1,1}。在这里,我们添加 0 填充到边缘,以帮助我们在以后搜索每个像素的邻居时处理拐角情况。
现在我们可以跳到get_posterior
函数中的主要逻辑实现。
在加载噪声图像 X 并随机初始化恢复图像 Y 之后,我们开始循环采样 Y 并计算后验概率 P(Y|Y_neighbor) 。
在每一步,我们迭代 I,j,通过调用函数sample_y()
对 Y 中的每个像素 yij 进行采样,并用采样值 yij 更新 Y 。我们还跟踪能量(等式 6),以便稍后可以可视化收敛。当老化期结束时,我们对 Y 中的 yij 的事件 yij = 1 的总发生次数进行求和。
一旦采样完成,我们使用蒙特卡罗方法来获得后验概率,这实质上是将 Y 的聚合值除以总样本数。
每个样品 yij 是怎么得到的?我们来看看函数sample_y()
。
sample_y()
功能需要 4 个输入:行和列索引 I 和 j、恢复图像阵列 Y 和噪声图像阵列 X 。该函数搜索 yij 的邻居yij _ neighbors并根据等式(5)* 计算条件概率P(yij = 1 | yij _ neighbors)。*
yij (1 或-1)的值用条件概率采样并由函数返回。
最后,我们有两个助手函数。
plot_energy()
将节省的能量可视化,save_image()
帮助将去噪后的图像 numpy 数组转换为 PNG 图像。
现在,让我们把所有东西放在main
模块中。
我们指定超参数 ita( η )和 beta( β )、总样本数和老化步骤。我们还设置了一个日志路径来记录能量。
来自denoise_image()
的输出降噪 _img 是恢复的图像阵列 Y 。
经过 100 步老化和 1000 步采样,我们可以看到我们的吉布斯采样做了一个体面的工作恢复损坏的图像,如下所示。
我们也可以检查能量汇聚。从下图中,我们发现虽然图像 Y 被随机初始化,但是能量很快收敛到一个低值。
就是这样!你可以在我的 Github 上找到完整的代码实现。
我们从这篇文章中学到了什么
- 马尔可夫链蒙特卡罗(MCMC)和吉布斯抽样;
- 基于成对马尔可夫随机场模型的地图推理:
- 如何在 Python 中对图像去噪应用 Gibbs 采样
我希望你喜欢这篇文章:)
参考
基于 OpenCV 和 Python 的图像增强技术
作者图片
在这篇博文中,我将展示如何使用图像处理技术从低分辨率/模糊图像/低对比度图像中提高质量并提取有意义的信息。
让我们开始这个过程:
我有一个在传送带上运行的从仓库中取出的液化石油气钢瓶的样本图像。我的目的是找出石油气瓶的批号,以便我可以更新有多少石油气瓶已经过质量检查。
步骤 1:导入必要的库
**import** cv2
**import** numpy **as** np
**import** matplotlib.pyplot **as** plt
步骤 2:加载图像并显示示例图像。
img= cv2.imread(**'cylinder1.png'**)
img1=cv2.imread(**'cylinder.png'**)
images=np.concatenate(img(img,img1),axis=1)
cv2.imshow(**"Images"**,images)
cv2.waitKey(0)
cv2.destroyAllWindows()
作者提供的(a)批次-D26 (b)批次 C27 的液化石油气钢瓶图片
正如你所看到的,图像的对比度很差。我们几乎认不出批号。这是雷电条件不合适的仓库常见的问题。进一步将讨论对比度受限的自适应直方图均衡化,并尝试在数据集上实验不同的算法。
步骤 3:将图像转换成灰度图像
gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray_img1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
步骤 4:现在我们找出灰度图像的直方图,并寻找强度的分布。
hist=cv2.calcHist(gray_img,[0],**None**,[256],[0,256])
hist1=cv2.calcHist(gray_img1,[0],**None**,[256],[0,256])
plt.subplot(121)
plt.title(**"Image1"**)
plt.xlabel(**'bins'**)
plt.ylabel(**"No of pixels"**)
plt.plot(hist)
plt.subplot(122)
plt.title(**"Image2"**)
plt.xlabel(**'bins'**)
plt.ylabel(**"No of pixels"**)
plt.plot(hist1)
plt.show()
步骤 5:现在我们将使用 cv2.equalizeHist()函数来均衡给定灰度图像的对比度。cv2.equalizeHist()函数使亮度正常化,同时增加对比度。
gray_img_eqhist=cv2.equalizeHist(gray_img)
gray_img1_eqhist=cv2.equalizeHist(gray_img1)
hist=cv2.calcHist(gray_img_eqhist,[0],**None**,[256],[0,256])
hist1=cv2.calcHist(gray_img1_eqhist,[0],**None**,[256],[0,256])
plt.subplot(121)
plt.plot(hist)
plt.subplot(122)
plt.plot(hist1)
plt.show()
步骤 6:显示灰度直方图均衡化的图像
eqhist_images=np.concatenate((gray_img_eqhist,gray_img1_eqhist),axis=1)
cv2.imshow(**"Images"**,eqhist_images)
cv2.waitKey(0)
cv2.destroyAllWindows()
灰度直方图均衡化
让我们进一步深入了解 CLAHE
第七步:
对比度受限的自适应直方图均衡化
该算法可用于提高图像的对比度。该算法通过创建图像的几个直方图来工作,并使用所有这些直方图来重新分配图像的亮度。CLAHE 可以应用于灰度图像和彩色图像。有两个参数需要调整。
- 设定对比度限制阈值的限幅限制。默认值为 40
- tileGridsize 设置行和列中标题的数量。在应用 cla 时,图像被分成称为图块(8*8)的小块,以便执行计算。
clahe=cv2.createCLAHE(clipLimit=40)
gray_img_clahe=clahe.apply(gray_img_eqhist)
gray_img1_clahe=clahe.apply(gray_img1_eqhist)
images=np.concatenate((gray_img_clahe,gray_img1_clahe),axis=1)
cv2.imshow(**"Images"**,images)
cv2.waitKey(0)
cv2.destroyAllWindows()
克拉赫
第八步:
阈值技术
阈值化是一种简单而有效的方法,用于将图像分割成前景和背景。最简单的阈值处理方法是,如果像素强度小于某个预定义的常数(阈值),则用黑色像素替换源图像中的每个像素,如果像素强度大于阈值,则用白色像素替换。不同类型的阈值是:-
cv2。THRESH_BINARY
cv2。阈值 _ 二进制 _INV
cv2。TRUNC 阈值
cv2。阈值为零
cv2。THRESH_TOZERO_INV
cv2。OTSU 阈值
cv2。阈值三角形
尝试更改阈值和 max_val 以获得不同的结果。
th=80
max_val=255
ret, o1 = cv2.threshold(gray_img_clahe, th, max_val, cv2.THRESH_BINARY)
cv2.putText(o1,**"Thresh_Binary"**,(40,100),cv2.FONT_HERSHEY_SIMPLEX,2,(255,255,255),3,cv2.LINE_AA)
ret, o2 = cv2.threshold(gray_img_clahe, th, max_val, cv2.THRESH_BINARY_INV)
cv2.putText(o2,**"Thresh_Binary_inv"**,(40,100),cv2.FONT_HERSHEY_SIMPLEX,2,(255,255,255),3,cv2.LINE_AA)
ret, o3 = cv2.threshold(gray_img_clahe, th, max_val, cv2.THRESH_TOZERO)
cv2.putText(o3,**"Thresh_Tozero"**,(40,100),cv2.FONT_HERSHEY_SIMPLEX,2,(255,255,255),3,cv2.LINE_AA)
ret, o4 = cv2.threshold(gray_img_clahe, th, max_val, cv2.THRESH_TOZERO_INV)
cv2.putText(o4,**"Thresh_Tozero_inv"**,(40,100),cv2.FONT_HERSHEY_SIMPLEX,2,(255,255,255),3,cv2.LINE_AA)
ret, o5 = cv2.threshold(gray_img_clahe, th, max_val, cv2.THRESH_TRUNC)
cv2.putText(o5,**"Thresh_trunc"**,(40,100),cv2.FONT_HERSHEY_SIMPLEX,2,(255,255,255),3,cv2.LINE_AA)
ret ,o6= cv2.threshold(gray_img_clahe, th, max_val, cv2.THRESH_OTSU)
cv2.putText(o6,**"Thresh_OSTU"**,(40,100),cv2.FONT_HERSHEY_SIMPLEX,2,(255,255,255),3,cv2.LINE_AA)
final=np.concatenate((o1,o2,o3),axis=1)
final1=np.concatenate((o4,o5,o6),axis=1)
cv2.imwrite(**"Image1.jpg"**,final)
cv2.imwrite(**"Image2.jpg"**,final1)
Thresh_Binary_inv,Thresh_Binary_inv,Thresh_Tozero
Thresh_Tozero_inv,Thresh_trunc,Thresh_OSTU
步骤 9:自适应阈值
在上一节中,我们已经使用全局阈值应用了 cv2.threshold()。正如我们所看到的,由于图像不同区域的光照条件不同,获得的结果不是很好。在这些情况下,您可以尝试自适应阈值处理。在 OpenCV 中,自适应阈值处理由函数 cv2.adapativeThreshold() 执行
该功能将自适应阈值应用于 src 阵列(8 位单通道图像)。maxValue 参数设置满足条件的 dst 图像中的像素值。adaptiveMethod 参数设置要使用的自适应阈值算法。
cv2。ADAPTIVE _ THRESH _ MEAN _ C:T(x,y)阈值计算为(x,y)的 blockSize x blockSize 邻域的均值减去 C 参数。
cv2。ADAPTIVE _ THRESH _ GAUSSIAN _ C:T(x,y)阈值计算为(x,y)的 blockSize x blockSize 邻域的加权和减去 C 参数。
blockSize 参数设置用于计算像素阈值的邻域的大小,它可以取值 3、5、7…等等。
C 参数只是从平均值或加权平均值中减去的常数(取决于 adaptive method 参数设置的自适应方法)。通常,该值为正值,但也可以为零或负值。
gray_image = cv2.imread(**'cylinder1.png'**,0)
gray_image1 = cv2.imread(**'cylinder.png'**,0)
thresh1 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
thresh2 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 31, 3)
thresh3 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 13, 5)
thresh4 = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 4)
thresh11 = cv2.adaptiveThreshold(gray_image1, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
thresh21 = cv2.adaptiveThreshold(gray_image1, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 31, 5)
thresh31 = cv2.adaptiveThreshold(gray_image1, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21,5 )
thresh41 = cv2.adaptiveThreshold(gray_image1, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 5)
final=np.concatenate((thresh1,thresh2,thresh3,thresh4),axis=1)
final1=np.concatenate((thresh11,thresh21,thresh31,thresh41),axis=1)
cv2.imwrite(**'rect.jpg'**,final)
cv2.imwrite(**'rect1.jpg'**,final1)
自适应阈值
自适应阈值
第十步:
OTSU 二值化
Otsu 的二值化算法,这是一种处理双峰图像的好方法。双峰图像可以通过包含两个峰值的直方图来表征。Otsu 的算法通过最大化两类像素之间的方差来自动计算分离两个峰值的最佳阈值。等效地,最佳阈值使类内方差最小化。Otsu 的二值化算法是一种统计方法,因为它依赖于从直方图中获得的统计信息(例如,平均值、方差或熵)
gray_image = cv2.imread(**'cylinder1.png'**,0)
gray_image1 = cv2.imread(**'cylinder.png'**,0)
ret,thresh1 = cv2.threshold(gray_image,0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
ret,thresh2 = cv2.threshold(gray_image1,0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imwrite(**'rect.jpeg'**,np.concatenate((thresh1,thresh2),axis=1))
OTSU 二值化
现在,我们已经从低对比度图像中清楚地识别出批号。希望你觉得这篇博客内容丰富且有趣。
谢谢大家!!
请继续关注我的下一篇博客…
你可以通过下面的链接访问我以前的博客
在我的 Youtube 频道上关注我
https://www.youtube.com/channel/UCSp0BoeXI_EK2W0GzG7TxEw
在此与我联系:
领英:https://www.linkedin.com/in/ashishban…
github:https://github.com/Ashishb21
中:https://medium.com/@ashishb21
电子邮件:techplanetai@gmail.com ashishb21@gmail.com
关注我的 Youtube 频道,观看与技术相关的视频
https://www.youtube.com/channel/UCSp0BoeXI_EK2W0GzG7TxEw
[## 用 OpenCV 和 OpenCV Contrib 构建 Python 源代码
从源代码在 Ubuntu 14.0 LTS 上安装 Python 3.7
towardsdatascience.com](/building-python-source-with-opencv-and-opencv-contrib-ba95d709eb) [## 使用深度神经网络的印度演员分类
如果你需要使用深度网络对你最喜欢的演员进行分类,该怎么办?
towardsdatascience.com](/indian-actors-classification-using-deep-neural-networks-8552573f39aa)
图像特征提取:传统和深度学习技术
简要的综述着重于给出用于特征提取的传统和深度学习技术的概述
特征提取是计算机视觉中的一项重要技术,广泛用于以下任务:
- 物体识别
- 图像对齐和拼接(创建全景)
- 三维立体重建
- 机器人/自动驾驶汽车导航
- 还有更多…
什么是特性?
特征是图像中帮助识别对象的部分或模式。例如,一个正方形有四个角和四条边,它们可以被称为正方形的特征,它们帮助我们人类识别它是一个正方形。特征包括像角、边、感兴趣点的区域、脊等属性。
如下图所示,黄色点表示使用哈里斯检测技术检测到的特征。
(src:https://commons . wikimedia . org/wiki/File:Writing _ Desk _ with _ Harris _ detector . png)
传统特征检测技术一瞥
用于特征检测的传统计算机视觉技术包括:
- Harris 角点检测— 使用高斯窗口函数来检测角点。(阅读更多)
- Shi-Tomasi 角点检测器— 作者修改了 Harris 角点检测中使用的评分函数,以实现更好的角点检测技术(阅读更多信息)
- **尺度不变特征变换(SIFT)——**与前两种不同,这种技术是尺度不变的。(阅读更多)
- **加速鲁棒特征(SURF)——**顾名思义,这是 SIFT 的更快版本。(阅读更多)
- 加速分段测试(FAST)的特征— 这是一种比 SURF 更快的角点检测技术。(阅读更多)
- **二元鲁棒独立基本特征(BRIEF)——**这只是一个特征描述符,可用于任何其他特征检测器。这种技术通过将浮点数形式的描述符转换为二进制字符串来减少内存使用。(阅读更多)
- 定向快速旋转简报(ORB) — SIFT 和 SURF 已获专利,OpenCV 实验室的这种算法是它们的免费替代品,它使用快速关键点检测器和简报描述符。(阅读更多)
深度学习特征提取技术一瞥
传统的特征提取器可以由卷积神经网络(CNN)代替,因为 CNN 具有提取复杂特征的强大能力,这些复杂特征更详细地表达了图像,学习特定于任务的特征,并且更有效。在这方面已经做了许多工作。下面列出了其中的一些:
- SuperPoint:自我监督的兴趣点检测和描述 ( 论文 ) —作者提出了一个完全卷积的神经网络,它在单次正向传递中计算 SIFT 样的兴趣点位置和描述符。它使用 VGG 式编码来提取特征,然后使用两个解码器,一个用于点检测,另一个用于点描述。
超点架构(src:https://arxiv.org/pdf/1712.07629.pdf
- D2 网:一个可训练的 CNN,用于局部特征的联合描述和检测 【论文】——作者提出了一个单一的卷积神经网络,它既是密集特征描述符,又是特征检测器。
检测并描述 https://arxiv.org/pdf/1905.03561.pdf 的 D2 网络
- LF-Net:从图像中学习局部特征 ( 论文 ) — 作者建议使用稀疏匹配深度架构,并在具有相对姿态和深度图的图像对上使用端到端训练方法。他们在第一幅图像上运行检测器,找到最大值,然后优化权重,以便在第二幅图像上运行时,产生清晰的响应图,在正确的位置具有尖锐的最大值。
LF-Net(src:https://papers . nips . cc/paper/7861-LF-Net-learning-local-features-from-images . pdf)
- 基于深度学习的图像特征匹配 ( 论文)——他们采用一种深度卷积神经网络(CNN)模型,在图像特征点匹配中关注图像块。
与 SIFT 和 SURF 相比的结果(src:https://ieeexplore.ieee.org/abstract/document/8780936)
- 特征匹配问题的深度图形特征学习 ( 论文 ) —他们建议使用图形神经网络将特征点的坐标转换为局部特征,这样就可以很容易地使用简单的推理算法进行特征匹配
结论
虽然看起来用于特征提取的深度学习技术对缩放、遮挡、变形、旋转等更加鲁棒,并且已经突破了使用传统计算机视觉技术的极限,但这并不意味着计算机视觉技术已经过时。
放弃
这是一篇简短的文章,重点是概述传统的和深度学习的特征提取技术。如果你认为我可能错过了一个应该提到的算法,请在评论中留下它(将在这里加上适当的学分)。
参考文献
https://www . cs . UBC . ca/research/FLANN/uploads/FLANN/FLANN _ manual-1 . 8 . 4 . pdf
https://arxiv.org/pdf/1712.07629.pdf
https://arxiv.org/pdf/1905.03561.pdf
https://arxiv.org/ftp/arxiv/papers/1910/1910.13796.pdf
https://papers . nips . cc/paper/7861-lf-net-learning-local-features-from-images . pdf
【https://ieeexplore.ieee.org/abstract/document/8780936
https://docs . opencv . org/3.4/DC/d0d/tutorial _ py _ features _ Harris . html
https://docs . opencv . org/3.4/D4/d8c/tutorial _ py _ Shi _ tomasi . html
https://docs . opencv . org/3.4/da/df5/tutorial _ py _ sift _ intro . html
https://docs . opencv . org/3.4/da/df5/tutorial _ py _ sift _ intro . html
https://docs . opencv . org/3.4/df/dd2/tutorial _ py _ surf _ intro . html
https://docs.opencv.org/3.4/df/d0c/tutorial_py_fast.html
https://docs.opencv.org/3.4/dc/d7d/tutorial_py_brief.html
https://docs.opencv.org/3.4/d1/d89/tutorial_py_orb.html
利用生成性对抗网络在 10 分钟内生成图像
深度学习案例研究
与 VIZIO AI 合作,使用 TensorFlow 和 MNIST 数据集,使用无监督深度学习生成具有深度卷积 gan 的手写数字
如今机器正在生成完美的图像,区分机器生成的图像和原件变得越来越困难。
如果你正在阅读这篇文章,我确信我们有着相似的兴趣,并且正在/将要从事相似的行业。那么我们就通过Linkedin来连线吧!请不要犹豫发送联系请求!Orhan g . Yal n—Linkedin
图一。Nvidia 的 StyleGAN 生成的图像示例【2】
图二。机器生成的数字使用 MNIST [ 3
在我的文章用 MNIST 数据集在 10 分钟内进行图像分类获得了超过 30 万的浏览量后,我决定准备另一个关于深度学习的教程。但这一次,我们不是对图像进行分类,而是使用相同的 MNIST 数据集来生成图像,该数据集代表修改后的国家标准与技术研究所数据库。它是一个手写数字的大型数据库,通常用于训练各种图像处理系统[1]。
生成对抗网络
为了用机器学习生成——基本上——任何东西,我们必须使用生成算法,至少目前,用于图像生成的最好的生成算法之一是生成对抗网络(或 GANs)。
生成对抗网络的发明
GANs 的发明出乎意料。著名的人工智能研究人员*,当时是蒙特利尔大学的博士研究员*,伊恩·古德菲勒,当他在一个朋友的告别派对上与他的朋友讨论其他生成算法的缺陷时,偶然想到了这个想法。聚会结束后,他满怀希望地回到家中,实施了他心中的构想。令人惊讶的是,在第一次试验中,一切都如他所愿[ 5 ],他成功地创建了生成性对抗网络(简称 GANs)。根据脸书人工智能研究主任、纽约大学教授 Yann Lecun 的说法,GANs 是“过去 10 年机器学习中最有趣的想法”。
GANs 的大致结构如下所示:
图 4。利用 CNN 的生成对抗网络(GANs)
在一个普通的 GAN 结构中,有两个相互竞争的代理:一个生成器和一个鉴别器。它们可以使用不同的网络来设计(例如,卷积神经网络(CNN)、递归神经网络( RNNs ),或者仅仅是常规神经网络(ann或常规网络)。由于我们将生成图像,CNN 更适合这项任务。因此,我们将用卷积神经网络来构建我们的代理。
我们的 GAN 模型是如何运作的?
图 5。GAN 网络中的生成器和鉴别器关系|(图表由作者提供)
简而言之,我们将要求生成器生成手写数字,而不给它任何附加数据。同时,我们将获取现有的手写数字到鉴别器,并要求它决定由生成器生成的图像是否是真实的。起初,生成器会生成糟糕的图像,这些图像会立即被鉴别器标记为假的。在从鉴别器获得足够的反馈后,由于与真实图像的差异减少,生成器将学习欺骗鉴别器。因此,我们将获得一个非常好的生成模型,可以给我们非常现实的输出。
构建 GAN 模型
GANs 经常使用复杂的计算,因此,支持 GPU 的机器将使你的生活变得容易得多。所以我会用 Google Colab,用 GPU 加速来减少训练时间。
使用 Google Colab 进行支持 GPU 的培训
对于机器学习任务,在很长一段时间里,我几乎专门通过 Anaconda 发行版使用-iPython- Jupyter Notebook 进行建模、训练和测试。不过,最近我因为几个好的原因转而使用 Google Colab。
Google Colab 在 Jupyter 笔记本的基础上提供了几个附加功能,例如(I)与其他开发人员的协作,(ii)基于云的托管,以及(iii) GPU 和 TPU 加速培训。你可以用免费版的 Google Colab 完成所有这些工作。Python、Jupyter Notebook 和 Google Colab 之间的关系可以形象化如下:
图 6。iPython、Jupyter Notebook、Google Colab |(图由作者提供)之间的关系
Anaconda 为科学计算提供免费和开源的 Python 和 R 编程语言发行版,包括 Jupyter Notebook (iPython)或 Jupyter Lab 等工具。在这些工具之上,Google Colab 允许其用户使用 iPython 笔记本和实验室工具及其服务器的计算能力。
现在,我们已经对作为我们的神经网络架构的生成式对抗网络和作为我们的编程环境的 Google Collaboratory 有了大致的了解,我们可以开始构建我们的模型了。在本教程中,我们将从一个官方的 TensorFlow 教程 [ 7 ]中获取我们自己的内容。
初始进口
Colab 已经预装了大多数机器学习库,因此,您可以通过以下共享方式导入它们:
TensorFlow、Keras 图层和 Matplotlib 导入
为了代码更短,我更喜欢单独导入层,如上所示。
加载并处理 MNIST 数据集
对于本教程,我们可以使用 MNIST 数据集。MNIST 数据集包含 60,000 张训练图像和 10,000 张测试图像,分别来自美国人口普查局员工和美国高中生[ 8 ]。
幸运的是,我们可以直接从 TensorFlow 库中检索 MNIST 数据集。我们从 Tensorflow 中检索数据集,因为这样,我们可以得到它的已处理版本。我们仍然需要做一些准备和处理工作,以使我们的数据适合 GAN 模型。因此,在第二行中,我们将这两组分为训练组和测试组,还将标签和图像分开。
x_train 和 x_test 零件包含灰度 RGB 代码(从 0 到 255),而 y_train 和 y_test 零件包含从 0 到 9 的标签,代表它们实际上是哪个数字。由于我们正在进行无监督的学习任务,我们将不需要标签值,因此,我们使用下划线(即 _)来忽略它们。我们还需要使用 reshape 函数将数据集转换为 4 维。最后,我们将 NumPy 数组转换为 TensorFlow Dataset 对象,以便更有效地进行训练。下面的代码行完成所有这些任务:
我们的数据已经处理完毕,是时候建立我们的 GAN 模型了。
建立模型
如上所述,每个 GAN 必须至少有一个发生器和一个鉴别器。由于我们正在处理图像数据,我们需要从这些网络中的卷积和转置卷积(逆卷积)层中受益。下面我们来定义一下我们的发生器和鉴别器网络。
发电机网络
我们的生成器网络负责从随机噪声中生成 28×28 像素的灰度假图像。因此,它需要接受一维数组并输出 28x28 像素的图像。对于这项任务,我们需要转置卷积层后,重塑我们的 1 维阵列到 2 维阵列。转置卷积层会增加较小数组的大小。我们还利用了 BatchNormalization 和 LeakyReLU 层。以下代码行创建了一个函数,该函数将使用 Keras Sequential API 生成一个发电机网络:
我们可以用下面的代码调用生成器函数:
图 7。我们发电机网的总结|(图由作者提供)
现在我们有了生成器网络,我们可以用下面的代码轻松地生成一个示例图像:
看起来像这样:
图 8。未经训练的生成器网络生成的样本图片|(图片由作者提供)
这只是普通的噪音。但是,它可以从随机噪声阵列中创建图像的事实证明了它的潜力。
鉴别器网络
对于我们的鉴别器网络,我们需要遵循我们的发生器网络的逆版本。它获取 28×28 像素的图像数据并输出单个值,表示真实性的可能性。因此,我们的鉴别器可以检查由生成器生成的样本图像是否是假的。
我们使用与创建生成器网络相同的方法,以下代码行创建了一个函数,该函数将使用 Keras Sequential API 创建一个鉴别器模型:
我们可以用下面的代码调用函数来创建我们的鉴别器网络:
图 9。我们的鉴频器网络总结|(图由作者提供)
最后,我们可以检查未经训练的鉴别器对未经训练的生成器生成的样本说了什么:
输出: tf。张量([[ -0.00108097 ]),shape=(1,1),dtype=float32)
负值表明我们未经训练的鉴别器断定图 8 中的图像样本是假的。目前,重要的是它可以检查图像并提供结果,经过训练后结果会可靠得多。
配置模型
由于我们在 GAN 网络中训练两个子网络,因此需要定义两个损失函数和两个优化器。
损失函数: 我们从从 tf.keras.losses 模块创建一个二元交叉熵对象开始。我们还将 from_logits 参数设置为 True 。创建对象后,我们用定制的鉴别器和生成器损耗函数填充它们。我们的鉴别器损耗计算为(I)鉴别器对真实图像的预测为一组 1,以及(ii)鉴别器对生成图像的预测为一组 0 的组合。我们的发电机损耗是通过测量它欺骗鉴别器的能力来计算的。因此,我们需要将鉴别器对生成图像的决策与 1 的数组进行比较。
优化器: 我们还为发生器和鉴别器网络分别设置了两个优化器。我们可以使用来自TF . keras . optimizer模块的亚当优化器对象。
下面几行配置了我们的损失函数和优化器
设置检查点
我们希望访问之前的训练步骤,TensorFlow 为此提供了一个选项: 检查点 。通过设置一个检查点目录,我们可以保存每个时期的进度。当我们从上一个纪元恢复我们的模型时,这将特别有用。以下代码行通过使用 os 库设置保存所有培训步骤的路径来配置培训检查点
训练模型
现在我们的数据准备好了,我们的模型也创建并配置好了。是时候设计我们的训练循环了。请注意,目前,甘需要定制的训练循环和步骤。我会尽量让你明白。确保阅读了 Github Gists 中的代码注释。
让我们用下面几行创建一些变量:
我们的种子是我们用来生成图像的噪音。下面的代码生成一个形状为(16,100)的正态分布的随机数组。
定义培训步骤
这是我们教程中最不寻常的部分:我们正在设置一个定制的训练步骤。通过注释 tf.function 模块定义自定义 train_step() 函数后,我们的模型将基于我们定义的自定义 train_step() 函数进行训练。
下面带有过多注释的代码是针对培训步骤的。请仔细阅读评论:
现在我们已经用 tf.function 注释创建了我们的定制训练步骤,我们可以为训练循环定义我们的训练函数了。
定义训练循环
我们为训练循环定义了一个名为 train 的函数。我们不仅运行 for 循环在 MNIST 上迭代我们的自定义训练步骤,还使用单个函数执行以下操作:
培训期间:
- 开始记录每个时期开始时花费的时间;
- 制作 GIF 图像并显示它们,
- 每五个时期保存一个模型作为检查点,
- 打印出完整的历元时间;和
- 训练完成后,最终生成最终图像。
以下带有详细注释的行执行所有这些任务:
图像生成功能
在训练函数中,有一个我们还没有定义的自定义图像生成函数。我们的图像生成功能执行以下任务:
- 通过使用模型生成图像;
- 使用 matplotlib 在 4x4 网格布局中显示生成的图像;
- 最后保存最后的数字
以下部门负责这些任务:
开始训练
在训练了三个复杂的函数之后,开始训练是相当容易的。只需使用以下参数调用 train 函数:
如果您使用支持 GPU 的 Google Colab 笔记本电脑,培训将需要大约 10 分钟。如果你用的是 CPU,可能要多花很多。让我们看看 60 个纪元后的最终产品。
图 10。我们的 GAN 在 60 个纪元后生成的数字。请注意,我们看到的是 16 个样本,因为我们是这样配置输出的。|(图片由作者提供)
生成数字
在生成新映像之前,让我们确保使用以下代码行从最新的检查点恢复值:
我们还可以通过查看生成的 4x4 网格来查看我们的生成式 GAN 模型的演变,该网格包含任何时期的 16 个样本数字,代码如下:
这段代码为我们提供了最新生成的网格。在 display_image(函数)中传递一个 0 到 60 之间的不同数字
或者更好的是,让我们用下面的代码创建一个 GIF 图像,可视化我们的 GAN 生成的样本的演变:
我们的输出如下:
图 11。GIF 图像显示了我们的 GAN 生成的样本数字随时间的演变|(图片由作者提供)
如图 11 所示,随着时间的推移,GAN 产生的输出变得更加真实。
恭喜
您已经建立并训练了一个生成式对抗网络(GAN)模型,它可以成功地创建手写数字。显然有一些样本不是很清楚,但对于仅在 6 万个样本上训练的 60 个纪元,我会说结果非常有希望。
一旦你能建立并训练这个网络,你就能生成更复杂的图像,
- 通过处理具有高清晰度彩色图像的较大数据集;
- 通过创建更复杂的鉴别器和发生器网络;
- 通过增加历元的数量;
- 通过在支持 GPU 的强大硬件上工作
最后,你可以创作艺术作品,如诗歌、绘画、文字或现实照片和视频。
订阅邮件列表获取完整代码
如果你想在 Google Colab 上获得完整的代码,并获得我的最新内容,请订阅邮件列表:✉️
喜欢这篇文章吗?
如果你喜欢这篇文章,可以考虑看看我的其他类似文章:
[## 使用 MNIST 数据集在 10 分钟内完成图像分类
towardsdatascience.com](/image-classification-in-10-minutes-with-mnist-dataset-54c35b77a38d) [## TensorFlow 和 VGG19 可以帮助您将照片转换成美丽的波普艺术作品
神经风格转移基于安迪沃霍尔的门罗双联画与预训练的计算机视觉网络 VGG19,转移…
towardsdatascience.com](/tensorflow-and-vgg19-can-help-you-convert-your-photos-into-beautiful-pop-art-pieces-c1abe87e7e01) [## 伯特和拥抱脸 10 分钟情感分析
学习预训练的自然语言处理模型的基础,伯特,并建立一个使用 IMDB 电影评论的情感分类器…
towardsdatascience.com](/sentiment-analysis-in-10-minutes-with-bert-and-hugging-face-294e8a04b671) [## 使用递归神经网络预测比特币(BTC)价格
如果你能以某种方式预测明天的比特币(BTC)价格,这不是很棒吗?加密货币市场有…
towardsdatascience.com](/using-recurrent-neural-networks-to-predict-bitcoin-btc-prices-c4ff70f9f3e4)
资源
[1]奥尔汉·g·亚尔琴,用 MNIST 数据集在 10 分钟内进行图像分类,走向数据科学,https://towardsdatascience . com/Image-Classification-in-10-Minutes-with-Mn ist-Dataset-54c 35 b 77 a 38d
[2]莱蒂宁法官(未注明日期)。分析并改善 StyleGAN Tero Karras NVIDIA samu Li Laine NVIDIA Miika Aittala NVIDIA Janne hells ten NVIDIA的图像质量。从 https://github.com/NVlabs/stylegan2取回
[3]或 Sharir & Ronen Tamari & Nadav Cohen & am non sha shua,Tensorial Mixture Models,https://www . research gate . net/profile/Or _ Sharir/publication/309131743。
[4]维基百科,文件:伊恩 Goodfellow.jpg,https://upload . wikimedia . org/Wikipedia/commons/f/Fe/Ian _ good fellow . jpg
同步,甘斯之父伊恩·古德费勒为苹果拆分谷歌,https://medium . com/SYNCED review/甘斯之父-伊恩·古德费勒-Splits-Google-For-Apple-279 FCC 54 b 328
[5] YOUTUBE,深度学习的英雄:https://www.youtube.com/watch?v=pWAc9B2zJS4 吴恩达采访伊恩·古德菲勒
[6] George Lawton,Generative adversarial networks 可能是 AI 中最强大的算法,https://search enterprise AI . tech target . com/feature/Generative-adversarial-networks-can-be-most-powerful-algorithm-in-AI
[7]深度卷积生成对抗网络,TensorFlow,可在https://www.tensorflow.org/tutorials/generative/dcgan获得
[8]维基百科,https://en.wikipedia.org/wiki/MNIST_database MNIST 数据库,
用一行代码修复图像
使用 Python 中的 OpenCV,使用四种不同的技术和一行代码,使用图像修复来恢复图像。
杰德·斯蒂芬斯在 Unsplash 上的照片
修复是一个过程,其中艺术品的损坏或缺失部分被填充以完成它。使用 GANs 来执行图像修复的现有技术方法,其中复杂模型在大量数据上被训练。如果呈现的数据完全不同,那么模型也可能受到影响。与此相反,图像修复也可以通过图像处理操作来完成,这也只需要使用 OpenCV 的一行代码。在本文中,我们将实现四种不同类型的图像修复方法,并基于 PSNR 和 SSIM 比较它们的结果。此外,我将在本文中遵循一种不同的方法,即首先呈现代码和结果,然后描述方法。
我们将使用三种算法,即基于 Navier-Stokes 的算法、Alexandru Telea 基于快速行进法的方法以及快速频率选择性重建算法的快速和最佳迭代。
目录
- 要求
- 密码
- 结果
- 方法概述
要求
其中两种方法需要 OpenCV Contrib,以便可以使用 pip 安装:
pip install opencv-contrib-python==4.3.0.36
密码
我们需要扭曲的图像和需要修补的蒙版。对于 Navier-Stokes 和 Telea 方法,蒙版上的白色部分代表要修复的区域,而对于 FSR 方法,黑色像素则是在修复的像素。
图像修复所需的单行代码是:
import cv2#distorted_img: The image on which inpainting has to be done.
#mask: Black mask with white pixels to be inpainted*res_NS = cv2.inpaint(distort_img, mask, 3, cv2.INPAINT_NS)
res_TELEA = cv2.inpaint(distort_img, mask, 3, cv2.INPAINT_TELEA)*res_FSRFAST = distorted_img.copy()
res_FSRBEST = distorted_img.copy()
mask1 = cv2.bitwise_not(mask)*cv2.xphoto.inpaint(distort, mask1, res_FSRFAST, cv2.xphoto.INPAINT_FSR_FAST)
cv2.xphoto.inpaint(distort, mask1, res_FSTBEST, cv2.xphoto.INPAINT_FSR_BEST)*
结果
我用了三张大小为 756x1008 的图片。所有四种方法的结果如下所示。
结果 1
结果 2
结果 3
每幅图像的每种方法所用的时间(秒)为:
花费的时间
PSNR 和 SSIM 的值也是使用以下代码根据重建图像与原始图像进行计算的:
import cv2
from skimage.metrics import structural_similarity as SSIMpsnr = cv2.PSNR(img, recon, 255)
ssim = SSIM(img, recon, multichannel=True)
结果是:
PSNR 价值观
SSIM 价值观
此外,Genser 等人发表了一篇论文,对这些方法进行了比较,其中他们使用了 Kodak 和 Tecnick 图像集以及五种不同的错误屏蔽,其结果如下所示:
结果
下面给出了使用的完整代码,其中显示了一个样本遮罩,其中白色区域必须在原始图像上进行修复,并叠加在原始图像上。
面具
方法概述
泰莱亚
Alexandru Telea 在 2004 年的论文“基于快速行进法的图像修复技术”中介绍了这种技术。我在这里引用的 OpenCV 文档对此做了很好的概述。
考虑图像中要修补的区域。算法从该区域的边界开始,进入该区域,首先逐渐填充边界中的所有内容。需要在要修复的邻域的像素周围有一个小的邻域。该像素被邻域中所有已知像素的归一化加权和所代替。砝码的选择是一件重要的事情。对那些靠近该点、靠近边界法线的像素和那些位于边界轮廓上的像素给予更大的权重。一旦像素被修复,它就使用快速行进方法移动到下一个最近的像素。FMM 确保已知像素附近的像素首先被修复,因此它就像一个手动启发式操作。
纳维尔-斯托克斯
由 Bertalmio 等人在他们的论文中介绍,“纳维尔-斯托克斯,流体动力学,以及图像和视频修复”早在 2001 年就介绍过了。再次引用 OpenCV 文档:
该算法基于流体动力学并利用偏微分方程。基本原理是启发式的。它首先沿着边缘从已知区域行进到未知区域(因为边缘应该是连续的)。它继续等照度线(连接具有相同强度的点的线,就像轮廓连接具有相同海拔的点),同时在修复区域的边界匹配梯度向量。为此,使用了流体动力学的一些方法。一旦它们被获得,颜色被填充以减少该区域的最小变化。
快速频率选择性重建算法
使用已知的样本和已经重构的像素作为支持来外推失真块的信号。该算法迭代地产生信号的一般复值模型,该模型被外推为傅立叶基函数的加权叠加。FSR 的一个重要特征是计算是在傅立叶域中进行的,这导致了快速实现。
总之,FSR 的快速实施提供了速度和精度之间的巨大平衡,即使在高度失真的情况下,这些方法也能提供良好的结果,因此它们可以为数据密集型 GAN 提供合理的替代方案,后者在不可预见的数据上可能表现不佳。
参考
- https://docs . opencv . org/master/df/d3d/tutorial _ py _ inpainting . html
- https://docs . opencv . org/4 . 2 . 0/DC/d2f/tutorial _ x photo _ inpainting . html
- https://github . com/opencv/opencv _ contrib/files/3730212/inpainting _ comparison . pdf
如上所述,我在本文中使用了不同的策略。下面给出的一篇文章采用了传统的方法。如果能知道你更喜欢哪种策略就太好了。
一个关于用 Python 实现不同人脸检测模型的完整教程,通过比较,找出最好的…
towardsdatascience.com](/face-detection-models-which-to-use-and-why-d263e82c302c)
使用脸书探测器的图像标记🤖🤖
你好,脸书探测器世界
Canva.com 地平线|免费媒体许可证
训练一个模型从头开始检测文本可能是一项非常困难和令人沮丧的任务。传统的方法是使用具有特征金字塔网络的 R-CNN 或者使用像 YOLO 这样的算法。
如果你不知道这两种方法背后的数学和逻辑,那么这两种方法都很难实现。
由脸书人工智能研究团队开发的 Detectron 2 是一个基于 mask-r-CNN 基准的最新目标检测模型。它的动力来自 Pytorch 深度学习框架。主要功能包括
- 全景分割:FAIR 的另一个产品,是一种将语义分割(给每个像素分配一个类标签)和实例分割(检测和分割每个对象实例)这两种典型的不同任务统一起来的分割类型。
2.密集姿态:用于将 RGB 图像的所有人体像素映射到人体的 3D 表面。这是由咖啡 2 驱动的。
“这种模式旨在通过提供快速培训和解决公司在从研究走向生产时面临的问题来推进物体检测”
我们开始吧!
Detectron 2 可以使用 Google Colab Notebook 实现对象检测。我们选择 Google Colab 而不是本地系统,以利用 GPU 进行更快的训练。
步骤 1:安装并导入 Detectron 2
我们将在 google colab 上编写这些代码,或者您可以在这里 获得整个笔记本 。
为了开始,我们将安装一些依赖项,如 COCO API,CUDA(获取关于 GPU 的信息),Tourch Visison
导入实用程序和公共库
步骤 2:运行预训练的检测器 2 模型
我们将使用来自 COCO 数据集的图像,并将运行一个预训练的模型,如果你想在客户数据集上运行这个模型,请参见这里。
在 COCO 的图像上运行模型的代码:
你已经成功地用 detectron 实现了你的第一个项目。
结果:可视化前后
下面列出了来源。
资源:
Python 中的图像处理
常用图像处理技术逐步指南
来自的照片
在这篇文章中,我将向你展示如何使用 Python 编辑图像。编辑图像的过程称为图像处理。您可能想知道为什么在项目中使用图像之前需要对它们进行一些润色。这有许多原因,但几个主要原因可以列为节省存储空间、提高培训质量和更快的运行时间。这篇文章中涉及的操作技术包括图像大小调整、图像亮度,以及最后将图像颜色转换成灰度。我们将通过测试每一张图片来进行一些实际操作。
图像大小调整
对于一个图像来说,这没有太大的区别,但是当你考虑在你的程序中处理成千上万的图像时,很小的尺寸变化将会节省你大量的时间和存储空间。
图像亮度
当我们看一幅图像时,很容易理解我们看到的东西,但对于机器来说,这可能有点挑战性。因此,为了帮助机器更好地处理图像,一点亮度可以帮助提高精确度。
图像灰度
当训练机器时,灰度图像做得更好。原因是因为机器将图像视为阵列的矩阵,所以存储黑白图像比存储多幅彩色图像更容易。
这些只是我们将在本帖中介绍的一些图像处理技术。还有很多,但如前所述,这些是最常用的技术,可以应用于任何格式的图像。如果你准备好了,我们开始吧!
图像
在我们开始编码之前,让我们选择一个图像来测试我们的代码。这张图片可以是任何格式,但我建议使用“png”或“jpg”。这是我选择玩的图像。这张图片的好处是没有使用滤镜和特效。
包装
我们总共只用一个包。我们将用于图像操作的主要库称为 PIL,它是图像处理库。PIL 将被安装为“枕头”,不要混淆,他们是一回事。
让我们从安装包开始吧。
pip install pillow
是时候将包作为库导入了,这样我们就可以使用它们了。
from PIL import Image, ImageEnhance
导入图像
我已经将我的图像重命名为“testme.jpg”,在这一步中,我通过将它分配给一个名为“img”的变量名来导入图像。我们将做最常用的三种手法。为了使事情变得简单明了,我将为每种技术使用相同的图像,但是可以随意为每种操作技术定义不同的图像。
img = Image.open("testme.jpg")
技巧 1 —调整大小
我们将对这张图片做的第一件事是调整它的大小。使用 PIL 库调整大小是非常容易的,这是一个图像处理库,如前所述。调整图像大小后,我想保存它,以便我们运行程序后可以看到图像。而最后要把图像保存为图像文件,我们就要用’保存’的方法。
在我们调整大小之前,您可以通过下面的代码打印图像的当前大小。
print(img.size)
调整图像大小:
newsize = (300, 300)
img_resized = img.resize(newsize) print(img_resized.size)
现在,我们可以将图像文件保存在我们的文件夹中。
img_resized.save("resized.jpg")
结果
resized.jpg
技术 2 —亮度
其次,让我们给我们的形象增加一些光亮。尤其是有阴影的图像,增加亮度有助于机器更好地看到图像中的线条。这在训练机器时非常重要,因为机器接受事物的本来面目,很少的错误信息都会导致错误的训练。不管怎样,下面是增加一些亮度的代码:
# Define enhancer
enhancer = ImageEnhance.Brightness(img) img_light = enhancer.enhance(1.8) img_light.save("brightened.jpg")
结果
Brightened.jpg
对于光线太强的图像,我们能做些什么吗?当然,和加光一样,也有一种方法可以让一些光出来。这将有助于在晴天拍摄的图像。要做到这一点非常容易,我们只需改变括号之间的值。如果数量大于 1,增强器将增加光线。如果该值介于 0 和 1 之间,增强器会发出一些光,这将使图像变得更暗。
值越小,颜色越深。你可以玩这个值,并观察它的行为。
enhancer = ImageEnhance.Brightness(img)
img_light = enhancer.enhance(0.8) img_light.save("darkened.jpg")
结果
darkened.jpg
技术 3 —灰度
作为我们的第三种图像处理技术,我们将看到如何将图像转换成灰度。换句话说,我们可以说非黑即白。存储灰度图像比存储多种颜色的图像更有效,机器也更容易理解。特别是,当训练机器学习图像中的特定对象时,灰度是最常用的技术之一。
img = Image.open('testme.jpg')
img = img.convert('L') img.save('grayscaled.jpg')
结果
grayscaled.jpg
这些是一些最常用的图像处理技术。这些技巧将帮助你更快更容易地编辑图像。在这个练习中,我们只编辑了一个图像,但是也可以在一个循环中运行相同的代码,这样你就可以用几行代码编辑成千上万的图像。
我是贝希克·居文,我喜欢分享关于创造力、编程、动力和生活的故事。
你可能喜欢的计算机视觉项目
如何使用 OpenCV 库检测图像中的人脸
towardsdatascience.com](/simple-face-detection-in-python-1fcda0ea648e)
利用 OpenCV 的模板匹配进行图像匹配
现实世界问题的高效计算解决方案
来自 icons8.com 的图片
介绍
作为 VATBox 的一名数据科学家,我主要从事核心涉及构建机器学习模型的项目。这个项目的好处在于,它纯粹包括建立一个算法来解决给定的任务。定制解决方案的现实问题。
问题定义
手头的问题本质上是两个接近相同的图像之间的匹配(例如,变化可能是由于图像大小)。这里的目标是实时地这样做,因此我们需要算法相对较快。
在 VATBox,我们的世界是一个发票的世界。用户将包含发票图像的报告上传到我们的平台。一份报告包含两组图像,一组是单独发票的集合,另一组是所有发票的集合。由于某些原因,我们不会深入探讨,一个组中的图像可能不会出现在另一个组中。目标是检测没有出现在另一组中的图像(如果有的话)。如果我们在本质上是相同图像的所有图像之间进行匹配,我们也可以识别备用图像。
我们想要检测备用图像(在左边用红色标记,在右边用蓝色标记)
解决办法
因此,为了找到备用图像,我们需要在每两个图像之间进行比较(或者…?我们会谈到这一点…),一个图像来自第一组,另一个来自第二组。一旦完成,我们就可以在图像之间进行匹配,然后查看哪些图像没有匹配。我们可以构建一个包含这些比较的比较矩阵。
比较矩阵
在我的研究中,我遇到的大多数解决方案都是基于从图像中提取的特征来匹配图像,但对于我们的情况来说,这在计算上是昂贵的,因为我们对每对图像都感兴趣。因此,我们需要一种不同的方法。
如上所述,实际匹配的图像几乎完全相同。所以我们可以预期它们的像素值相对相似。那么我们是否可以计算两个给定信号之间的相关性?但是如何用图像有效地做到这一点呢?
OpenCV 有一个模板匹配模块。这个模块的目的是在一个(更大的)图像中找到一个给定的模板。该模块使我们能够在图像(I)上“滑动”模板(T)并有效地执行计算(类似于在 CNN 中卷积核如何在图像上滑动)。
照片来自pexels.com
这对我们的需求很有帮助!我们可以使用它来有效地将第一组中的图像滑动到另一组的图像上,因为 OpenCV 的实现是最佳的。当然,由于我们寻找的是两个匹配的图像(而不是另一个图像中的模板),所以滑动只进行一次。
模板匹配模块包括计算相关性的不同方法,其中一种是归一化计算,返回值介于 0(无相似性)到 1(完全相同的图像)之间:
corr = cv2.matchTemplate(group1_image, group2_image,
cv2.TM_CCOEFF_NORMED)[0][0]
索引显示我们正在访问一个矩阵。如前所述,我们本质上是执行一次滑动,因此我们只是从具有单个元素的矩阵中获取单个值。
关于计算的一句话。在实际的相关性计算之前,图像被归一化,产生具有负值和正值的矩阵(或张量)。当执行相关性计算时,相似的区域将在相关性计算中获得正值,而不同的区域将获得负值(导致较低的相关性)。
复杂性
因为我们正在比较每一对图像,所以算法的复杂度是 O(n*m),n 是第一组中图像的数量,m 是第二组中图像的数量。能不能让算法更高效?
由于上面的函数为相似的图像返回接近 1 的值,我们可以设置一个阈值(例如 0.9),如果找到一个匹配,就不需要继续搜索。此外,如果找到匹配,我们将从搜索中删除匹配的图像。例如,如果在第一次迭代中,我们将第一组中的一幅图像与第二组中的 4 幅图像进行比较,那么在第二次迭代中,我们将只与 3 幅图像进行比较,依此类推。
摘要
在本文中,我们回顾了一个有点不同寻常的现实世界的数据科学问题,它需要一个定制的解决方案。我们深入研究了 OpenCV 的模板匹配,了解了如何使用它来满足手头问题的需求。希望你喜欢它!
使用深度卷积自动编码器在 10 分钟内降低图像噪声
深度学习案例研究
借助时尚 MNIST |使用 TensorFlow 的无监督深度学习,使用自动编码器清理(或去噪)有噪声的图像
如果你正在阅读这篇文章,我确信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过 Linkedin 来连线吧!请不要犹豫发送联系请求!Orhan g . yaln—Linkedin
图一。一只贪玩的狗的图像降噪前后(由 Anna Dudkova 在 Unsplash 上拍摄)
如果你在这个页面上,你也可能对不同的神经网络架构有些熟悉。你可能听说过前馈神经网络,CNN,RNNs,这些神经网络非常适合解决监督学习任务,如回归和分类。
但是,在无监督学习领域,我们有大量的问题,例如降维、特征提取、异常检测、数据生成、增强以及降噪。对于这些任务,我们需要专门为无监督学习任务开发的特殊神经网络的帮助。因此,他们必须能够在不需要监督的情况下解数学方程。这些特殊的神经网络架构之一是自动编码器。
获取最新的机器学习教程
自动编码器
什么是自动编码器?
自动编码器是由两个子网络组成的神经网络架构,即编码器和解码器网络,它们通过潜在空间相互联系。自动编码器最初是由人工智能界最受尊敬的科学家之一 Geoffrey Hinton 和 PDP 小组在 20 世纪 80 年代开发的。Hinton 和 PDP 小组旨在通过将输入作为教师来解决“无教师反向传播”问题,也称为无监督学习。换句话说,他们只是将特征数据用作特征数据和标签数据。让我们仔细看看自动编码器是如何工作的!
图二。具有编码器和解码器网络的自动编码器网络
自动编码器架构
自动编码器由一个编码器网络组成,它获取特征数据并对其进行编码以适应潜在空间。该编码数据(即代码)被解码器用来转换回特征数据。在编码器中,模型学习的是如何有效地编码数据,以便解码器可以将其转换回原始数据。因此,自动编码器训练的基本部分是生成优化的潜在空间。
现在,我们知道,在大多数情况下,潜在空间中的神经元数量比输入和输出层要少得多,但也不一定是这样。有不同类型的自动编码器,如欠完整、过完整、稀疏、去噪、收缩和变化自动编码器。在本教程中,我们只关注用于去噪的欠完整自动编码器。
自动编码器中的图层
构建自动编码器时的标准做法是设计一个编码器,并创建该网络的反向版本作为该自动编码器的解码器。因此,只要编码器和解码器网络之间存在反向关系,您就可以自由地向这些子网添加任何层。例如,如果您正在处理图像数据,您肯定会需要卷积和池层。另一方面,如果您正在处理序列数据,您可能需要 LSTM、GRU 或 RNN 单位。这里重要的一点是,你可以自由地建造任何你想要的东西。
图 3。欠完整自动编码器中的潜在空间通常比其他层窄
现在,您已经有了可以为图像降噪构建自动编码器的想法,我们可以继续学习教程,并开始为我们的图像降噪模型编写代码。对于本教程,我们选择做我们自己对 TensorFlow 的官方教程之一,自动编码器简介,我们将使用人工智能社区成员中非常受欢迎的数据集: 时尚 MNIST 。
下载时尚 MNIST 数据集
时尚 MNIST 由位于德国柏林的欧洲电子商务公司 Zalando 设计和维护。时尚 MNIST 由 60,000 幅图像的训练集和 10,000 幅图像的测试集组成。每个示例都是 28×28 灰度图像,与来自 10 个类别的标签相关联。“时尚 MNIST”包含服装商品的图像(如图 4 所示),它被设计为包含手写数字的 MNIST 数据集的替代数据集。我们选择时尚 MNIST 仅仅是因为 MNIST 已经在许多教程中被过度使用。
下面几行导入 TensorFlow 和 load Fashion MNIST:
现在,让我们用数据集的样本生成一个网格,代码如下:
我们的输出显示了测试数据集中的前 50 个样本:
图 4。显示时尚 MNIST 测试数据集中前 50 个样本的 5x10 网格
处理时尚 MNIST 数据
为了计算效率和模型可靠性,我们必须对我们的图像数据应用最小最大归一化,将值范围限制在 0 和 1 之间。由于我们的数据是 RGB 格式的,最小值是 0,最大值是 255,我们可以用下面几行进行最小最大规范化操作:
我们还必须调整 NumPy 数组的形状,因为数据集的当前形状是(60000,28,28)和(10000,28,28)。我们只需要添加一个具有单一值的第四维(例如,从(60000,28,28)到(60000,28,28,1))。第四维几乎可以证明我们的数据是灰度格式的,用一个值表示从白色到黑色的颜色信息。如果我们有彩色图像,那么我们就需要第四维中的三个值。但是我们所需要的是包含单一值的第四维,因为我们使用灰度图像。以下代码行可以做到这一点:
让我们用下面几行来看看 NumPy 数组的形状:
输出: (60000,28,28,1)和(10000,28,28,1)
向图像添加噪声
请记住,我们的目标是建立一个能够对图像进行降噪的模型。为了做到这一点,我们将使用现有的图像数据,并将它们添加到随机噪声中。然后,我们将原始图像作为输入,含噪图像作为输出。我们的自动编码器将学习干净的图像和有噪声的图像之间的关系,以及如何清洁有噪声的图像。因此,让我们创建一个噪声版本的时尚 MNIST 数据集。
对于此任务,我们使用 tf.random.normal 方法向每个数组项添加一个随机生成的值。然后,我们将这个随机值乘以一个 noise_factor,你可以随意使用它。以下代码向图像添加了噪声:
我们还需要确保数组项的值在 0 到 1 的范围内。为此,我们可以使用 tf.clip_by_value 方法。 clip_by_value 是一种张量流方法,它剪切最小-最大范围之外的值,并用指定的最小或最大值替换它们。以下代码将值截取到范围之外:
现在我们已经创建了数据集的正则化和噪声版本,我们可以检查它的外观:
图 5。显示清晰和嘈杂图像样本的 2x5 网格
正如你所看到的,几乎不可能理解我们在嘈杂的图像中看到的东西。然而,我们的自动编码器会神奇地学会清理它。
构建我们的模型
在 TensorFlow 中,除了顺序 API 和函数 API 之外,还有第三种构建模型的选择:模型子类化。在模型子类化中,我们可以自由地从头开始实现任何东西。模型子类化是完全可定制的,使我们能够实现我们自己的定制模型。这是一个非常强大的方法,因为我们可以建立任何类型的模型。但是,它需要基本的面向对象编程知识。我们的自定义类将继承 tf.keras.Model 对象。它还需要声明几个变量和函数。不过,这没什么可怕的。
另请注意,由于我们处理的是图像数据,因此构建卷积自动编码器会更有效,如下所示:
图 6。卷积自动编码器示例
要构建模型,我们只需完成以下任务:
- 创建一个扩展 keras 的类。模型对象
- 创建一个 init 函数来声明用顺序 API 构建的两个独立的模型。在它们内部,我们需要声明可以相互反转的层。一个 Conv2D 层用于编码器模型,而一个 conv 2d 转置层用于解码器模型。
- 创建一个调用函数,告诉模型如何通过 init 方法使用初始化的变量处理输入:
- 我们需要调用初始化的编码器模型,该模型将图像作为输入
- 我们还需要调用初始化的解码器模型,该模型将编码器模型(已编码)的输出作为输入
- 返回解码器的输出
我们可以用下面的代码实现所有这些:
让我们用一个对象调用来创建模型:
配置我们的模型
对于这项任务,我们将使用 Adam 优化器和模型的均方误差。我们可以很容易地使用编译功能来配置我们的自动编码器,如下所示:
最后,我们可以通过输入有噪声和干净的图像来运行我们的模型 10 个时期,这将需要大约 1 分钟来训练。我们还使用测试数据集进行验证。以下代码用于训练模型:
图 7。深度卷积自动编码器训练性能
使用我们训练有素的自动编码器降低图像噪音
既然我们已经训练了我们的自动编码器,我们可以开始清理噪声图像。注意,我们可以访问编码器和解码器网络,因为我们是在 NoiseReducer 对象下定义它们的。
因此,首先,我们将使用一个编码器来编码我们的噪声测试数据集(x _ test _ noisy)。然后,我们将把编码器的编码输出送入解码器,以获得干净的图像。以下代码行完成这些任务:
让我们绘制前 10 个样本,进行并列比较:
第一行是有噪声的图像,第二行是干净的(重建的)图像,最后,第三行是原始图像。查看清理后的图像与原始图像有何相似之处:
图 5。一个 3x10 的网格,显示干净和有噪声的图像样本以及它们的重建副本
恭喜
你已经建立了一个 autoencoder 模型,它可以成功地清理非常嘈杂的图像,这是它以前从未见过的(我们使用了测试数据集)。显然有一些未恢复的失真,例如右边第二个图像中缺失的拖鞋底部。然而,如果你考虑噪声图像的变形程度,我们可以说我们的模型在恢复失真图像方面相当成功。
在我的脑海中,你可以-例如-考虑扩展这个自动编码器,并将其嵌入到照片增强应用程序中,这可以增加照片的清晰度和清晰度。
订阅邮件列表获取完整代码
如果你想访问 Google Colab 的全部代码,并访问我的最新内容,请订阅邮件列表:
喜欢这篇文章
如果你喜欢这篇文章,可以考虑看看我的其他类似文章:
[## 使用 MNIST 数据集在 10 分钟内完成图像分类
towardsdatascience.com](/image-classification-in-10-minutes-with-mnist-dataset-54c35b77a38d) [## 利用生成性对抗网络在 10 分钟内生成图像
使用无监督深度学习生成手写数字与深度卷积甘斯使用张量流和…
towardsdatascience.com](/image-generation-in-10-minutes-with-generative-adversarial-networks-c2afc56bfa3b) [## 伯特和拥抱脸 10 分钟情感分析
学习预训练的自然语言处理模型的基础,伯特,并建立一个使用 IMDB 电影评论的情感分类器…
towardsdatascience.com](/sentiment-analysis-in-10-minutes-with-bert-and-hugging-face-294e8a04b671) [## TensorFlow 和 VGG19 可以帮助您将照片转换成美丽的波普艺术作品
神经风格转移基于安迪沃霍尔的门罗双联画与预训练的计算机视觉网络 VGG19,转移…
towardsdatascience.com](/tensorflow-and-vgg19-can-help-you-convert-your-photos-into-beautiful-pop-art-pieces-c1abe87e7e01)
计算机视觉的图像处理和数据增强技术
图像处理是计算机视觉的一个组成部分。我们几乎总是想要调整图像的大小,增加数据,查看网格中的图像,等等。 OpenCV (开源计算机视觉)、 scikit-image 、 Pillow 是 Python 中比较流行的一些图像处理库。在本文中,我介绍了一些最常用的图像处理技术。
这是我在这篇文章中使用的 Jupyter 笔记本:https://jovian.ml/aakanksha-ns/image-processing
1)读取图像
图像表示为由像素值组成的数组。8 位图像的像素值范围从 0(黑色)到 255(白色)。根据色阶的不同,图像中有不同的通道,每个通道代表一种特定颜色的像素值。RGB(红、绿、蓝)是最常用的色标,我在示例中使用的所有图像都是 RGB 图像。
我们可以使用 OpenCV 中的imread
函数轻松读取图像数组。这里需要记住的一点是,OpenCV 默认按照 BGR 顺序读取图像。
2)裁剪
裁剪是一种广泛使用的增强技术。然而,注意不要裁剪图像的重要部分(非常明显,但是当你有太多不同大小的图像时容易被忽略)。因为图像是用数组表示的,所以裁剪相当于从数组中取出一个切片:
中心裁剪:
随机裁剪:
3)调整大小
大多数深度学习模型架构期望所有输入图像都具有相同的维度。
4)翻转图像
这是另一种非常流行的图像增强技术。这里唯一要记住的是,翻转应该对您的用例有意义。例如,如果您正在对建筑类型进行分类,您不会在测试集中遇到任何倒置的建筑,因此在这种情况下进行垂直翻转是没有意义的。
垂直翻转:
水平翻转:
5)旋转图像:
在大多数情况下,可以将图像旋转一个小角度。在某些情况下,这种天真的做法可能会改变图像的整个方向,就像这样:
因此,更好的旋转方式是使用 OpenCV 进行仿射变换。仿射变换保留了共线性和距离比(例如:即使在变换后,线段的中点仍然是中点)。您也可以使用BORDER_REFLECT
标志来填充边框。
6)更改亮度和对比度:
这包括对每个像素应用以下函数:
这里α(> 0)称为增益,β称为偏置,这些参数据说分别控制对比度和亮度。因为我们使用数组表示图像,所以可以通过遍历数组将该函数应用于每个像素:
然而,对于较大的图像(如下图所示),这可能需要一段时间,因此您需要使用优化的库函数:
增加对比度
增加亮度
7)显示包围盒:
目标检测是一个非常流行的计算机视觉问题,涉及到寻找包围感兴趣的目标的包围盒。在图片上显示包围盒可以帮助我们直观地检查问题和需求。在处理这些问题时要记住的一件事是,如果你打算翻转图像,确保你也相应地翻转了框坐标。这里有一个简单的方法来显示图像及其边界框。
8)在网格中显示多个图像:
我们通常希望一次检查多幅图像。使用 matplotlib 中的子情节可以很容易地做到这一点。
9)将图像转换为黑白图像:
虽然没有在计算机视觉中广泛使用,但知道如何将彩色图像转换为灰度图像还是很不错的。
10)模糊:
这项技术有助于使您的模型对图像质量问题更加稳健。如果一个模型可以在模糊的图像上表现良好,这可能表明该模型总体上表现良好。
当然,还有很多针对特定问题的图像处理技术。例如,对于自动驾驶汽车,您可能想要标记道路上的其他汽车,并从各种角度查看它。但是,对于大多数问题,上述函数应该是有用的!
使用 Streamlit 进行图像处理
使用 OpenCV 了解 Streamlit
作者图片
在本文中,我们将了解如何将 Streamlit 与图像处理技术和对象检测算法结合使用。我假设您已经在系统上安装并运行了 Streamlit。如果你不知道如何从 streamlit 开始,那么你可以参考我的以前的文章,在那里我简单地解释了一下。
我还在 streamlit 共享上部署了这个 Streamlit 应用程序。在进一步阅读这篇文章之前,你可以先看一下。
以下是链接:使用 Streamlit 的图像处理
现在让我们深入研究代码。
首先导入必要的库
import streamlit as st
from PIL import Image
import cv2
import numpy as np
我已经创建了 main 函数,这是代码的起点。在这个函数中,你会看到一个我创建的侧边栏。Streamlit 为您提供了边栏选择框功能,可以轻松创建一个。在侧边栏中,我添加了一些值,每个值都与一个函数相关联。当用户点击它们中的任何一个时,相应的功能被触发。默认情况下,选择第一个值,即 welcome 字符串,if 语句调用 Welcome()函数。
def main():selected_box = st.sidebar.selectbox(
'Choose one of the following',
('Welcome','Image Processing', 'Video', 'Face Detection', 'Feature Detection', 'Object Detection')
)
if selected_box == 'Welcome':
welcome()
if selected_box == 'Image Processing':
photo()
if selected_box == 'Video':
video()
if selected_box == 'Face Detection':
face_detection()
if selected_box == 'Feature Detection':
feature_detection()
if selected_box == 'Object Detection':
object_detection()if __name__ == "__main__":
main()
作者图片
下图显示了欢迎页面。让我们看看欢迎函数。
作者图片
def welcome():
st.title('Image Processing using Streamlit')
st.subheader('A simple app that shows different image processing algorithms. You can choose the options'
+ ' from the left. I have implemented only a few to show how it works on Streamlit. ' +
'You are free to add stuff to this app.')
st.image('hackershrine.jpg',use_column_width=True)
用 st.title 你可以创建一个粗体标题,用 st.subheader 你可以有一个较低字体大小的粗体。使用 st.image,您可以在 streamlit 应用程序上显示任何图像。请确保将列宽设置为 true,以使其合适。
接下来,我们在侧边栏中有图像处理部分。在这里,我们将看到阈值,边缘检测和轮廓。为了方便用户,我使用了一个滑块来改变阈值。要制作一个交互式滑块,只需在 streamlit 中编写 st.slider。在 OpenCV 的帮助下,我们正在进行 RGB 到灰度的转换,然后使用 OpenCV 中的阈值函数。我们在阈值函数中传递滑块的值。所以当我们移动滑块时,值会改变并存储在 thresh1 中。然后我们使用 st.image 来显示 thresh1 图像。确保将 clamp 设置为 True。
接下来,我们有一个显示该图像的条形图。您可以使用 streamlit 中的条形图功能来完成此操作。传递的值是用 cv2.calchist 函数计算的。您可以使用不同的直方图和图来分析您的图像。
然后,我们有精明的边缘检测技术。我做了一个按钮,当用户点击它时,它运行算法并显示输出。您可以简单地通过编写 st.button 和 if 语句来创建一个按钮。如果你写了边缘检测代码。
对于轮廓,我再次使用滑块来改变图像,使轮廓发生变化。在 OpenCV 中,您可以在传递图像的地方找到轮廓和绘制轮廓。
def photo():st.header("Thresholding, Edge Detection and Contours")
if st.button('See Original Image of Tom'):
original = Image.open('tom.jpg')
st.image(original, use_column_width=True)
image = cv2.imread('tom.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
x = st.slider('Change Threshold value',min_value = 50,max_value = 255)ret,thresh1 = cv2.threshold(image,x,255,cv2.THRESH_BINARY)
thresh1 = thresh1.astype(np.float64)
st.image(thresh1, use_column_width=True,clamp = True)
st.text("Bar Chart of the image")
histr = cv2.calcHist([image],[0],None,[256],[0,256])
st.bar_chart(histr)
st.text("Press the button below to view Canny Edge Detection Technique")
if st.button('Canny Edge Detector'):
image = load_image("jerry.jpg")
edges = cv2.Canny(image,50,300)
cv2.imwrite('edges.jpg',edges)
st.image(edges,use_column_width=True,clamp=True)
y = st.slider('Change Value to increase or decrease contours',min_value = 50,max_value = 255)
if st.button('Contours'):
im = load_image("jerry1.jpg")
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,y,255,0)
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(im, contours, -1, (0,255,0), 3)
st.image(thresh, use_column_width=True, clamp = True)
st.image(img, use_column_width=True, clamp = True)
我们接下来要看的是人脸检测。对于人脸检测,我使用的是哈尔级联文件。使用 cascadeClassifier,我们将加载 XML 文件。我们有 detectMultiScale 函数,我们传递图像来寻找图像中的人脸。如果我们找到图像,然后在脸部周围画一个矩形。如果您希望保存图像,那么您可以使用写入功能。然后,我们使用 Streamlit 使用 st.image 显示图像。
def face_detection():
st.header("Face Detection using haarcascade")
if st.button('See Original Image'):
original = Image.open('friends.jpeg')
st.image(original, use_column_width=True)
image2 = cv2.imread("friends.jpeg")face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
faces = face_cascade.detectMultiScale(image2)
print(f"{len(faces)} faces detected in the image.")
for x, y, width, height in faces:
cv2.rectangle(image2, (x, y), (x + width, y + height), color=(255, 0, 0), thickness=2)
cv2.imwrite("faces.jpg", image2)
st.image(image2, use_column_width=True,clamp = True)
我想展示的最后一部分是对象检测。我已经使用挂钟和眼哈尔级联文件做对象检测。与人脸检测类似,我们将加载 XML 文件并使用检测多尺度函数。如果找到了相应的对象,我们将在该对象周围绘制一个矩形。下图显示了输出。
def object_detection():
st.header('Object Detection')
st.subheader("Object Detection is done using different haarcascade files.")
img = load_image("clock.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
clock = cv2.CascadeClassifier('haarcascade_wallclock.xml')
found = clock.detectMultiScale(img_gray,
minSize =(20, 20))
amount_found = len(found)
st.text("Detecting a clock from an image")
if amount_found != 0:
for (x, y, width, height) in found:
cv2.rectangle(img_rgb, (x, y),
(x + height, y + width),
(0, 255, 0), 5)
st.image(img_rgb, use_column_width=True,clamp = True)
st.text("Detecting eyes from an image")
image = load_image("eyes.jpg")
img_gray_ = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
img_rgb_ = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
eye = cv2.CascadeClassifier('haarcascade_eye.xml')
found = eye.detectMultiScale(img_gray_,
minSize =(20, 20))
amount_found_ = len(found)
if amount_found_ != 0:
for (x, y, width, height) in found:
cv2.rectangle(img_rgb_, (x, y),
(x + height, y + width),
(0, 255, 0), 5)
st.image(img_rgb_, use_column_width=True,clamp = True)
检测挂钟|作者图片
检测眼睛|作者图片
你可以在我的 Github 上找到代码。我还为此制作了一个视频。
关于图像处理和机器学习的进一步阅读,可以参考这篇资料丰富的文章。
https://Neptune . ai/blog/what-image-processing-techniques-is-actual-used-in-the-ml-industry
和平!