C语言解析人脸检测的Haar分类器方法:Haar特征、积分图、 AdaBoost 、级联

解析人脸检测的Haar分类器方法

同、Haar分类器的前生今生

      
人脸检测属于计算机视觉的局面,早期人们的重大研究方向是人脸识别,即基于人口脸来识别人物之位置,后来当千头万绪背景下之人脸检测需要进一步好,人脸检测也日趋作为一个独立的钻方向前行兴起。

       目前底人头脸检测方法主要发生三三两两良类:基于知识和冲统计。

Ø  因知识之法子:要使用先验知识将人脸看作器官特征的构成,根据眼睛、眉毛、嘴巴、鼻子等器官的性状及互动的几乎哪里位置关系来检测脸部。

Ø  基于统计的艺术:将人口脸看作一个完整的模式——二维像素矩阵,从统计的看法通过大气口脸图像样本构造人脸模式空间,根据相似量来判断人脸是否有。

基于知识之丁脸检测方法:

       模板匹配、人脸特征、形状和边缘、纹理特性、颜色特征

基于统计的人脸检测方法:

      
主成分分析及特征脸、神经网络方法、支持于量机、隐马尔可夫模型、Adaboost算法

      
本文中牵线的Haar分类器方法,包含了Adaboost算法,稍候会针对当时等同算法做详细介绍。所谓分类器,在这里就是凭对脸部和未人脸进行分拣的算法,在机器上园地,很多算法都是对事物进行分类、聚类的过程。OpenCV中之ml模块提供了不少分类、聚类的算法。

横流:聚类和分类的分是什么?

Ø  分类:诚如针对已经掌握物体类别总数的辨识术我们誉为分类,并且训练之数据是产生标签的,比如就显著指定了凡脸还是非人脸,这是一律种出监督上。

Ø  聚类:为设有好处理项目总数不确定的法子还是教练之数是未曾签的,这就是聚类,不需要上学等受到有关物体类别的音信,是同样种植无监控上。

      
其中包括Mahalanobis距离、K均值、朴素贝叶斯分类器、决策树、Boosting、随机森林、Haar分类器、期望最大化、K近邻、神经网络、支持于量机。

      
我们只要追究的Haar分类器实际上是Boosting算法的一个运用,Haar分类器用到了Boosting算法中之AdaBoost算法,只是将AdaBoost算法训练有之大分类器进行了级联,并且在脚的特征提取中行使了强效率的矩形特征与积分图方法,这里提到到的几乎单名词接下会具体讨论。

         在2001年,Viola与Jones两各项大牛发表了藏的《Rapid Object
Detection using a Boosted Cascade of Simple Features》和《Robust
Real-Time Face
Detection》,在AdaBoost算法的根基及,使用Haar-like小波特征与积分图方法进行人口脸检测,他俩不是极致早采用提出小波特征的,但是她们计划了对人脸检测还实用之特点,并针对AdaBoost训练有之赛分类器进行级联。这可以说凡是颜面检测史上里程碑式的一律笔了,也为此这提出的之算法为号称Viola-Jones检测器。又过了一段时间,Rainer
Lienhart和Jochen
Maydt两位异常牛将是检测器进行了扩大【3】,最终形成了OpenCV现在的Haar分类器。

          
AdaBoost是Freund和Schapire在1995年提出的算法,是指向传统Boosting算法的一致生提升。Boosting算法的核心思想,是将死亡学习方式提升成胜上算法,也不怕是“三个臭皮匠顶一个智囊”

Haar分类器 = Haar-like特征 + 积分图方法 + AdaBoost +级联;

Haar分类器算法的要如下:

① 使用Haar-like特征做检测。

② 使用积分图(Integral Image)对Haar-like特征求值进行加速。

③ 使用AdaBoost算法训练区分人脸和非人脸的高分类器。

④ 使用筛选式级联把大分类器级联到一起,提高准确率。

 

次、Haar分类器的浅入浅出

2.1 、Haar-like特征你是何方神圣?

        什么是特点,我将她座落脚的气象中来描述,假要于人数脸检测时我们要来诸如此类一个子窗口于待检测的图纸窗口被频频的动滑动,子窗口每届一个职,就见面算起拖欠区域之特性,然后用我们训练好之级联分类器对该特征进行筛选,一旦该特征通过了装有强分类器的淘,则判定该区域也面。

