这种以Boxfilter替代integral image 的方法很难使用到haar、LBP等特征检测中,因为像下面说的,它不支持多尺度,也就是说所提取的特征必须是同一个大小,最起码同一个宽高比的,这一点对宽高不定的haar特征、LBP特征都有很大的限制,但对于HOG特征因为尺度不像另外两个那样灵活,还是有迹可循的。采长补短

申明:以下非笔者原创,原文转载自:http://www.cnblogs.com/easymind223/archive/2012/11/13/2768680.html

这个项目大概是在2年前了,因为要用嵌入式编程,所以无法用opencv的库函数,一切算法纯靠手写(是不是很坑爹?),其中一部分程序需要计算Haar特征,于是就有了下面的故事:

  在模式识别领域,Haar特征是大家非常熟悉的一种图像特征了,它可以应用于许多目标检测的算法中。与Haar相似,图像的局部矩形内像素的和、平方和、均值、方差等特征也可以用类似Haar特征的计算方法来计算。这些特征有时会频繁的在某些算法中使用,因此对它的优化势在必行。Boxfilter就是这样一种优化方法,它可以使复杂度为O(MN)的求和,求方差等运算降低到O(1)或近似于O(1)的复杂度,它的缺点是不支持多尺度

  第一个提出Haar特征快速计算方法的是CVPR2001上的那篇经典论文Rapid Object Detection using a Boosted Cascade of Simple Features ,它提出了integral image的概念,这个方法使得图像的局部矩形求和运算的复杂度从O(MN)下降到了O(4)。它的原理很简单:首先建立一个数组A,宽高与原图像相等,然后对这个数组赋值,每个元素的值A[i]赋为该点与图像原点所构成的矩形中所有像素的和。初始化之后,想要计算某个矩形像素和的时候可以采用如下方法:如图D矩形的像素和就等于A[4]
– A[2] – A[3] + A[1],共4次运算,即O(4)。Integral Image极大的提高了Haar特征的计算速度,它的优点在于能够快速计算任意大小的矩形求和运算。

  Boxfilter的原理有点类似Integral Image,而且比它还要快,但是实现步骤比较复杂。在计算矩形特征之前,Boxfilter与Integral Image都需要对图像进行初始化(即对数组A赋值),不同于Integral Image, Boxfilter的数组A中的每个元素的值是该像素邻域内的像素和(或像素平方和),在需要求某个矩形内像素和的时候,直接访问数组中对应的位置就可以了。因此可以看出它的复杂度是O(1)。

Boxfilter的初始化过程如下:(此处较繁琐,如睡意来袭可以略过)

1、给定一张图像,宽高为(M,N),确定待求矩形模板的宽高(m,n),如图紫色矩形。图中每个黑色方块代表一个像素,红色方块是假想像素。

2、开辟一段大小为M的数组,记为buff, 用来存储计算过程的中间变量,用红色方块表示

3、将矩形模板(紫色)从左上角(0,0)开始,逐像素向右滑动,到达行末时,矩形移动到下一行的开头(0,1),如此反复,每移动到一个新位置时,计算矩形内的像素和,保存在数组A中。以(0,0)位置为例进行说明:首先将绿色矩形内的每一列像素求和,结果放在buff内(红色方块),再对蓝色矩形内的像素求和,结果即为紫色特征矩形内的像素和,把它存放到数组A中,如此便完成了第一次求和运算。

4、每次紫色矩形向右移动时,实际上就是求对应的蓝色矩形的像素和,此时只要把上一次的求和结果减去蓝色矩形内的第一个红色块,再加上它右面的一个红色块,就是当前位置的和了,用公式表示 sum[i] = sum[i-1] - buff[x-1] + buff[x+m-1]

5、当紫色矩形移动到行末时,需要对buff进行更新。因为整个绿色矩形下移了一个像素,所以对于每个buff[i], 需要加上一个新进来的像素,再减去一个出去的像素,然后便开始新的一行的计算了。

  Boxfilter的初始化过程非常快速,每个矩形的计算基本上只需要一加一减两次运算。从初始化的计算速度上来说,Boxfilter比Integral Image要快一些,大约25%。在具体求某个矩形特征时,Boxfilter比Integral Image快4倍,所谓的4倍其实就是从4次加减运算降低到1次,虽然这个优化非常渺小,但是把它放到几层大循环里面,还是能节省一些时间的。对于那些实时跟踪检测算法,一帧的处理时间要严格在40ms以下,正是这些细小的优化决定了程序的效率,积少成多,聚沙成塔。

下面的程序是Boxfilter的示例代码,谨供参考

.h

#pragma once

typedef unsigned char uchar;

