目标检测的图像特征提取—Haar特征

2024-06-17 04:08

本文主要是介绍目标检测的图像特征提取—Haar特征,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1Haar-like特征

       Haar-like特征最早是由Papageorgiou等应用于人脸表示,ViolaJones在此基础上,使用3种类型4种形式的特征。

Haar特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模板。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素和减去黑色矩形像素和。Haar特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。

     对于图中的A, BD这类特征,特征数值计算公式为:v=Sum-Sum黑,而对于C来说,计算公式如下:v=Sum-2*Sum黑;之所以将黑色区域像素和乘以2,是为了使两种矩形区域中像素数目一致。

     通过改变特征模板的大小和位置,可在图像子窗口中穷举出大量的特征。上图的特征模板称为“特征原型”;特征原型在图像子窗口中扩展(平移伸缩)得到的特征称为“矩形特征”;矩形特征的值称为“特征值”。

      矩形特征可位于图像任意位置,大小也可以任意改变,所以矩形特征值是矩形模版类别、矩形位置和矩形大小这三个因素的函数。故类别、大小和位置的变化,使得很小的检测窗口含有非常多的矩形特征,如:在24*24像素大小的检测窗口内矩形特征数量可以达到16万个。这样就有两个问题需要解决了:(1)如何快速计算那么多的特征?---积分图大显神通;(2)哪些矩形特征才是对分类器分类最有效的?---如通过AdaBoost算法来训练(这一块这里不讨论,具体见http://blog.csdn.net/zouxy09/article/details/7922923

 

2Haar-like特征的计算积分图

       积分图就是只遍历一次图像就可以求出图像中所有区域像素和的快速算法,大大的提高了图像特征值计算的效率。

       积分图主要的思想是将图像从起点开始到各个点所形成的矩形区域像素之和作为一个数组的元素保存在内存中,当要计算某个区域的像素和时可以直接索引数组的元素,不用重新计算这个区域的像素和,从而加快了计算(这有个相应的称呼,叫做动态规划算法)。积分图能够在多种尺度下,使用相同的时间(常数时间)来计算不同的特征,因此大大提高了检测速度。

       我们来看看它是怎么做到的。

       积分图是一种能够描述全局信息的矩阵表示方法。积分图的构造方式是位置(i,j)处的值ii(i,j)是原图像(i,j)左上角方向所有像素的和:

  

        

积分图构建算法:

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就构造好了。     

    任意矩形区域内像素积分。由图像的积分图可方便快速地计算图像中任意矩形内所有像素灰度积分。如下图2.3所示,点1的积分图像ii1的值为(其中Sum为求和) : ii1=Sum(A)

    [转载]Haar-like矩形特征的特征值的快速计算方法

    同理,点2、点3、点4的积分图像分别为:

    ii2=Sum(A)+Sum(B);      ii3=Sum(A)+Sum(C);    ii4=Sum(A)+Sum(B)+Sum(C)+Sum(D);

    矩形区域D内的所有像素灰度积分可由矩形端点的积分图像值得到:

                     Sum(D)=ii1+ii4-(ii2+ii3)            (1)
    (2) 特征值计算
    矩形特征的特征值是两个不同的矩形区域像素和之差,由(1)式可以计算任意矩形特征的特征值,下面以图2.1中特征原型A为例说明特征值的计算。

    [转载]Haar-like矩形特征的特征值的快速计算方法

    如图2.4 所示,该特征原型的特征值定义为:

    Sum(A)-Sum(B)

    根据(1)式则有:Sum(A)=ii4+ii1-(ii2+ii3);    Sum(B)=ii6+ii3-(ii4+ii5);

    所以此类特征原型的特征值为:

                 (ii4-ii3)-(ii2-ii1)+(ii4-ii3)-(ii6-ii5)

    另示:运用积分图可以快速计算给定的矩形之所有象素值之和Sum(r)。假设r=(x,y,w,h),那么此矩形内部所有元素之和等价于下面积分图中下面这个式子:

                 Sum(r) = ii(x+w,y+h)+ii(x-1,y-1)-ii(x+w,y-1)-ii(x-1,y+h)


    Haar-like特征值无非就是两个矩阵像素和的差,同样可以在常数时间内完成。所以矩形特征的特征值计算,只与此特征矩形的端点的积分图有关,所以不管此特征矩形的尺度变换如何,特征值的计算所消耗的时间都是常量。这样只要遍历图像一次,就可以求得所有子窗口的特征值。

3Haar-like矩形特征拓展

         Lienhart R.等对Haar-like矩形特征库作了进一步扩展,加入了旋转45角的矩形特征。扩展后的特征大致分为4种类型:边缘特征、线特征环、中心环绕特征和对角线特征:

       在特征值的计算过程中,黑色区域的权值为负值,白色区域的权值为正值。而且权值与矩形面积成反比(使两种矩形区域中像素数目一致);

竖直矩阵特征值计算:

     对于竖直矩阵,与上面2处说的一样。

45°旋角的矩形特征计算:

      对于45°旋角的矩形,我们定义RSAT(x,y)为点(x,y)左上角45°区域和左下角45°区域的像素和。

       

用公式可以表示为:

为了节约时间,减少重复计算,可按如下递推公式计算:

而计算矩阵特征的特征值,是位于十字行矩形RSAT(x,y)之差。可参考下图:


4代码实现

   这里我是在一副灰度图像内随便选取一个框,计算其haar特征,当然具体应用时由于haar特征对于人脸检测效果尤其好,感兴趣的朋友可以把程序进行更改,加入手动画框模块,读取视频,计算得到每帧目标框内的特征值。


main函数:
//  main.cpp  
//  HaarFeature  #include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  #include "HaarFeature.h"  using namespace cv;  
using namespace std;  const int featureNUM=192;  int main()  
{  Mat image=imread("lena.bmp");  //cvtColor(image,image,CV_RGB2GRAY);  if (image.empty())  {  cout<<"Load the image error!"<<endl;  return -1;  }  vector<HaarFeature> m_features;     //用于生成特征模板  float x[] = {0.2f, 0.4f, 0.6f, 0.8f};  float y[] = {0.2f, 0.4f, 0.6f, 0.8f};  float s[] = {0.2f, 0.4f};  for (int iy = 0; iy < 4; ++iy)  {  for (int ix = 0; ix < 4; ++ix)  {  for (int is = 0; is < 2; ++is)  {  FloatRect r(x[ix]-s[is]/2, y[iy]-s[is]/2, s[is], s[is]);  //32种尺寸  for (int it = 0; it < 6; ++it)        //这里主要实现6种hair特征,32*6=192种特征模板  {  m_features.push_back(HaarFeature(r, it));     }  }  }  }  float m_feat;  FloatRect rect(10,10,100,50);  for(int i=0;i<featureNUM;i++){  m_feat= m_features[i].caluHf(image,rect);   cout<<m_feat<<" "<<endl;    }  return 0;  
}

HaarFeature类:
头文件:
#include <opencv2/opencv.hpp>  
#include <vector>  #include "RECT.h"  using namespace cv;  class HaarFeature  
{  
public:  HaarFeature(FloatRect& bb, int type);  ~HaarFeature();  float caluHf(Mat& _image,FloatRect& _rect);  //计算haar特征值  private:  float sum(Mat& _image,IntRect& _rect);  private:  FloatRect m_box;  std::vector<FloatRect> m_rects;  std::vector<float> m_weights;  float m_factor;  Mat _imageIntegral;  
};  

源文件:
#include "HaarFeature.h"  
#include <iostream>  using namespace std;  HaarFeature::HaarFeature(FloatRect& bb, int type) :  
m_box(bb)  
{  assert(type < 6);    //分别实现六种haar特征,可以参照文章开头时引用的图片进行对应  switch (type)  {  case 0:  {  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin(), bb.Width(), bb.Height()/2));  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin()+bb.Height()/2, bb.Width(), bb.Height()/2));  m_weights.push_back(1.f);  m_weights.push_back(-1.f);  m_factor = 255*1.f/2;  break;  }  case 1:  {  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin(), bb.Width()/2, bb.Height()));  m_rects.push_back(FloatRect(bb.XMin()+bb.Width()/2, bb.YMin(), bb.Width()/2, bb.Height()));  m_weights.push_back(1.f);  m_weights.push_back(-1.f);  m_factor = 255*1.f/2;  break;  }  case 2:  {  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin(), bb.Width()/3, bb.Height()));  m_rects.push_back(FloatRect(bb.XMin()+bb.Width()/3, bb.YMin(), bb.Width()/3, bb.Height()));  m_rects.push_back(FloatRect(bb.XMin()+2*bb.Width()/3, bb.YMin(), bb.Width()/3, bb.Height()));  m_weights.push_back(1.f);  m_weights.push_back(-2.f);  m_weights.push_back(1.f);  m_factor = 255*2.f/3;  break;  }  case 3:  {  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin(), bb.Width(), bb.Height()/3));  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin()+bb.Height()/3, bb.Width(), bb.Height()/3));  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin()+2*bb.Height()/3, bb.Width(), bb.Height()/3));  m_weights.push_back(1.f);  m_weights.push_back(-2.f);  m_weights.push_back(1.f);  m_factor = 255*2.f/3;  break;  }  case 4:  {  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin(), bb.Width()/2, bb.Height()/2));  m_rects.push_back(FloatRect(bb.XMin()+bb.Width()/2, bb.YMin()+bb.Height()/2, bb.Width()/2, bb.Height()/2));  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin()+bb.Height()/2, bb.Width()/2, bb.Height()/2));  m_rects.push_back(FloatRect(bb.XMin()+bb.Width()/2, bb.YMin(), bb.Width()/2, bb.Height()/2));  m_weights.push_back(1.f);  m_weights.push_back(1.f);  m_weights.push_back(-1.f);  m_weights.push_back(-1.f);  m_factor = 255*1.f/2;  break;  }  case 5:  {  m_rects.push_back(FloatRect(bb.XMin(), bb.YMin(), bb.Width(), bb.Height()));  m_rects.push_back(FloatRect(bb.XMin()+bb.Width()/4, bb.YMin()+bb.Height()/4, bb.Width()/2, bb.Height()/2));  m_weights.push_back(1.f);  m_weights.push_back(-4.f);  m_factor = 255*3.f/4;  break;  }                 }  
}  HaarFeature::~HaarFeature()  
{  
}  float HaarFeature::sum(Mat& _image,IntRect& _rect)  
{  int xMin=_rect.XMin();  int yMin=_rect.YMin();  int xMax=_rect.XMin()+_rect.Width();  int yMax=_rect.YMin()+_rect.Height();  int tempValue=0;  tempValue +=    _imageIntegral.at<int>(yMin, xMin) +  _imageIntegral.at<int>(yMax, xMax) -  _imageIntegral.at<int>(yMin, xMax) -  _imageIntegral.at<int>(yMax, xMin);  //cout<<weight<<endl;  //cout<<tempValue<<endl;  return tempValue;  
}  float HaarFeature::caluHf(Mat& _image,FloatRect& _rect)    
{  int value = 0;  integral(_image, _imageIntegral, CV_32F);  //cout<<_imageIntegral<<" "<<endl;  for (int i = 0; i < (int)m_rects.size(); ++i)      //m_rects.size()=2;  {  FloatRect& r = m_rects[i];  IntRect sampleRect((int)(_rect.XMin()+r.XMin()*_rect.Width()+0.5f), (int)(_rect.YMin()+r.YMin()*_rect.Height()+0.5f),  (int)(r.Width()*_rect.Width()), (int)(r.Height()*_rect.Height()));  value +=m_weights[i]*sum(_image,sampleRect);   //sum函数返回的是积分图像对应的数值  }  return value / (m_factor*(_rect.Area())*(m_box.Area()));     
}

    这里大家应该都看到了 HaarFeature类头文件中还加入了一个RECT头文件,这个头文件的作用定义两种矩形框:IntRect和FloatRect。之所以要定义这两种矩形框,是因为我们所选取的用于生成特征模板的矩形框r的值过小(r在main.cpp中),而opencv里自带的rect原型为typedef Rect_ <int> Rect,如果使用它会导致r的值为(0,0,0,0)。

RECT源文件:
#pragma once  #include <iostream>  
#include <algorithm>  template <typename T>  
class Rect  
{  
public:  Rect() :  m_xMin(0),  m_yMin(0),  m_width(0),  m_height(0)  {  }  Rect(T xMin, T yMin, T width, T height) :  m_xMin(xMin),  m_yMin(yMin),  m_width(width),  m_height(height)  {  }  template <typename T2>  Rect(const Rect<T2>& rOther) :  m_xMin((T)rOther.XMin()),  m_yMin((T)rOther.YMin()),  m_width((T)rOther.Width()),  m_height((T)rOther.Height())  {  }  inline T XMin() const { return m_xMin; }  inline T YMin() const { return m_yMin; }  inline T Width() const { return m_width; }  inline T Height() const { return m_height; }  inline T Area() const { return m_width * m_height; }  private:  T m_xMin;  T m_yMin;  T m_width;  T m_height;  
};  typedef Rect<int> IntRect;  
typedef Rect<float> FloatRect;

[1] http://blog.csdn.net/smf0504/article/details/51322255
[2] http://blog.csdn.net/zouxy09/article/details/7929570

这篇关于目标检测的图像特征提取—Haar特征的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1068436

相关文章

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

基于WinForm+Halcon实现图像缩放与交互功能

《基于WinForm+Halcon实现图像缩放与交互功能》本文主要讲述在WinForm中结合Halcon实现图像缩放、平移及实时显示灰度值等交互功能,包括初始化窗口的不同方式,以及通过特定事件添加相应... 目录前言初始化窗口添加图像缩放功能添加图像平移功能添加实时显示灰度值功能示例代码总结最后前言本文将

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

JavaFX应用更新检测功能(在线自动更新方案)

JavaFX开发的桌面应用属于C端,一般来说需要版本检测和自动更新功能,这里记录一下一种版本检测和自动更新的方法。 1. 整体方案 JavaFX.应用版本检测、自动更新主要涉及一下步骤: 读取本地应用版本拉取远程版本并比较两个版本如果需要升级,那么拉取更新历史弹出升级控制窗口用户选择升级时,拉取升级包解压,重启应用用户选择忽略时,本地版本标志为忽略版本用户选择取消时,隐藏升级控制窗口 2.

OmniGlue论文详解(特征匹配)

OmniGlue论文详解(特征匹配) 摘要1. 引言2. 相关工作2.1. 广义局部特征匹配2.2. 稀疏可学习匹配2.3. 半稠密可学习匹配2.4. 与其他图像表示匹配 3. OmniGlue3.1. 模型概述3.2. OmniGlue 细节3.2.1. 特征提取3.2.2. 利用DINOv2构建图形。3.2.3. 信息传播与新的指导3.2.4. 匹配层和损失函数3.2.5. 与Super