Adaboost级联分类器经典运用案例:人脸识别

#include <opencv2/opencv.hpp>
#define CV_COLOR_RED cv::Scalar(0, 0, 255)
int main(int argc, char** argv)
{cv::CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");cv::Mat image = cv::imread("Your image path.");std::vector<cv::Rect> objects;faceDetector.detectMultiScale(image, objects);for (int i = 0; i < objects.size(); i++){cv::rectangle(image, objects[i], CV_COLOR_RED);}cv::imshow("result", image);cv::waitKey(0);return 0;
}

结果如下:

1 Haar特征
opencv接口中,实现Haar/LBP/HOG等多种特征,本文以Haar特征为例介绍。
1.1 Haar特征的生成
Haar特征最先由Paul Viola等人提出,后经过Rainer Lienhart等扩展引入45°倾斜特征,成为现在OpenCV所使用的的样子。图1-1展示了目前OpenCV(2.4.11版本)所使用的共计14种Haar特征,包括5种Basic特征、3种Core特征和6种Titled(即45°旋转)特征。

实际检测中,Haar特征可以在窗口中自由放大+平移产生一系列的子特征,但是白:黑区域面积比始终保持不变。

如图1-2,以x3特征为例,在放大+平移过程中白:黑:白面积比始终保持1:1:1。首先在红框所示的检测窗口中生成大小为3个像素的最小X3特征;之后分别沿着x和y平移产生了在检测窗口不同位置的大量最小3像素X3特征;然后把最小X3特征沿着x和y放大,再平移,又产生了一系列大一点的X3特征;然后继续放大+平移,重复此过程,直到放大后的x3和检测窗口一样大。这样x3就产生了完整的x3系列特征。

通过这些放大+平移的获得的子特征总共有多少个?Rainer Lienhart在他的论文中给出了完美的解释:假设检测窗口大小为WH,举行特征大小为wh,X和Y 为表示矩形特征在水平和垂直方向的能放大的最大比例系数:


则如图1-3,在检测窗口Window中,一般矩形特征(upright rectangle)的数量为:

简单解释一下,上述公式可以理解为:
1特征框竖直放大1倍,即无放大,竖直方向有(H-h+1)个特征
2特征框竖直放大2倍,竖直方向有(H-2h+1)个特征
3特征框竖直放大3倍,竖直方向有(H-3h+1)个特征
4如此到竖直放大Y=floor(H/h)倍,竖直方向有1个特征,即(H-Yh+1)
那么竖直方向总共有

个特征。考虑到水平和竖直方向缩放是独立的,所以能得到上述公式。对应于之前的x3特征,当x3特征在24
24大小的检测窗口中时(此时W=H=24,w=3,h=1,X=8,Y=24),一共能产生27600个子特征,除x3外其他一般矩形特征数量计算方法类似。

1.2如何计算Haar特征值
看到这里,该看明白了大量的Haar特征是如何产生的。当有了大量的Haar特征用于训练和检测时,接下来的问题是如何计算Haar特征值。按照opencv代码,Haar特征值=整个Haar区域内像素和X权重+黑色区域内像素和X权重:

1.对于图2中的X3和y3特征,weightall=1,weightblack=-3;
2.对于point特征,weightall=1,weightblack=-9;
3.其余11种特征均为weightall=1,weightblack=-2;

这也是其他文章中提到的所谓“白色区域像素和减去黑色区域像素和”,只不过是加权相加而已。例如:
·对于x2特征:(黑 + 白) * 1+黑 * (-2) = 白 - 黑;
·对于Point特征:(黑 + 白) * 1 + 黑 * (-9) = 白 - 8 * 黑。
为什么要设置这种加权相减,而不是直接相减?请仔细观察图2中的特征,不难发现x3、y3、point特征黑白面积不相等,而其他特征黑白面积相等。设置权值就是为了抵消面积不等带来的影响,保证所有Haar特征的特征值在灰度分布绝对均匀的图中为0。

了解了特征值如何计算之后,再来看看不同的特征值的含义是什么。我选取MIT人脸库中2706个大小为20*20的人脸样本图像,计算如图1-4位置的Haar特征值,结果如图1-5。