class Boxfilter
{
public:
Boxfilter(void);
~Boxfilter(void); void init(int width, int height, int mwidth=5, int mheight=5);
void boxfilter(unsigned char* img);
public:
float getMean(int x, int y); //以x,y为中心点,mwidth,mheight为直径的局部区域,下同
float getVar(int x, int y);
int getSum(int x, int y);
int getSquareSum(int x, int y);
int getLocalSize(); private:
int mwidth ;
int mheight ;
unsigned char* img;
int width;
int height;
int* f_sum;
int* f_sum2; };

.cpp

#include "Boxfilter.h"
#include <assert.h>
#include <string> int* buff = 0;
int* buff2 = 0;
int boxwidth;
int boxheight; Boxfilter::Boxfilter(void)
{
f_sum = 0;
f_sum2 = 0;
} Boxfilter::~Boxfilter(void)
{
if(f_sum) delete[] f_sum;
if(f_sum2) delete[] f_sum2;
if(buff) delete[] buff;
if(buff2) delete[] buff2;
} void Boxfilter::init(int width, int height, int mwidth, int mheight)
{
this->mwidth = mwidth;
this->mheight = mheight;
this->width = width;
this->height = height; boxwidth = width - mwidth;
boxheight = height - mheight;
f_sum = new int[boxwidth *boxheight];
f_sum2 = new int[boxwidth *boxheight]; buff = new int[width];
buff2= new int[width];
} void Boxfilter::boxfilter (unsigned char* img)
{
int j,x,y; memset(buff, 0, width *sizeof(int));
memset(buff2, 0, width *sizeof(int));
memset(f_sum, 0, boxwidth *boxheight);
memset(f_sum2, 0, boxwidth *boxheight); for(y=0; y<mheight; y++)
{
for(x=0; x<width; x++)
{
uchar pixel = img[y *width + x];
buff[x] += pixel;
buff2[x] += pixel*pixel;
}
} for(y=0; y<height - mheight;y++)
{
int Xsum=0;
int Xsum2=0; for(j=0; j<mwidth; j++)
{
Xsum += buff[j];
Xsum2 += buff2[j];
} for(x=0; x<width - mwidth; x++)
{
if(x!=0)
{
Xsum = Xsum-buff[x-1]+buff[mwidth-1+x];
Xsum2 = Xsum2-buff2[x-1]+buff2[mwidth-1+x];
}
f_sum[y*(width - mwidth)+x] = (float) Xsum ;
f_sum2[y*(width - mwidth)+x] = Xsum2;
} for(x=0; x<width; x++)
{
uchar pixel = img[y *width + x];
uchar pixel2 = img[(y+mheight) *width + x];
buff[x] = buff[x] - pixel + pixel2;
buff2[x] = buff2[x] - pixel*pixel + pixel2*pixel2;
}
}
} float Boxfilter::getMean(int x, int y)
{
return getSum(x,y) / (float)(mwidth*mheight);
} float Boxfilter::getVar(int x, int y)
{
float mean = getMean(x, y);
return (float)getSquareSum(x, y)/(mwidth *mheight) - mean*mean;
} int Boxfilter::getSquareSum(int x, int y)
{
if(y>mheight/2 && y<height - mheight/2 && x>mwidth/2 && x<width - mwidth/2)
return f_sum2[(y - mheight/2) *boxwidth + (x - mwidth/2)];
else
return -1;
} int Boxfilter::getSum(int x, int y)
{
if(y>mheight/2 && y<height - mheight/2 && x>mwidth/2 && x<width - mwidth/2)
return f_sum[(y - mheight/2) *boxwidth + (x - mwidth/2)];
else
return -1;
} int Boxfilter::getLocalSize()
{
return mwidth > mheight ? mwidth : mheight;
}

测试用例

// cv2.4 test.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "Boxfilter.h"
#include <iostream>
using namespace cv;
using namespace std; int _tmain(int argc, _TCHAR* argv[])
{
Mat src = imread("C:\\Documents and Settings\\Administrator\\桌面\\img1.png",0); Boxfilter box;
box.init(src.cols, src.rows, 5, 5);
box.boxfilter((uchar*)src.data); int x = 50, y = 50;
float a = box.getMean(x, y); //求出以(x,y)为中心的矩形的均值
float b = box.getVar(x, y);
int c = box.getSum(x, y);
int d = box.getSquareSum(x, y);
int e = box.getLocalSize(); cout<<"mean: " <<a<<endl;
cout<<"var: " <<b<<endl;
cout<<"sum: " <<c<<endl;
cout<<"squaresum: " <<d<<endl;
cout<<"size: " <<e<<endl; getchar();
return 0;
}