那这特性如何表示也?好了,这就算是大牛们干的善事了。后人遂这他们作出来的这些事物叫Haar-Like特征。

脚是Viola牛们提出的Haar-like特征。

C语言 1

 

下面是Lienhart等牛们提出的Haar-like特征。

C语言 2

     
这些所谓的性状未就是是相同堆积堆积如山带条纹的矩形形么,到底是干吗用之?我这么于出解释,将地方的随机一个矩形放到人脸区域上,然后,将白色区域的像素和削弱去黑色区域之比如素和,得到的值我们暂且称之为人脸特征值,如果你管这矩形放到一个非人脸区域,那么合算产生的特征值应该同人数脸特征值是无一样的,而且进一步不一致越好,所以这些方块的目的就是管丁脸特征量化,以界别人脸和非人脸。

        为了增加区分度,可以对多只矩形特征计算得到一个界别渡过再怪之特性值,那么怎样的矩形特征怎么样的结及同片好又好之区别出人脸和非人脸呢,这就是AdaBoost算法要召开的从业了。这里我们事先拖积分图这个定义不随便,为了为咱的思绪连贯,我直接开始介绍AdaBoost算法。

 

2.2、 AdaBoost你吃自身的确道来!

      
本节旨在介绍AdaBoost在Haar分类器中之运用,所以只是是叙了它们以Haar分类器中之特点,而其实AdaBoost是平种有一般性的分类器提升算法,它采取的分类器并无局限某一样一定算法。

     
上面说交用AdaBoost算法可以助我们摘重新好的矩阵特征结合,其实这里涉及的矩阵特征结合就是咱前面涉嫌的分类器,分类器将矩阵组合以二叉决策树的形式储存起来。

我现脑子里露出了累累题目,总结起来粗粗发生这样几个:

(1)弱分类器和大分类器是呀?

(2)弱分类器是怎么抱的?

(3)强分类器是怎么抱的?

(4)二叉决策树是什么?

倘应对这同一名目繁多题材,我得与你罗嗦一会儿了,这得起AdaBoost的遭遇说自。

 

2.2.1、 AdaBoost的身世之谜

      
AdaBoost的老祖先可以说凡是机上的一个模子,它的名字叫PAC(Probably
Approximately Correct)。

PAC模型是算上理论中常用的模型,是Valiant牛在自家还没出生的1984年取出来的【5】,他看“学习”是模式显然清晰或模式不设有时时按会取得知识之同等栽“过程”,并于有了一个起计算角度来博这种“过程”的方式,这种方法包括:

(1)适当信息征集体制的挑三拣四;

(2)学习的协定;

(3)对能够当成立步骤内形成上之定义的分类。

         
PAC学习的原形就是是以样本训练的基础及,使算法的输出以概率接近未知的目标概念。PAC学习型是考虑样本复杂度(指学习器收敛到成功借出设时至少所待的训练样本数)和测算复杂度(指学习器收敛到成功而时所要的计算量)的一个基本框架,成功之求学给定义为形式化的票房价值理论。简单说来,PAC学习型不求您每次都不错,只要会于差不多项式个样本和多项式时间内取满足急需的正确率,就终于一个成功之读书。

       
基于PAC学习型的申辩剖析,Valiant牛提出了Boosting算法【5】,Boosting算法涉及到零星个重大之定义就是死学习和强上。

Ø  弱学习:就算是因一个攻算法对同一组概念的识别率只比较自由识别好一点;

Ø  强学习:纵使是据一个上学算法对同一组概率的识别率很高。

       
现在咱们明白所谓的弱分类器和强分类器就是故学习算法和赛上算法。弱学习算法是较容易得到的,获得过程需要数巨大的若集合,这个要集合是根据某些简单规则之做及针对样本集的性评估而生成的,而大上算法是不便于取得的,然而,Kearns和Valiant两头牛提出了回老家学习及大上等价格的题材【6】并说明了一旦来足够的多寡,弱学习算法就能够通过集成的方式生成任意高精度的胜上道。这同样征使得Boosting有了保险的答辩功底,Boosting算法成为了一个晋级分类器精确性的日常方法。【4】

      
1990年,Schapire牛提出了第一个多项式时间的算法【7】,1年晚Freund牛又提出了一个频率又胜之Boosting算法【8】。然而,Boosting算法还是有着几只举足轻重的题目,其一Boosting算法需要事先了解死学习算法学习正确率的下限即死亡分类器的误差,其二Boosting算法可能致新兴的训练过分集中为少数专程难分的样书,导致不安定。针对Boosting的多少弱点,Freund和Schapire牛于1996年左右提出了一个其实可用之于适应Boosting算法AdaBoost【9】,AdaBoost目前早就发展起了约四种样式之算法,Discrete
AdaBoost(AdaBoost.M1)、Real AdaBoost、LogitBoost、gentle
AdaBoost,本文不开一一介绍。至此,AdaBoost的际遇的谜就如此揭开鸟。同时弱分类器和赛分类器是啊的题目呢说明清楚了。剩下3个问题,我们先行看一下,弱分类器是何许收获的。

 

2.2.2、弱分类器的孵化

       
最初的弱分类器可能就是一个最为基本的Haar-like特征,计算输入图像的Haar-like特征值,和最初的弱分类器的特征值比较,以之来判定输入图像是未是脸部,然而这弱分类器太简陋了,可能并无较自由判断的效能好,对弱分类器的孵化就是训练弱分类器成为最为优弱分类器,注意这里的不过精彩不是因大分类器,只是一个误差相对小小之弱分类器,训练弱分类器实际上是也分类器进行安装的过程。至于什么设置分类器,设置什么,我们第一分别看下与世长辞分类器的数学结构及代码结构。

数学结构

 C语言 3

      
一个弱分类器由子窗口图像x,一个特征f,指示不等于号方向的p和阈值Θ组成。P的意向是控制不等式的来头,使得不等式都是<号,形式好。

代码结构

/*

  * CART classifier

  */

 typedef struct CvCARTHaarClassifier

 {

     CV_INT_HAAR_CLASSIFIER_FIELDS()

     int count;

     int* compidx;

     CvTHaarFeature* feature;

     CvFastHaarFeature* fastfeature;

     float* threshold;

     int* left;

     int* right;

     float* val;

 } CvCARTHaarClassifier;

 代码结构面临的threshold即意味着数学结构中之Θ阈值。

     
这个阈值究竟是干吗的?我们事先了解下CvCARTHaarClassifier这个结构,注意CART这个词,它是均等栽二叉决策树,它的倡导者Leo
Breiman等牛称该也“分类及回归树(CART)”。什么是决定树?我一旦条分缕析讲起来而得其它于一节,我光简单介绍她。

     
“机器上着,决策树是一个展望模型;他意味着的凡目标属性与目标值内的一致栽炫耀关系。树被每个节点表示有对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则指向承诺自根节点交该叶节点所经历的门路所代表的靶子的价值。决策树仅来纯粹输出,若需来复数输出,可以建立独立的仲裁树因拍卖不同输出。从数据来决策树的机器上技术叫做决策树学,通俗说就是是决策树。”(来自《维基百科》)

决定树包含:分类培育,回归树,分类及回归树(CART),CHAID。

分类和回归之分是,

Ø  分类:是当预测结果也许为少种植档次(例如男女,输赢等)使用的定义。

Ø  回归:是当局域结果可能为实数(例如房价,患者住院日等于)使用的定义。

      
决策树用途充分广阔得分析因素对事件结果的影响(详见维基百科),同时为是老大常用之归类方法,我选个最简单易行的表决树例子,假要我们使用三只Haar-like特征f1,f2,f3来判断输入数据是否也面,可以建立如下决定树:

 C语言 4

       
可以看到,在分拣的运中,每个非叶子节点都代表同样种判断,每个路径代表一样栽判断的出口,每个叶子节点代表一致种类型,并视作最终看清的结果。

       
一个弱分类器就是一个主导与达成图接近之决策树,最中心的弱分类器只包含一个Haar-like特征,也就算是它的裁决树只出一致重合,被誉为树桩(stump)。

       
最着重之虽是怎决定每个结点判断的出口,要比较输入图片的特征值和弱分类器中特征,一定用一个阈值,当输入图片的特征值大于该阈值时才判该也面。训练最优弱分类器的历程实际上就是是当寻找适合的分类器阈值,使该分类器对有样本的判读误差最低。

具体操作过程如下:

1)对于每个特征 f,计算有所训练样本的表征值,并以其排序。

举目四望一全体排好序的特点值,对排好序的表中的每个元素,计算下面四个价:

全体满脸样本的权重的以及t1;

所有非人脸样本的权重的同t0;

以斯因素之前的人头脸样本的权重的以及s1;

当此因素之前的非人脸样本的权重的与s0;

2)最终求得每个元素的归类误差 r = min((s1 + (t0 – s0)), (s0 + (t1 –
s1)))

       
在表明中找找r值最小之素,则该因素作为最了不起阈值。有了该阈值,我们的首先个极端优弱分类器就出生了。

于当时老的折磨中,我们见证了一个弱分类器孵化成长的长河,并答复了哪收获弱分类器以及二叉决策树是啊。最后之题目是大分类器是怎么样赢得的。

 

2.2.3、弱分类器的化蝶飞

率先看一下胜似分类器的代码结构:

/* internal stage classifier */

 typedef struct CvStageHaarClassifier

 {

     CV_INT_HAAR_CLASSIFIER_FIELDS()

     int count;

     float threshold;

     CvIntHaarClassifier** classifier;

 }CvStageHaarClassifier;

/* internal weak classifier*/

typedef struct CvIntHaarClassifier

{

CV_INT_HAAR_CLASSIFIER_FIELDS()

} CvIntHaarClassifier;

        这里而涉及的是CvIntHaarClassifier结构:它就相当给一个接口类,当然是因此C语言模拟的面向对象思想,利用CV_INT_HAAR_CLASSIFIER_FIELDS()这个宏让弱分类CvCARTHaarClassifier强分类器和CvStageHaarClassifier继承于CvIntHaarClassifier。

愈分类器的出世需要T轮的迭代,具体操作如下:

1. 加以训练样本集S,共N个样本,其中X和Y分别对应于正样本及负样本; T为教练的绝深循环次数;  

2. 初始化样本权重为1/N,即为训练样本的开端概率分布;  

3. 率先浅迭代训练N个样本,得到第一独顶优弱分类器,步骤见2.2.2节

4. 增高上等同轮子被给误判的范本的权重;

5. 以新的范本与上次遵循分错的样书在同展开新一轱辘的训。

6. 巡回执行4-5步骤,T轮后获T个最优弱分类器。

7.组合T单极优弱分类器得到高分类器,组合措施如下:

  C语言 5        

       相当给让拥有弱分类器投票,再指向投票结果按弱分类器的错误率加权求和,将投票加权求和的结果以及平均投票结果比得出最终之结果。

     
至此,我们视实际我之问题由的优秀也并无对路,强分类器的脱颖而出更如是民主的投票制度,众人拾材火焰高,强分类器不是个体英雄主义的底结局,而是团结之能力。但自本的局外的角度看,整个AdaBoost算法就是一个弱分类器从孵化至化蝶的长河。小人物的冲刺永远是理想主义者们津津乐道的话题。但少被咱拖AdaBoost继续探讨Haar分类器的别样特色吧。

 

2.3、强分类器的强强联手

       
至今为止我们好像一直当开口分类器的训练,实际上Haar分类器是起半点单网之,训练之体系,和检测的网。训练之一对大约都涉及了,还余下最后一有的即是针对性筛选式级联分类器的教练。我们来看了通过AdaBoost算法辛苦之训出了高分类器,然而以切实的总人口脸检测中,只靠一个强分类器还是难以保证检测的正确率,这个时候,需要一个美轮美奂的阵容,训练有多只强分类器将她强强联手,最终形成正确率很高之级联分类器这虽是我们最后的目标Haar分类器。

        
那么训练级联分类器的目的就是以检测的时刻,更加规范,这干到Haar分类器的别样一个体系,检测体系,检测系统是为现实中之一模一样帧颇图片作为输入,然后对图纸中进行多区域,多规格之检测,所谓多区域,是使针对图纸划分多块,对每个片进行检测,由于训练之时光用之肖像相像还是20*20左右底略微图,所以对于充分之总人口脸,还需要展开多规格之检测,多规格检测机制一般生半点栽政策,一种植是免更改搜索窗口的大小,而频频缩放图片,这种艺术明显要对每个缩放后的图纸展开区域特征值的演算,效率不愈,而其余一样种方式,是连连初始化搜索窗口size为教练时之图片大小,不断扩大搜索窗口,进行搜寻,解决了第一种植方法的弱势。在区域推广的长河遭到见面冒出和一个口脸给一再检测,这需要展开区域之联结,这里不作探讨。

         无论哪一样种检索方法,都见面也输入图片输出大量的子窗口图像,这些子窗口图像经过筛选式级联分类器会没完没了地受诸一个节点筛选,抛弃或经。

她的构造如图所示。

 C语言 6

本身思念你肯定当特别熟悉,这个结构不是老像一个略的决策树么。

于代码中,它的构造如下:

 

/* internal tree cascade classifier node */

 typedef struct CvTreeCascadeNode

 {

     CvStageHaarClassifier* stage;

     struct CvTreeCascadeNode* next;

     struct CvTreeCascadeNode* child;

     struct CvTreeCascadeNode* parent;

     struct CvTreeCascadeNode* next_same_level;

     struct CvTreeCascadeNode* child_eval;

     int idx;

     int leaf;

 } CvTreeCascadeNode;

 

 /* internal tree cascade classifier */

 typedef struct CvTreeCascadeClassifier

 {

     CV_INT_HAAR_CLASSIFIER_FIELDS()

     CvTreeCascadeNode* root;      /* root of the tree */

     CvTreeCascadeNode* root_eval; /* root node for the filtering */

     int next_idx;

 } CvTreeCascadeClassifier;

 

        级联强分类器的政策是,将多只强分类器由简单到复杂排列,希望经过训练使每个强分类器都发生比高检测率,而误识率可以放低,比如几乎99%底食指脸可以经过,但50%的非人脸也堪经,这样一旦产生20只大分类器级联,那么他们的总识别率为0.99^20大体相当于98%,错误接受率也仅仅为0.5^20约齐0.0001%。这样的机能就可满足实际的消了,但是什么使每个强分类器都享有较高检测率呢,为什么单个的大分类器不可以而且具备较高检测率和比高误识率呢?

     
下面我们叙讲级联分类器的训。(主要参照了舆论《基于Adaboost的口脸检测方法和眼睛定位算法研究》)

设K是一个级联检测器的层数,D是该级联分类器的检测率,F是该级联分类器的误识率,di是第i重叠高分类器的检测率,fi是第i层高分类器的误识率。如果只要训练一个级联分类器达到给定的F值和D值,只待训练出每层的d值和f值,这样:

d^K = D, f^K = F

级联分类器的中心就是何许训练每层高分类器的d值和f值达到指定要求。

        
AdaBoost训练出的高分类器一般装有比小的误识率,但检测率并无深高,一般情况下,高检测率会促成大误识率,这是青出于蓝分类阈值的撤并导致的,要加强高分类器的检测率既使大跌阈值,要下降强分类器的误识率就假设增长阈值,这是独矛盾的事情。据参考论文的尝试结果,增加分类器个数可以于增强高分类器检测率的还要降低误识率,所以级联分类器在教练时如考虑如下平衡,一凡是物化分类器的个数和计量时之抵,二凡是赛分类器检测率和误识率之间的抵。

      具体训练方法如下,我于是伪码的款型被出:

1)设定每层最小如达成的检测率d,最充分误识率f,最终级联分类器的误识率Ft;

2)P=人脸训练样本,N=非总人口脸训练样本,D0=1.0,F0=1.0;

3)i=0;

4)for : Fi>Ft

 ++i;

 ni=0;Fi=Fi-1;

 for : Fi>f*Fi-1

 ++ni;

 利用AdaBoost算法在P和N上训练有ni个弱分类器的高分类器;

 衡量当前级联分类器的检测率Di和误识率Fi;

 for : di<d*Di-1;

 降低第i层的赛分类器阈值;

 衡量当前级联分类器的检测率Di和误识率Fi;

 N = Φ;

 利用目前之级联分类器检测不人脸图像,将误识的图像放入N;

 