1-4haar特征位置示意图

图4的2个Haar特征在MIT人脸样本中特征值分布图(左边特征结果为红色,右边蓝色)

可以看到,图1-4中2个不同的Haar特征在同一组样本中具有不同的特征分布,左边特征计算出的特征值基本都大于0,而右边特征计算出的特征值基本均匀分布于0两侧(分布越均匀对样本的区分度越小)。所以,正是由于样本中Haar特征值分布不同,导致了不同Haar特征分类效果。显而易见,对样本区分度越大的特征分类效果越好,即红色曲线对应图1-4中的左边Haar特征分类效果好于右边Haar特征。那么看到这里,应该理解了下面的2个问题:
1.在检测窗口通过平移+放大可以产生一系类Haar特征,这些特征由于位置和大小不同,分类效果也各异;
2.通过计算Haar特征的特征值,可以有将图像矩阵映射为1维特征值,有效的实现了降维

1.3 Haar特征如何保存
对应的,在opencv xml文件中,每个Haar特征都被保存在2~3个形如:
< x y weidth height weight>
的标签中,其中x和y代表Haar矩形左上角坐标(以检测窗口左上角为原点),width和height代表矩形的宽和高,而weight则对应了上面说的权重值,例如图4中左边的x2类型的Haar特征应该为<4 2 12 8 1.0>(整个Haar,权重1)和<4 2 12 4 -2.0>(黑色区域,权重-2)。

1.4 Haar 特征值标准化
从上文1-5中发现,仅仅一个1218大小的Haar特征计算出的特征值变化范围从-2000~+6000,
跨度非常大。这种跨度大的特性不利于量化评定特征值,所以需要进行“标准化”,压缩特征值范围。假设当前检测窗口中图像为i(x,y),当前检测窗口为w
h大小(例如图6中2020大小),OPenCV采用如下方式“标准化”:
**·**计算检测窗口中间部分(w-2)
(h-2)的图像的灰度值和灰度值平方和:

**·**计算均值:

**·**计算标准化因子:

**·**标准化特征值:

具体代码在cascadedetect.cpp中的HaarEvaluator::setImage()函数中可以看到,关键部分如下:

normrect = Rect(1, 1, origWinSize.width-2, origWinSize.height-2);
CV_SUM_PTRS( p[0], p[1], p[2], p[3], sdata, normrect, sumStep );
CV_SUM_PTRS( pq[0], pq[1], pq[2], pq[3], sqdata, normrect, sqsumStep );

与代码对应的,如图中蓝色为检测窗口,红色为标准化过程中使用到的像素。

其实如何标准化并不重要,重要的是检测和训练时的方法一定要一致,否则可能会由于标准化不同带来的误差导致模型无法工作!

1.5 积分图像
以OpenCV自带的人脸分类器haarcascade_frontalface_alt2.xml为例,其中存储了超过1000个大小和位置都不相同的Haar特征(XML文件解释见下节)。在运算中,伴随着检测窗口的移动,如何快速计算Haar特征值就成了一个很重要的问题。在设计Haar+AdaBoost算法时,Paul Viola等人就提出积分图。

对于灰度图像中任意一点image(x,y),opencv定义其积分图为sum(x,y)为:

其中第0行和第0列为0:

其中image(x,y)为点(x,y)处的原始灰度图。这样就定义了一张类似于数学中“积分”的积分图。如图1-7,如果要计算D区域内灰度和,只需要计算

其中(x1,y1),(x2,y2),(x3,y3),(x4,y4)依次代表图1中image的1234点的图像坐标。需要说明,在计算D区域灰度和时sum(x1,y1)深蓝色区域被减去了2次,最后需要补上。显然可以通过此方法快速计算图像中任意位置和大小区域的灰度和,即通过积分图像只需要做有限次操作就能获得任意位置的Haar特征值

1.6 旋转积分图

为了提高检测精度,Rainer Lienhart 等人首先提出了45°旋转积分图,如图1-8.旋转积分图用于快速计算图1中的title_x2和title_y2等共6种旋转Haar特征。

