可以说,计算机视觉技术是人工智能技术的核心方向,特别是深度学习技术在计算机视觉中的应用,在最近五六年的人工智能浪潮中担当了先锋者的角色。甚至可以说,如果没有深度学习技术在过去几年对计算机视觉一些核心领域的推动和促进,就很可能没有这一波的人工智能技术浪潮。
我们可以这么来看待人工智能技术,它可以说是利用计算机技术来对人的感官,例如视觉、听觉、触觉以及思维进行模拟,从而建立起逻辑推断等智能才具备的能力。其中,计算机视觉技术无疑是至关重要的,也是非常困难的。
今天我会带你先来看看究竟什么是计算机视觉,以及这个方向的研发都需要解决哪些核心问题。
关于计算机视觉(Computer Vision,CV),有两种人们普遍接受的定义。
第一种定义认为,计算机视觉是从数字图像(Digital Images)中提取信息。这些信息可以是图像中的物品识别(Identification)、导航系统的位置测量(Space Measurement)以及增强现实(Augmented Reality)的应用。
计算机视觉的第二种定义主要是从应用的角度出发,认为计算机视觉是为了构建可以理解数字图像内容的算法,从而有多种应用。
那到底什么是计算机视觉呢?主要解决哪些问题?我们可以拿人类视觉的主要功能来做类比,就比较容易理解了。
当人类面对一个现实中的场景时,我们有一个感官器官来收集信号,那就是“眼睛”。眼睛收集的原始信号转换为人可以处理的信息之后,这些信息就来到了“大脑”这一个人类信息处理中心,进行分析和处理。
这个过程中最主要的一个处理模块,就是对信号产生“语义”(Semantic)解释或者进行逻辑上的理解。比如,当我们看到一个公园的一角以后,需要识别这个场景里的桥梁、水、树等物体,并且在头脑中形成这些物体的概念。可以说,这就是人类视觉系统的一个简单的框架,眼睛收集信息,大脑处理信息。
那么,在整体的框架上,计算机视觉其实就是希望模仿人类的视觉系统构架。输入依然是一个现实中的场景,但是我们需要借助其他的感知仪器(Sensing Device)来从中获取原始信息。最常见的感知仪器包括照相机、摄像机以及现在广泛普及的手机摄像头。从这些感知仪器中获取了最初级的信息之后,计算机视觉的“大脑”就是计算机。这里的“计算机”其实是指计算机算法,通过算法理解原始数据,构建语义信息。
这么理解起来,计算机视觉技术好像挺简单的。就像 1966 年,麻省理工大学的一个本科生想做这样一个暑期项目,并且认为这个项目可以在一个暑假里解决。这或许就是计算机视觉的一个起源了。但是,令人感慨的是,计算机视觉绝不是可以在一个假期内解决的项目,整整半个多世纪已经过去了,计算机视觉依然有很多值得挑战的课题,也依然还在高速发展中。
了解了计算机视觉的定义之后,我们来进一步聊一聊这个领域的一些特点。
首先,计算机视觉是一个“跨学科领域”。正如刚才所说,对人类视觉的研究给计算机视觉带来了重要的启发。那这里就涉及到生物领域的研究,包括对人的眼睛以及视觉神经的研究。一方面,我们需要感知器来从现实世界中获取信息。那么,对于感知仪器来说,设备越是精确,就越能完整地捕捉外界世界的信息。这里就涉及到物理,特别是光学的研究。另一方面,人脑是处理所有信号并且形成语义概念的器官,理解人脑的信息处理机制就会对计算机视觉的发展有重要的作用,这就涉及到脑科学和认知科学等领域。
除此以外,计算机视觉毕竟是一个和计算机结合得很紧密的学科方向。因此,要想设计高效的计算机视觉算法,就必须和计算机科学的很多其他方向结合并借鉴,例如信息检索、计算机体系结构、机器学习等。
计算机视觉的另外一个特点,就是这个领域包含了很多非常深刻的困难问题。我们说,从计算机视觉被当作一个暑假项目到现在,五十多年已经过去了,这个领域依然在蓬勃发展着。时至今日,我们依然不能说计算机视觉是一个已经被完全解决的问题。
那计算机视觉任务“难”在哪里呢?我认为根本原因在于计算机视觉算法处理的输入,也就是数字化了的图像信息和我们需要理解的语义信息之间存在巨大的鸿沟。举例来说,一个 200 乘以 200 的 RGB 图像其实就是一个由 12 万个数字组成的矩阵,但是这个矩阵可能代表一个非常复杂的图像。从数字到具体的图像中的物体,再到去理解这个图像的语义,这中间有很长的距离。
一直以来,计算机视觉也在尝试去构造和逼近一些人类视觉系统的特点,但是困难重重。比如,人类视觉系统的反应很快。有实验表明,从一幅普通场景的图像中,人类只需要 150 毫秒就能够识别出里面的物体。另外,人类视觉系统的复杂性还来自于对世界认知的理解。例如,人可以依靠过去的记忆或者经验,还可以依靠其他外界知识,来对图像中的物体进行判断。这些都是计算机视觉系统难以企及的。
当然,在经历了半个世纪的研究之后,也有不少学者提出怀疑的观点,计算机视觉研究是否要对人类视觉系统进行完全的模仿呢?一种观点是,计算机视觉系统并不需要亦步亦趋地完全照搬人类视觉系统,这可能也并不是一条切实有效的道路。有一种观点认为,计算机视觉系统可以从人类视觉或者其他领域得到灵感,但是究竟应该如何搭建一个有效的系统,还是需要开辟新的研究道路。
计算机视觉技术的领用非常广泛,可以说是深入到了普通人生活的方方面面。在这些应用中,除了我们日常比较容易接触到的,例如面部识别、光学字符识别(OCR)、电影特效、视觉搜索以外,还包括最近几年飞速兴起的自动驾驶、自动无人商店、虚拟现实、增强现实等等。
可以说计算机视觉的应用任务领域众多。近几年都受到深度学习的影响,绝大多数领域都得到了高速发展,但是依然需要领域知识来构建更加有效的模型。
我们在上一次的分享中谈到了计算机视觉任务中一个非常重要的步骤,那就是把现实世界的信号通过感知仪器(Sensing Device)收集起来,然后在计算机系统中加以表达。那么,在所有的表达中,最基础的就是“像素表达”(Pixel)。我们这里就展开说一说这种表达的思路。
把图像信息利用像素来进行表达是一种非常直观简单的表达方式。
对于黑白图像来说,图像就被转换为了 0 或者 1 的二元矩阵。这个矩阵的每一个元素就是一个像素,0 代表黑,1 则代表白。
对于灰度图像来说,每一个像素,或者说是矩阵的每一个元素,代表灰度的“强度”(Intensity),从 0 到 255,0 代表黑,255 代表白。
对于彩色的图像来说,我们一般要先选择一种模型来表示不同的颜色。一种较为流行的表达方式是 RGB(红、绿、蓝)模型。在这样的模型中,任何一个彩色图像都能够转化成为 RGB 这三种颜色表达的叠加。具体来说,就是 RGB 分别代表三种不同的“通道”(Channel)。每一种通道都是原始图像在这个通道,也就是这个原始颜色下的表达。每一个通道都是一个矩阵像素表达。每一个像素代表着从 0 到 255 的值。换句话说,一个彩色图像在 RGB 模型下,是一个“张量”(Tensor),也就是三个矩阵叠加在一起的结果。
针对像素,你需要建立一种概念,那就是像素本身是对真实世界中的“采样”(Sample)。每一个像素是一个整数,整个像素表达并不是一个“连续”(Continuous)表达。因此,在把世界上的连续信号采样到离散像素的这一过程中,难免会有失真。而不同的“分辨率”,会带来失真程度不同的像素表达。
既然已经把图像表达成为了像素,也就是某种矩阵的形式,那么我们就可以利用线性代数等工具在这个矩阵上进行变换,从而能够对图像进行某种操作。这就是“过滤器”(Filter)的一个基本思想。
很多计算机视觉的操作本质上都是过滤器操作。除了把过滤器想成某种线性代数变换之外,更普遍的一种思路是把在矩阵上的操作想成某种函数的操作。因此,我们也可以认为过滤器是函数在某一个特定区间内的操作。
举一个最简单的过滤器的例子,就是“移动平均”(Moving Average)。这个过滤器的本质就是针对每一个像素点,计算它周围 9 个像素点的平均值。如果我们针对每一个像素进行这样的操作,就会得到一个新的矩阵。然后我们把这个矩阵当作新的像素表达进行视觉化,就会发现是在原有图像基础上进行了“柔化”处理。反过来,如果我们需要对某一个图像进行柔化处理,就需要对其进行“移动平均”过滤操作。
有了这个直观的例子,你一定能够想到,很多我们熟知的图像特效处理,其实都对应着某种过滤器操作。
这里,我们提及一种比较特殊的过滤处理,那就是“卷积”(Convolution)。这个概念我们在深度学习中经常接触到。
刚才我们说到“移动平均”这个过滤器。如果我们把图像看作是一个函数 F 在某一个区域的取值,那么,“移动平均”这个过滤器是针对函数在某一点的取值(也就是某一个像素的取值),通过利用同样的函数 F 在周围的取值,从而得到一个新的计算值。
那卷积操作的思想是怎样的呢?卷积是针对 F 在某一个点的取值,除了需要利用 F 在周围的点以外,还需要利用另外一个函数,这里称作是 H 的取值。也就是说,我们要利用 H 来针对 F 进行操作。
除了通过过滤器对图像进行简单操作之外,还有一些图像的基本操作蕴含了计算机视觉的基本原理。我们这里也稍微做一些介绍。
例如我们通常需要了解图像的边界。有研究表明,图像的边界对于人类认知图像的内涵有着特殊的意义。因此从一个完整的图像中找到不同物体的边界是一个很有现实意义的任务,并且通常被称作是“边界探测”(Edge Detection)。
那么,怎么来认识图像中的物体边界呢?我们先从直观上来想一想,在图像中,“边界”都有什么特征?一般来说,如果我们遇到了色彩、景深、照明的突然变化,或者是其他某种图像特质上的突然变化,我们就有可能遇到了边界。现在的问题是,在像素或者函数表达的情况下,如何来描述和检测这些“突然变化”?
在数学分析中我们学过,描述函数值变化的概念叫“导数”或者“梯度”(Gradient)。梯度大小(Gradient Magnitude)和梯度方向(Gradient Direction)都包含了函数变化的重要信息。
虽然梯度从数学的角度来说刻画了函数的变化,但是这对于设计一个实际的边界探测器依然是不够的。一个好的边界探测器需要真正能够探测到边界,也就是要尽可能少地出现错误,能够对边界进行定位(Location)的同时还需要尽量使边界平滑和链接。
在真实的边界探测中,我们往往先让图像变得更加平滑,比如利用“高斯柔化”(Gaussian Blur)的办法,然后在这个基础上计算梯度大小和方向,有了这些之后再进行一些后期处理。
在深入讨论特征提取之前,我们先来了解一下特征提取的目的,或者说是研究特征提取的必要性。
从大的方面来说,计算机视觉的一部分任务是实现对图像的智能理解。那么,理解图像的语义就是其中一个非常重要的任务。
我们提到的边界检测或者是颜色检测,虽然都是理解图像的任务,但是这些任务并不理解图像中具体的物体,比如哪里是一只动物、哪里是行人等。那么,怎样才能理解图像中具体的物体呢?或者更进一步,整个图像表达了怎样的社会关系或者说是场景关系?例如一张会议室的图像,我们不仅关心里面的陈设和人物,还关心会议室的整体气氛,以及这样的气氛是不是传递出了更复杂的人物之间的社会关系。
那么,如何实现这种更高维度的语义理解呢?这往往需要我们对底层的一些图像先进行抽象,然后再在抽象出来的特征基础上,进一步来建模。
除了我们这里提到的对图像本身的理解以外,在很多任务中,我们还需要对图像和其他信息结合起来进行理解和分析。一种常见的形式是图像和一段文字结合起来,对某一个物品或者某一个事件进行描述。例如电商网站的商品信息,一般都有精美的图片和详细的介绍,这些信息组合起来完整地描述了整个商品的信息。
这个时候,我们就要同时理解图像和文字信息。很明显,在这样的任务中,一种比较容易想到的模式是先从图像和文字中分别抽取一定的抽象特征,有了高度概括的图像特征和文字特征之后,我们再在这个基础上进行建模。
从比较小的计算机视觉的任务来说,很多时候,一个任务会涉及到两个步骤:把任务抽象为提取特征,然后转换为一个普通的机器学习任务。这个流程的第二步可以是一个监督学习任务,例如回归或者分类;也可以是一个非监督学习任务。需要注意的是,我们这里提到的两个步骤,并不一定是绝对地把建模过程当作两个完全独立的步骤,而是从逻辑上对这两个步骤进行区分。事实上,在现代的深度学习架构中,这两个步骤往往都在统一的一个架构下进行训练,从而能够得到更好的效果。
今天,我们就从传统的计算机视觉的角度,来看看特征提取有哪些难点和经典方法。
图像数据的特征提取为什么有难度呢?原因在于图像信息本身的复杂性。
试想我们有两张人民大会堂的建筑物照片,一张是从地面拍摄的,一张是从空中拍摄的。虽然这两张照片可能在角度、色彩、位置等方面有很多的不同,但是因为这两张照片本身所描述的对象是一致的,都是人民大会堂,因此我们希望从这两个图片中提取的特征有一些相似性。也就是说,我们需要找到在诸多变化因素中不变的成分。
一个经典的思路是从局部信息(Local Information)入手,从图像中提取相应的特征。从实际的效果来看,局部特征(Local Feature)比全局特征更加稳固。
回到上面的例子,如何构造一个能够匹配两个图片的普遍的局部特征呢?过程如下:第一,找到一组关键的点或者是像素;第二,在关键点周围定义一个区域;第三,抽取并且归一化这个区域;第四,从归一化后的区域提取“局部描述子”(Local Descriptor)。得到局部描述子之后,我们就可以利用它来进行匹配了。
从上面这个流程来看,整体的思路其实就是希望从局部找到具有代表性的特征,然后把所有因为各种因素造成的特征变化归一化掉。
当然,这个简单的流程是有一些问题的。比如,如果我们针对两幅不同的图像分别进行上述的流程,那么很有可能最后得到的关键点和局部描述子都不一样。所以我们需要一种更具普适性的方法。
其实从 70 年代开始,就有一大部分的计算机视觉工作是在研究如何构建局部特征描述子。在这 30 多年的发展历程中,很多研究工作者提出了不少既有理论基础又有实用价值的特征提取方法。甚至是最近的深度学习热潮,从某种程度上来说也是一个重要的特征提取成果。
在这些研究成果中,比较有代表性的局部描述子包括 SIFT(Scale-invariant feature transform)描述子和 HOG(Histogram of oriented gradient)描述子。关于这两个描述子,我在这里不展开介绍它们的细节,因为在深度学习浪潮中,大部分利用描述子来对特征进行提取的方法都被淘汰了,但是这些方法的思路,我们在很多类似的工作中依然可以借鉴。