【计算机视觉】极限优化:Haar特征的另一种的快速计算方法—boxfilter的更多相关文章

  1. 图像特征提取三大法宝:HOG特征,LBP特征,Haar特征(转载)

    (一)HOG特征 1.HOG特征: 方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子.它通过计算和 ...

  2. 图像特征提取三大法宝:HOG特征,LBP特征,Haar特征

    (一)HOG特征 1.HOG特征: 方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子.它通过计算和 ...

  3. [CV笔记]图像特征提取三大法宝:HOG特征,LBP特征,Haar特征

    (一)HOG特征 1.HOG特征: 方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子.它通过计算和 ...

  4. Haar特征

    转自:http://blog.csdn.net/carson2005/article/details/8094699 Haar-like特征,即很多人常说的Haar特征,是计算机视觉领域一种常用的特征 ...

  5. web前端图片极限优化策略

    随着web的发展,网站资源的流量也变得越来越大.据统计,60%的网站流量均来自网站图片,可见对图片合理优化可以大幅影响网站流量,减小带宽消耗和服务器压力. 一.现有web图片格式 我们先来看下现在常用 ...

  6. iOS图片加载速度极限优化—FastImageCache解析

    FastImageCache是Path团队开发的一个开源库,用于提升图片的加载和渲染速度,让基于图片的列表滑动 优化点 iOS从磁盘加载一张图片,使用UIImageVIew显示在屏幕上,需要经过以下步 ...

  7. 目标检测的图像特征提取之(三)Haar特征

    1.Haar-like特征 Haar-like特征最早是由Papageorgiou等应用于人脸表示,Viola和Jones在此基础上,使用3种类型4种形式的特征. Haar特征分为三类:边缘特征.线性 ...

  8. AdaBoost中利用Haar特征进行人脸识别算法分析与总结1——Haar特征与积分图

    原地址:http://blog.csdn.net/watkinsong/article/details/7631241 目前因为做人脸识别的一个小项目,用到了AdaBoost的人脸识别算法,因为在网上 ...

  9. 基于Haar特征Adaboost人脸检测级联分类

    基于Haar特征Adaboost人脸检测级联分类 基于Haar特征Adaboost人脸检测级联分类,称haar分类器. 通过这个算法的名字,我们能够看到这个算法事实上包括了几个关键点:Haar特征.A ...

随机推荐

  1. ACM-ICPC 2017 南宁赛区现场赛 M. The Maximum Unreachable Node Set(二分图)

    题目链接:https://nanti.jisuanke.com/t/19979 题意:给出一个 n 个点,m 条边的 DAG,选出最大的子集使得其中结点两两不能到达. 题解:参考自:https://b ...

  2. excel操作之poi-ooxml

    目前市场上流行的对于excel处理的框架大致有两种:poi和jxl.对于这两种框架,我们可以做一个简单的对比:   1 开发团队:poi是Apache旗下的一个开源项目,由Apache官方维护,jxl ...

  3. HTTP 协议讲解

    http请求由三部分组成,分别是:请求行.消息报头.请求正文 HTTP(超文本传输协议)是一个基于请求与响应模式的.无状态的.应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接 ...

  4. python基于opencv实现人脸定位

    import cv2 # 读取图片 img = cv2.imread("image.jpg") # 加载模型,模型可以从https://github.com/opencv/open ...

  5. Eclipse 导入项目

  6. Codeforces 576D Flights for Regular Customers (图论、矩阵乘法、Bitset)

    题目链接 http://codeforces.com/contest/576/problem/D 题解 把边按\(t_i\)从小到大排序后枚举\(i\), 求出按前\((i-1)\)条边走\(t_i\ ...

  7. [NOIP2018]:旅行(数据加强版)(基环树+搜索+乱搞)

    题目描述 小$Y$是一个爱好旅行的$OIer$.她来到$X$国,打算将各个城市都玩一遍.小$Y$了解到,$X$国的$n$个城市之间有$m$条双向道路.每条双向道路连接两个城市.不存在两条连接同一对城市 ...

  8. java实现二维码的生成与解析

    简单介绍下二维码:二维码其实就是一种编码技术,只是这种编码技术是用在图片上了,将给定的一些文字,数字转换为一张经过特定编码的图片,而解析二维码则相反,就是将一张经过编码的图片解析为数字或者文字. 当然 ...

  9. Nginx-HTTP之ngx_http_top_body_filter

    1. ngx_http_top_body_filter 该链表用于构造响应消息的响应正文. 大致有以下模块在该链表中插入了自己的函数: ngx_http_range_filter_module: ng ...

  10. koa 实现上传文件

    项目目录: 1.上传单个文件 思路: (1)获取上传文件,使用 const file = ctx.request.files.file (2)我们使用 fs.createReadStream 来读取文 ...