图1-8 45°旋转积分图

与一般积分图类似,opencv中45°旋转积分图同样采用“扩边”方式(即旋转积分图比原灰度图多1行和1列,其中第1行和1列元素为0),对应计算公式为:

其中第一行第一列为0:



有了旋转积分图如何计算任意位置和大小的45°倾斜长方形区域的灰度和呢?
设有如图9红色方框大小的灰度图image,其计算出来的45°旋转灰度图为titled(第0行和第0列为0),虚线代表image中cv::Rect为<3 1 2 3>区域。显然虚线区域的灰度和为:

应该不难理解。(最后一个是+titled(4,1))
在实际中,如果使用旋转特征,则需要多计算一张积分图。但是旋转特征的效果往往不理想,得不偿失,不建议使用。
ps:45°旋转积分图还有另外一种实现方式,但是opencv由于数据存储方式限定不那样做。

2 级联分类器结构
了解Haar特征之后,接下来分析级联分类器结构,主要包括以下2个内容:
1.OpenCV中的Adaboost级联分类器的结构,包括强分类器和弱分类器的形式;
2.Opencv自带的XML分类器中各项参数的含义,如internalNodes和leafValues标签里面的一大堆数字的意义。

Opencv中的Adaboost级联分类器是树状结构,如图2-1,其中每个stage都代表一级强分类器。当检测窗口通过所有的强分类器时才被认为是目标,否则拒绝。实际上,不仅强分类器是树状结构,强分类器中的每一个弱分类器也是树状结构。

图2-1 强分类器和弱分类器示意图(此图有误,应是stage1,stage2,…,stageN)

这篇文章将结合OpenCV-2.4.11中自带的haarcascade_frontalface_alt2.xml文件介绍整个级联分类器的结构。需要说明,自从2.4.11版本后所有分类器都被替换成新式XML,所以本文介绍新式XML结构。(注意:opencv2.4.11之后和之前的.xml文件不兼容)。

2.1 xml的头部
在了解opencv分类器的结构之前,先看看存储分类器的XML文件汇总有什么。图2中注释分类器XML文件头不信息,括号中的参数为opencv_traincascade.exe训练程序对应参数。

其中< features >标签存储了所有的Haar特性,在之前的1.3节有讲。

2.2 弱分类器结构
Haar特征和弱分类器之间的关系和简单:
一个完整的弱分类器包括:
1.若干个Haar特征+和Haar特征数量相等的弱分类器阈值
2.若干个leftValue
3.若干个rightValue

这些元素共同构成了弱分类器,缺一不可。haarcascade_frontalface_alt2.xml的分类器Depth=2,包含2种形式,如图2-3:
**·**左边形式包含2个Haar特征、1个leftValue、2个rightValue和2个弱分类器阈(t1和t2)
**·**右边形式包含2个Haar特征、2个leftValue、1个rightValue和2个弱分类器阈值

图2-3 Depth=2的树状弱分类器示意图

看图2-3应该明白了弱分类器的大致结构,接下来我们了解树状弱分类器是如何工作的。还是以图3左边的形式为例:
1.计算第一个Haar特征的特征值haar1,与第一个弱分类器阈值t1对比,当haar1<t1时,进入步骤2;当haar1>t1时候,该弱分类器输出rightValue2并结束。
2.计算第二个Haar特征值haar2,与第二个弱分类器阈值t2对比,当haar2<t2时候输出leftValue;当haar2>t2时输出rightValue1。

即通过上述步骤计算弱分类器输出值,这与Opencv的cascadedetect.hpp文件中predictOrdered()函数代码对应(这里简单解释一下,在OpenCV中所有弱分类器的leftValue和rightValue都依次存储在一个一维数组中,代码中的leafOfs表示当前弱分类器中leftValue和rightValue在该数组中存储位置的偏移量,idx表示在偏移量leafOfs基础上的leftValue和rightValue值的索引,cascadeLeaves[leafOfs - idx]就是该弱分类器的输出):

do
{CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx];double val = featureEvaluator(node.featureIdx);idx = val < node.threshold ? node.left : node.right;
}
while( idx > 0 );
sum += cascadeLeaves[leafOfs - idx];

