圖像特征提取之Haar特征


1、Haar-like特征

       Haar-like特征最早是由Papageorgiou等應用於人臉表示,Viola和Jones在此基礎上,使用3種類型4種形式的特征。

Haar特征分為三類:邊緣特征、線性特征、中心特征和對角線特征,組合成特征模板。特征模板內有白色和黑色兩種矩形,並定義該模板的特征值為白色矩形像素和減去黑色矩形像素和。Haar特征值反映了圖像的灰度變化情況。例如:臉部的一些特征能由矩形特征簡單的描述,如:眼睛要比臉頰顏色要深,鼻梁兩側比鼻梁顏色要深,嘴巴比周圍顏色要深等。但矩形特征只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述特定走向(水平、垂直、對角)的結構。

 

 

     對於圖中的A, B和D這類特征,特征數值計算公式為:v=Sum白-Sum黑,而對於C來說,計算公式如下:v=Sum白-2*Sum黑;之所以將黑色區域像素和乘以2,是為了使兩種矩形區域中像素數目一致。

     通過改變特征模板的大小和位置,可在圖像子窗口中窮舉出大量的特征。上圖的特征模板稱為“特征原型”;特征原型在圖像子窗口中擴展(平移伸縮)得到的特征稱為“矩形特征”;矩形特征的值稱為“特征值”。

      矩形特征可位於圖像任意位置,大小也可以任意改變,所以矩形特征值是矩形模版類別、矩形位置和矩形大小這三個因素的函數。故類別、大小和位置的變化,使得很小的檢測窗口含有非常多的矩形特征,如:在24*24像素大小的檢測窗口內矩形特征數量可以達到16萬個。這樣就有兩個問題需要解決了:(1)如何快速計算那么多的特征?---積分圖大顯神通;(2)哪些矩形特征才是對分類器分類最有效的?---如通過AdaBoost算法來訓練:https://www.cnblogs.com/henuliulei/p/10719208.html

 

2、Haar-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就構造好了。

積分圖構造好之后,圖像中任何矩陣區域的像素累加和都可以通過簡單運算得到如圖所示。

          

 

設D的四個頂點分別為α、β、γ、δ,則D的像素和可以表示為

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

        而Haar-like特征值無非就是兩個矩陣像素和的差,同樣可以在常數時間內完成。所以矩形特征的特征值計算,只與此特征矩形的端點的積分圖有關,所以不管此特征矩形的尺度變換如何,特征值的計算所消耗的時間都是常量。這樣只要遍歷圖像一次,就可以求得所有子窗口的特征值。

 這個鏈接里的文件實現了對每個像素的haar特征值的計算:https://files.cnblogs.com/files/henuliulei/ConsoleApplication2.7z

3、Haar-like矩形特征拓展

         Lienhart R.等對Haar-like矩形特征庫作了進一步擴展,加入了旋轉45角的矩形特征。擴展后的特征大致分為4種類型:邊緣特征、線特征環、中心環繞特征和對角線特征:

 

      

在特征值的計算過程中,黑色區域的權值為負值,白色區域的權值為正值。而且權值與矩形面積成反比(使兩種矩形區域中像素數目一致);

積分圖構建算法:
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就構造好了。

如下圖:

Sum(D)=ii(x4,y4)−ii(x2,y2)−ii(x3,y3)+ii(x1,y1)

 

利用opencv自帶的基於haar特征的人臉識別的xml文件識別人臉代碼

 1 #include<iostream>
 2 #include<stdio.h>
 3 //#include<pch.h>
 4 #include<opencv2/opencv.hpp>
 5 #include<opencv2/highgui/highgui.hpp>
 6 #include<opencv2/imgproc/imgproc.hpp>
 7 #include "opencv2/core/core.hpp"
 8 #include <opencv2\imgproc\types_c.h>
 9 
10 using namespace cv;
11 using namespace std;
12 
13 #define W 1920
14 #define H 1080
15 
16 string face_cascade_name = "F:\\OpenCV\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml";//此處只檢測到了臉,檢測其他器官可以添加其他的分類器
17 CascadeClassifier face_cascade;
18 int facesnum = 0;
19 void DectectorAndDis(Mat frame)
20 {
21     Mat face_gray = Mat::zeros(H, W, CV_8UC3);
22     vector<Rect> faces;
23     cvtColor(frame, face_gray, CV_BGR2GRAY);//RGB轉化為灰度
24     equalizeHist(face_gray, face_gray);//直方圖均衡化
25     face_cascade.detectMultiScale(face_gray, faces, 1.75, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
26     for (int i = 0; i < faces.size(); i++) {
27         Point CvBox2D(int(faces[i].x + faces[i].width*0.5), int(faces[i].y + faces[i].height*0.5));
28         ellipse(frame, CvBox2D, Size(int(faces[i].width*0.5), int(faces[i].height*0.5)), 0, 0, 360, Scalar(255, 0, 0), 4, 8, 0);
29     }
30     if (facesnum != faces.size())
31     {
32         cout << "人臉數:" << faces.size() << endl;
33         facesnum = faces.size();
34     }
35 
36     imshow("讀取視頻", frame);
37 }
38 int main(int argc, char* argv[])
39 {
40     ///cv::Mat test  = cv::imread("E:/code/Myprojects/ConsoleApplication1/test.jpg",0);
41     //cv::Mat test1;
42     //resize(test, test, Size(W, H));
43     //imshow("test", test);
44     //cv::Canny(test, test1, 1, 3, 3);
45     //imshow("test1", test1);
46     //test.convertTo(test, CV_32SC1);
47 
48     VideoCapture capture;
49     capture.open(0);
50 
51     Mat frame = Mat::zeros(H, W, CV_8UC3);
52     Mat frameaftcanny = Mat::zeros(H, W, CV_8UC3);
53     face_cascade.load(face_cascade_name);
54     while (1)
55     {
56         capture >> frame;
57 
58         //cv::Canny(frame, frameaftcanny, 100, 300, 3);
59         //imshow("邊緣檢測", frameaftcanny);
60         DectectorAndDis(frame);
61         cv::waitKey(50);
62     }
63     waitKey(0);
64     return 0;
65 }

 

referencehttps://blog.csdn.net/zylxadz/article/details/46602263

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM