Haar特征原理綜述
Haar特征是一種反映圖像的灰度變化的,像素分模塊求差值的一種特征。它分為三類:邊緣特征、線性特征、中心特征和對角線特征。如下所示:
Haar-like矩形特征拓展
Lienhart R.等對Haar-like矩形特征庫作了進一步擴展,加入了旋轉45。角的矩形特征。擴展后的特征大致分為4種類型:邊緣特征、線特征環、中心環繞特征和對角線特征:
可是這些所謂的特征不就是一堆堆帶條紋的矩形么,到底是干什么用的?我的理解是,將上面的任意一個矩形放到人臉區域上,然后,將白色區域的像素和減去黑色區域的像素和,得到的值我們暫且稱之為人臉特征值,如果你把這個矩形放到一個非人臉區域,那么計算出的特征值應該和人臉特征值是不一樣的,而且越不一樣越好,所以這些方塊的目的就是把人臉特征量化,以區分人臉和非人臉。
用黑白兩種矩形框組合成特征模板,在特征模板內用 黑色矩形像素和 減去 白色矩形像素和來表示這個模版的特征值。例如:臉部的一些特征能由矩形模塊差值特征簡單的描述,如:眼睛要比臉頰顏色要深,鼻梁兩側比鼻梁顏色要深,嘴巴比周圍顏色要深等。但矩形特征只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述在特定方向(水平、垂直、對角)上有明顯像素模塊梯度變化的圖像結構。
如上圖A、B、D模塊的圖像Haar特征為:v=Sum白-Sum黑
C 模塊的圖像Haar特征為:v=Sum白(左)+Sum白(右)-2*Sum黑
這里要保證白色矩形模塊中的像素與黑色矩形的模塊的像素數相同,所以乘2
對於一幅圖像來說,可以通過通過改變特征模板的大小和位置,可窮舉出大量的特征來表示一幅圖像。上圖的特征模板稱為“特征原型”;特征原型在圖像子窗口中擴展(平移伸縮)得到的特征稱為“矩形特征”;矩形特征的值稱為“特征值”。例如在24*24大小的圖像中可以以坐標(0,0)開始寬為20高為20矩形模版計算上圖A特征,也可以以坐標(0,2)開始寬為20高為20矩形模版計算上圖A特征,也可以以坐標(0,0)開始寬為22高為22矩形模版計算上圖A特征,這樣矩形特征值隨着類別、大小和位置的變化,使得很小的一幅很小的圖像含有非常多的矩形特征。矩形特征值是矩形模版類別、矩形位置和矩形大小這三個因素的函數。
總結來說,
特征 = 某個區域的像素點經過某種四則運算之后得到的結果。
這個結果可以是一個具體的值也可以是一個向量,矩陣,多維。實際上就是矩陣運算
使用特征可以識別一張圖片里有沒有人臉,人臉上五官的位置。
haar特征的計算(積分圖法):
首先要解決一個問題,什么是積分圖?
積分圖就是只遍歷一次圖像就可以求出圖像中所有區域像素和的快速算法,大大的提高了圖像特征值計算的效率。
積分圖主要的思想是將圖像從起點開始到各個點所形成的矩形區域像素之和作為一個數組的元素保存在內存中,當要計算某個區域的像素和時可以直接索引數組的元素,不用重新計算這個區域的像素和,從而加快了計算(這有個相應的稱呼,叫做動態規划算法)。積分圖能夠在多種尺度下,使用相同的時間(常數時間)來計算不同的特征,因此大大提高了檢測速度。
我們來看看它是怎么做到的。
積分圖是一種能夠描述全局信息的矩陣表示方法。積分圖的構造方式是位置(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就構造好了。
積分圖構造好之后,圖像中任何矩陣區域的像素累加和都可以通過簡單運算得到如圖所示。
公式:Sum(D)=ii(x4,y4)−ii(x2,y2)−ii(x3,y3)+ii(x1,y1)
了解了原理及算法,接下來就是如何利用haar特征實現人臉檢測了。
opencv里面提供了Haar特征分類器。Haar特征分類器說白了就是一個個的xml文件,不同的xml里面描述人體各個部位的特征值,比如人臉、眼睛等等。OpenCV4.2.0中提供了如下特征文件:
通過加載不同的特征文件,就能達到相應的檢測效果。
OpenCV4.2.0中detectMultiScale函數參數說明:
detectMultiScale(Mat image, MatOfRect objects, double scaleFactor, int minNeighbors, int flags, Size minSize, Size maxSize)
image:待檢測圖片,一般為灰度圖(提高效率)
objects:被檢測物體的矩形框向量組
scaleFactor:前后兩次相繼的掃描中,搜索窗口的比例系數。默認為1.1即每次搜索窗口依次擴大10%
minNeighbors:構成檢測目標的相鄰矩形的最小個數(默認為3個)
flags:要么使用默認值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果設置為CV_HAAR_DO_CANNY_PRUNING,那么函數將會使用Canny邊緣檢測來排除邊緣過多或過少的區域,因此這些區域通常不會是人臉所在區域
minSize:得到的目標區域的最小范圍
maxSize:得到的目標區域的最大范圍
java實現代碼如下:
package part; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Point; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; import org.opencv.objdetect.CascadeClassifier; public class HaarFaceDetect { public static void main(String[] args) { // TODO Auto-generated method stub System.loadLibrary(Core.NATIVE_LIBRARY_NAME); System.out.println("\nRunning FaceDetector"); CascadeClassifier faceDetector = new CascadeClassifier(); faceDetector.load( //這里是你opencv的安裝地址 "D:\\opencv\\windows\\opencv4.2.0\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml"); Mat image = Imgcodecs.imread("./data/facedetect.jpg"); MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale(image, faceDetections); System.out.println(String.format("Detected %s faces", faceDetections.toArray().length)); for (Rect rect : faceDetections.toArray()) { Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0)); } String filename = "./data/facedetect_2.jpg"; Imgcodecs.imwrite(filename, image); } }
效果展示:
原圖
效果圖
可以看到效果還不錯,但是還是有瑕疵的,並不是百分之百識別。
參考資料:https://blog.csdn.net/u012507022/article/details/54138299