即弱分类器的工作方式:通过计算出Haar特征值与弱分类器阈值对比,从而选择最终输出leftValue和rightValue值中的哪一个。

那么这些Haar特征、leftValue、rightValue和弱分类器阈值t都是如何存储在xml文件中的?不妨来看haarcascade_frontalface_alt2.xml文件中的第一级的第三个弱分类器,如图2-4。图2-4中的弱分类器恰好是图3中左边类型,包含了和两个标签。其中标签中的3个浮点数由左向右依次是rightValue2、leftValue和rightValue1;而中有6个整数和2个浮点数,其中2个浮点数依次分别是弱分类器阈值t1和t2,剩下的6个整数容我慢慢分解。

首先来看两个浮点数前的整数,即4和5。这两个整数用于标示所属本弱分类器Haar特征存储在标签中的位置。比如数值4表示该弱分类器的haar1特征存储在xml文件下面标签中第4个位置,即为:

而的其他4个整数1、0和-1、-2则用于控制弱分类器树的形状。在运行时,OpenCV会把1赋值给当前的node.left,并把0赋值给node.right(请注意do-while代码中的条件,只有idx<=0时才停止循环,参考图3应该可以理解这4个整数的含义)。如此,OpenCV通过这些巧妙的数值和结构,控制了整个分类器的运行。可以看到,每个弱分类器内部都是类似于这种树状的“串联”结构,所以我称其为“串联组成的的弱分类器”。

图2-4 OpenCV弱分类器运行示意图

而Depth=1(如haarcascade_frontalface_alt.xml)类型的弱分类器,结构更加简单且运行方式对比可知,不在赘述

图2-5 Depth=1的stump弱分类器示意图

2.3 强分类器结构
在opencv中,强分类器是有多个弱分类器“并列”构成,即强分类器中的弱分类器是两两相互独立的。在目标检测时,每个弱分类器独立运行并输出cascadeLeaves[leafOfs-idx]值,然后把当前强分类器中每个弱分类器的输出值相加,即:

sum += cascadeLeaves[leafOfs - idx];


之后与本级强分类器的stageThreshold阈值对比,当且仅当结果sum>stageThreshold时,认为当前检测窗口通过了该级强分类器。当前检测窗口通过所有强分类器时,才被认为是一个检测目标。可以看出,强分类器与弱分类器结构不同,是一种类似于“并联”的结构,我称其为“并联组成的强分类器”。

2.4 如何搜索目标?
还有一个问题:检测窗口大小固定(例如alt2是20*20像素)的级联分类器如何遍历图像,以便找到在图像中大小不同、位置不同的目标?

解决方法如下:为了找到图像中不同位置的目标,需要逐次移动检测窗口(窗口中的Haar特征相应也随着移动),这样就可以遍历到图像中的每一个位置;而为了检测到不同大小的目标,一般有两种做法:逐步缩小图像or逐步放大检测窗口:
1.缩小图像就是把图像按照一定的比例逐步缩小然后滑动窗口检测,如图2-7;
2.放大检测窗口是吧检测窗口长宽按照一定比例逐步放大,这时位于检测窗口内的Haar特征也会对应放大,然后检测。

图2-7 经典的Pyramid+Sliding-window检测(借用一张大佬的照片)
新版c++函数CascadeClassifier::detectMultiScale()只实现了缩小图像检测;旧版的c函数cvHaarDetectObject()同时实现了缩小图像和放大窗口两种检测方式,当函数参数flag为CV_HAAR_SCALE_IMAGE时是缩小图像检测,默认flag=0时放检测大窗口检测。
#define CV_HAAR_SCALE_IMAGE 2

3 对检测结构NMS
考虑这样的情况:一个被检测为目标的窗口,其附近窗口也应该被检测到。

图3-1 展示检测一副含有人脸图像的结果,左边为合并检测结果窗口之前的结果,右边为合并之后的结果。所以有必要对重叠的检测结果窗口进行合并,同时剔除零散分布的错误检测窗口。该功能其实就是NMS(non-maximum suppression即是非极大值抑制)。

图3-1 检测结果合并窗口前后对比图

3-1 并查集(Union-Set)
在了解如何合并窗口前,先来了解一种数据结构——并查集。为了形象的说明并查集,首先来了解一个例子。江湖上存在各种各样的大侠,他们没什么正当职业,整天背着剑四处游荡,碰到其他大侠就大打出手。俗话说“双拳难敌四手”,这些大侠都会拉帮结派壮大实力。那么为了辨识每个大侠属于哪个帮派,就需要每个帮派都推举一个“老大”。这些大侠只需要知道自己和其他大侠的老大是不是同一个人,就能明白自己和对方是不是一个帮派,从而决定是否动手过招。

图3-2 江湖大侠关系图(箭头表示上一级)

如图3-2,现在武当和明教分别推举张三丰和张无忌为老大。当帮派很大时,每个大侠记不住帮派所有人,那么他们只需要记住自己的上一级是谁,一级一级往上问就知道老大是谁了。某日,宋青书和殷梨亭在武当山门遇到,那么宋青书问宋远桥后得知自己的老大是张三丰,而殷梨亭的老大也是张三丰,那么他俩是同门。反之宋青书遇到陈友谅时,一级一级向上询问后发现老大不是一个人,就不是同门。

除此之外,在武林中还需要组建联盟扩大帮派势力。既然杨不悔嫁给了殷梨亭,不妨直接设张无忌的上级为张三丰,这样就可以将明教和武当组成一个更大的联盟(如图3-2红色虚线。需要说明,我们只关心数据的代表,而忽略数据内部结构)。从此以后当宋青书再和杨不悔相遇,一级一级查询后可以确定是同伙了。但是如果大侠们相遇都像这样一级一级往上问,查询路径很长。所以这种直接连接最上级的方法不是最优。

为了解决这个问题,需要压缩路径——每个人记住自己最终的老大就行(如宋青书记住自己老大是张三丰,不在去问宋远桥),基本思路如下:
·以武当为例,张三丰创建门派(明教也类似)
·宋远桥和殷梨亭加入武当派,上级设置为张三丰
·宋青书通过与宋远桥的关系加入武当派,压缩路径后设置上级为张三丰,同时也设置其所有原上级的上级为张三丰(由于原上级宋远桥的上级就是张三丰,没有变化)。

压缩完路径后的武当与明教状态图如下,其中红色代表压缩路径:

·杨不悔通过与殷梨亭的关系也加入武当派别,压缩路径后设置上级为张三丰,同时设置原上级张无忌的上级是张三丰。绿色代表此次压缩路径。

以后每次在合并中关系到了谁,就压缩谁的路径,同时压缩谁的所有上级的路径。此后宋青书和杨不悔的查询路径就短了很多。
·假如某天范右使收徒了,徒弟也要加入联盟。在加入的时候,也需要压缩路径,设置徒弟的上级为张三丰;同时设置徒弟的原上级(范右使和张无忌)的上级为张三丰,如蓝色箭头。由于张无忌的上级就是张三丰,所以没有改变。这样,范右使的路径也得到压缩。

看完例子之后,一起来看看并查集定义。并查集保持一组不相交的动态集合S={S1,S2,…,Sk},每个动态集合Si通过一个代表ai来识别,代表是集合中的某个元素(ai∈Si)。在某些应用中,哪一个元素被选为代表是无所谓的,我们只关心在不修改动态集合的前提下分别寻找某一集合的代表2次获得的结果相同;在另外一些应用中,如何选择集合的代表可能存在预先说明的规则,如选择集合的最大or最小值作为代表。总之,在并查集中,不改变动态集合S则每个集合Si的代表ai不变。

不妨设x表示每个结点,p[x]表示x的父结点(即上一级,如图2中p[宋远桥]==张三丰),rank[x]表示x节点的秩(即该节点最长路径中结点个数,如图2中最长路径为:张三丰-张无忌-杨左使-杨不悔,所以rank[张三丰]==4)。并查集伪代码如下:

//创建Union-set
MAKE-SET(x)
1 p[x] ← x //←号表示赋值
2 rank[x] ← 0//合并x和y,底层压缩路径
UNION(x, y)
1 LINK(FIND-SET(x), FIND-SET(y))LINK(x, y)
1 if rank[x] < rank[y]
2     p[x] ← y
3 else
4     p[y] ← x
5     if rank[x]==rank[y]
6         rank[x] = rank[x] + 1FIND-SET(x)
1 if x ≠ p[x]
2     p[x] ← FIND-SET(p[x])
3 return p[x]

其中,MAKE-SET函数用于在无序数据中初始化并查集数据结构,将每个结点父结点设为其本身;UNION函数通过调用LINK和FIND-SET实现带压缩路径的并查集合并;LINK函数通过秩进行并查集合并;FIND-SET是带压缩路径的寻找结点代表的函数。如果还有不明白的地方,建议查阅《算法导论》中的第21章:《用于不相交的数据结构》

3.2 利用并查集合并检测结果窗口
为了将并查集利用到合并窗口中,首先要定义窗口相似函数,即当前的两个窗口是不是“一伙人”。在OpenCV中,图像中的矩形窗口一般用Rect结构体表示,其包含x,y,width,height共4个成员变量,分别代表窗口的左上角点x坐标、y坐标、宽度和高度。下面代码定义了窗口相似函数SimilarRects::operator(),当2个窗口r1和r2位置很接近时返回TRUE,通过SimilarRects::operator()就可以将图1那些重叠的窗口合并在“一伙人”中。

class CV_EXPORTS SimilarRects
{public:SimilarRects(double _eps) : eps(_eps) {}inline bool operator()(const Rect& r1, const Rect& r2) const{double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5;return std::abs(r1.x - r2.x) <= delta &&std::abs(r1.y - r2.y) <= delta &&std::abs(r1.x + r1.width - r2.x - r2.width) <= delta &&std::abs(r1.y + r1.height - r2.y - r2.height) <= delta;}double eps;
}

定义好窗口相似性函数后,就可以利用并查集合并窗口函数了,大致过程如下:
1.首先利用MAKE-SET函数建立Rect对象的并查集初始结构
2.然后遍历整个并查集,用SimilarRects::operator()判断每2个窗口相似性,若相似则将这2个窗口合并为“一伙人”;
3.运行完步骤2后应该出现几个相互间不相似的窗口“团伙”,当“团伙”中的窗口数量小于阈值minNeighbors时,丢弃该“团伙”(认为这是零散分布的误检);
4.之后剩下若干组由大量重叠窗口组成的大“团伙”,分别求每个“团伙”中的所有窗口位置的平均值作为最终检测结果。

这里只介绍NMS基本算法,代码请读者自行查阅OpenCV源码。不过在算法描述中为了清晰简洁,使用递归实现了整个并查集;但在实际中递归需要保存现场并进行压栈,开销极大,所以OpenCV使用循环替代了递归。

检测部分到此为止。接下来介绍训练部分。–》》》