2.4 、积分图是一个加速器

        之所以放到最后说积分图(Integral
image),不是为它们不重要,正相反,它是Haar分类器能够实时检测脸部的承保。当我拿Haar分类器的主脉络都介绍了晚,其实当这边引出积分图的定义相当。

         在前边的章节中,我们耳熟能详了Haar-like分类器的训练和检测过程,你晤面视任训练要检测,每遇一个图纸样本,每遇一个子窗口图像,我们且面临着哪些计算当前子图像特征值的题目,一个Haar-like特征在一个窗口被哪排列能够又好之反映人脸的特性,这是未知之,所以才要训练,而教练前我们不得不通过排列组合穷举所有这样的特征,仅盖Viola牛提出的绝基本四只特征呢条例,在一个24×24size之窗口中擅自排列至少可产生数以10万划算之特征,对这些特点求值的计算量是深充分的。

倘积分图就是只遍历一不良图像就足以要来图像遭到保有区域像素和的高效算法,大大的提高了图像特点值计算的效率。

咱们来探它是怎么形成的。

积分图是同样种植能描述全局信息的矩阵表示方法。积分图的构造方式是岗位(i,j)处之值ii(i,j)是原本图像(i,j)左上角倾向有着像从的及:

  C语言 7        

积分图构建算法:

1)用s(i,j)表示行方向的长和,初始化s(i,-1)=0;

2)用ii(i,j)表示一个积分图像,初始化ii(-1,i)=0;

3)逐行扫描图像,递归计算每个像素(i,j)行方向的丰富和s(i,j)和积分图像ii(i,j)的价值

s(i,j)=s(i,j-1)+f(i,j)

ii(i,j)=ii(i-1,j)+s(i,j)

4)扫描图像一通,当到图像右下角像素时,积分图像ii就组织好了。

积分图构造好下,图像中任何矩阵区域的像素累加和还得透过简单运算得到如图所示。

       C语言 8   

设D的季单顶峰分别吗α、β、γ、δ,则D的像素和足表示也

Dsum = ii( α )+ii( β)-(ii( γ)+ii( δ ));

苟Haar-like特征值无非就是是个别独矩阵像素和的两样,同样好在常数时间内得。

 

其三、Haar分类器你胆敢再快点也?!

当下同段我概括的探讨下Haar分类器的检测频率。

本身尝试过的几乎种办法:

1)尝试检测算法和跟算法相结合,原本以为Camshift是单轻量级的算法,但是比较我后来相的,建立反向投影图的效率实在不赛,在PC上力量不错,但是当ios上快颇缓慢,这个自后来察觉或是以ios浮点运算效率不强的原因。但是就是速度会上,靠Camshift跟踪算法极其依仗肤色了,导致脖子,或是手啊的侵扰大严重,这个调整起来很辛苦,也非肯定能够调动好。

2)修改OpenCV中Haar检测函数的参数,效果特别明确,得出的下结论是,搜索窗口的搜寻区域是提高效率的重点。

3)根据2)的启迪,我打算采取YCbCr颜色空间,粗估肤色区域,以减少人数脸的搜面积,但是后来烦躁没有能够强效率的分出肤色区域,放弃了拖欠方式。

4)换了方针,考虑到视频被人脸检测的特殊性,上一帧人脸的位置信息对下一帧的检测出不行高的指导价值,所以采有帧间约束之道,减少了丁脸搜索的区域,并且动态调整Haar检测函数的参数,得到了较高的频率。

5)其他关于算法之外的优化内需基于不同的微处理器做具体的优化。

 

四、总结

      
之前没怎么碰到电脑视觉领域,这次reseach对己来说是一个未略的挑战,发现内部提到大气底数学知识,线代,统计学,数学分析等等,虽然发辛苦,但本身感到莫大的趣味,尤其是机上园地,在本人面前进行的是一致幅好的画面,大牛们神乎其技各显神通,复杂的数学公式背后蕴藏着简单的哲理与揣摩。

人类的提高来对本来背后神秘力量的惊奇和膜拜,简单的构造往往构建出给丁难以想象的皇皇,0和1构成了极大之电子信息世界,DNA构成了温馨尚且爱莫能助完全了解自己之生命体,夸克也许比夸克还有些之粒子构成了是让人在迷的宇宙空间,在这些简单的结构背后,是啊在注视着我们,狭义的编程只是以计算机的硬件躯壳内构建而尽之次序,而广义的编程在我看来是创建世界之平栽手段。

如今,我受您一个开立世界之时机,你是因此Vim还是Emacs,也许你会调侃的跟我说:

“恩,我用E = mc^2”。