opencv基础:adaboost+haar目标检测技术(上)相关推荐

  1. 黑窗口检测wamp的命令_OpenCV AdaBoost + Haar目标检测技术内幕(上)

    很多使用过OpenCV的小伙伴都见过如下代码.这段看似简单的代码,通过读入一个神奇的XML文件,能够找到图像中所有人脸,是不是非常神奇?这其实就是一个Adaboost级联分类器的经典实现:但是当你希望 ...

  2. 北航孙钰:昆虫目标检测技术

    2020-05-07 12:36:00 不到现场,照样看最干货的学术报告! 嗨,大家好.这里是学术报告专栏,读芯术小编不定期挑选并亲自跑会,为大家奉献科技领域最优秀的学术报告,为同学们记录报告干货,并 ...

  3. 目标检测技术演化:从R-CNN到Faster R-CNN

    摘要: 一文了解目标检测技术发展,不要错过哟. 目标检测旨在准确地找到给定图片中物体的位置,并将其正确分类.准确地来讲,目标检测需要确定目标是什么以及对其定位. 然而,想要解决这个问题并不容易.因为, ...

  4. 树莓派摄像头 C++ OpenCV YoloV3 实现实时目标检测

    树莓派摄像头 C++ OpenCV YoloV3 实现实时目标检测 本文将实现树莓派摄像头 C++ OpenCV YoloV3 实现实时目标检测,我们会先实现树莓派对视频文件的逐帧检测来验证算法流程, ...

  5. 基于深度学习的目标检测技术演进:从目标检测到人脸检测

    本篇博客主要转载两篇写得好的分别介绍基于深度学习的目标检测和人脸检测的文章,最近在调研基于深度学习的人脸检测相关的文章,在网上查相关资料时,有幸看到.文末附带基于深度学习的目标检测和人脸检测相关经典文 ...

  6. 复杂动背景下的“低小慢”目标检测技术

    复杂动背景下的"低小慢"目标检测技术,论文阅读和复现代码 本文的目的是要检测低空中的慢速目标,我复现了本文算法(修正了一些模块),下面给出复现的细节. 视觉显著性模型 视觉显著性反 ...

  7. 对象检测目标小用什么模型好_小目标检测技术分析

    小目标检测技术分析 小目标检测及跟踪系统分为四个模块: · 硬件模块 该模块基于标准PCI总线,并配以超大规模可编程芯片(DSP.FPGA),具有极强的运算.处理能力. · DSP 程序模块 其功能主 ...

  8. 自动驾驶采标系列三:基于图像的目标检测技术

        标注猿的第54篇原创        一个用数据视角看AI世界的标注猿    上一篇文章我们从"环境感知"数据的采集设备上进行了详细说明,已经了解了相应设备采集的数据及采集前 ...

  9. 基于深度学习的高分辨率遥感图像目标检测技术目前的研究现状

    参考   基于深度学习的高分辨率遥感图像目标检测技术目前的研究现状 - 云+社区 - 腾讯云 目录 一.概述 二.通用目标检测方法 1.类不平衡问题 2.复杂背景 3.目标的尺度变化 4.特殊视角 5 ...

最新文章

  1. Linux下vi编辑器命令精华版
  2. 【有上下界网络流】【ZOJ】2314 Reactor Cooling
  3. DebugView调试C#程序 学习总结
  4. 数学知识点大集合!有了它学数学真的很简单!
  5. 数据结构之栈对逆BoLand表达式的计算
  6. 使用webpack打包ES6代码
  7. Day7--误差反向传播
  8. EBSD Channel5软件
  9. win10系统如何查询本机的IP地址和外网IP地址
  10. 【机器学习】Sklearn-cluster聚类方法
  11. 手机更新显示itunes store无法连接服务器,iPhone无法连接App Store、iTunes Store?解决方法有哪些?...
  12. 如何创建数据透视表的方法
  13. TOM邮箱布局商务市场,致力打造更全能的邮箱办公产品!
  14. 北京住房公积金转杭州相关信息的整理,个人整理
  15. 关于讯飞语音SDK开发学习
  16. ELK实践(一)使用es搭建商品搜索项目
  17. 中国49城市智慧程度排行榜:新一线城市武汉和杭州靠前
  18. C++11新特性 R字符串
  19. Java实现序列化机制
  20. 苹果cms提示没有权限解决方法

热门文章

  1. mysql配合memcache部署_Docker多容器配合实现开发环境(nginx、php、memcached、mysql)...
  2. android tabhost 生命周期,FragmentTabHost + FragmentLayout布局框架,Fragment生命周期
  3. [Git] 关于refs/for/ 和refs/heads/
  4. MongoDB索引概念及使用详解
  5. java窗体程序秒表,帮忙解释一个Java小程序(秒表)
  6. 快速删除大文件 多级目录 同步并删除 rsync
  7. 平方根升余弦滚降滤波器matlab函数,平方根升余弦滚降数字滤波器的设计和实现.pdf...
  8. bilstmcrf词性标注_深度学习--biLSTM_CRF 命名实体识别
  9. 开始使用windows live writer写博客。
  10. 保护你的眼睛,把电脑屏幕由白色改为淡绿