<sub id="xzfrn"></sub>
    <form id="xzfrn"><nobr id="xzfrn"></nobr></form>

    <address id="xzfrn"><nobr id="xzfrn"><meter id="xzfrn"></meter></nobr></address>

                  關閉
                  理論原理

                  Viola-jones人臉檢測算法基本原理

                  在計算機視覺領域中,人臉檢測或者物體檢測一直是一個非常受關注的領域,而在人臉檢測中,Viola-Jones人臉檢測算法可以說是非常經典的一個算法,所有從事人臉檢測研究的人,都會熟悉了解這個算法。Viola-Jones算法...

                  admin

                  admin

                  發布于 2021-02-01 閱讀:609

                         在計算機視覺領域中,人臉檢測或者物體檢測一直是一個非常受關注的領域,而在人臉檢測中,Viola-Jones人臉檢測算法可以說是非常經典的一個算法,所有從事人臉檢測研究的人,都會熟悉了解這個算法。Viola-Jones算法在2001年的CVPR上提出,因為其高效而快速的檢測即使到現在也依然被廣泛使用,OpenCV 和 Matlab中都將這個算法寫進了函數庫可以很方便的直接調用。雖然VJ人臉檢測算法最初都是用來檢測正面的人臉圖像,對于側臉圖像的檢測不是很穩健,不過這個算法依然有值得研究的價值。
                  (1) 利用Haar特征描述人臉的共有屬性
                         Haar特征是一種反映圖像的灰度變化的,像素分模塊求差值的一種特征。它分為四類:邊緣特征、線性特征、中心特征和對角線特征。用黑白兩種矩形框組合成特征模板,在特征模板內用黑色矩形像素和減去白色矩形像素和來表示這個模版的特征值。例如:臉部的一些特征能由矩形模塊差值特征簡單的描述,如:眼睛要比臉頰顏色要深,鼻梁兩側比鼻梁顏色要深,嘴巴比周圍顏色要深等。但矩形特征只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述在特定方向(水平、垂直、對角)上有明顯像素模塊梯度變化的圖像結構。
                  圖 1  四種基本的Haar特征
                  (2) 建立積分圖像特征,并且基于積分圖像,快速獲取幾種不同的矩形特征。 
                         對于一幅灰度的圖像,積分圖像中的任意一點(x, y)的值是指從圖像的左上角到這個點的所構成的矩形區域內所有的點的灰度值之和。例如,計算圖中D區域內像素之和sum(D),利用積分圖像可表示如下:
                  sum(D) = sum(A+B+C+D) -sum(A+B)-sum(A+C)+sum(A)
                   
                   
                  圖2  利用積分圖計算s(D)
                  (3) 利用Adaboost算法進行訓練。
                         AdaBoost將一系列的人臉識別弱分類器通過線性組合,構成一個強分類器,如下所示:
                   
                  h(x)是一個強分類器,hj(x)是一個弱分類器,其為一個簡單的閾值函數:
                  &theta;j為閾值,sj&isin;{-1, 1},&alpha;j為權重。
                  對弱分類器和強分類器進行訓練后,即可獲得用于人臉識別的算法模型。
                  (4) 建立級聯分類器。
                         在正常的圖像中,人臉區域只是占了很小的一部分,如果使用所有的特征進行訓練的話,運算量非常大。級聯為了簡化任務,把若干個Adaboost分類器級聯起來,一開始使用少量的特征將大部分的非人臉區域剔除掉,后面再利用更復雜的特征將更復雜的非人臉區域剔除掉。排序原則是簡單的放在前邊(如圖中分類器1),因為通常來說人臉只占一小部分,所以可以很放心地在前幾層分類器就拒絕掉大部分非人臉區域。只要前一級拒絕了,就不在進入下一級分類器,這可以大大提高速度。其本質是一顆退化決策樹。
                  圖3  級聯分類器

                   

                  附:Python調用OpenCV中Viola-jones算法的源代碼:

                  from PyQt5 import QtCore,QtGui,QtWidgets
                  import sys
                  import cv2
                  class Ui_MainWindow(QtWidgets.QWidget):
                      def __init__(self,parent=None):
                          super().__init__(parent)      #父類的構造函數
                          self.timer_camera = QtCore.QTimer()      #定義定時器,用于控制顯示視頻的幀率
                          self.cap = cv2.VideoCapture()      #視頻流
                          self.CAM_NUM = 0      #為0時表示視頻流來自筆記本內置攝像頭
                          self.set_ui()      #初始化程序界面
                          self.slot_init()      #初始化槽函數
                      '''程序界面布局'''
                      def set_ui(self):
                          self.__layout_main = QtWidgets.QHBoxLayout()      #總布局
                          self.__layout_fun_button = QtWidgets.QVBoxLayout()      #按鍵布局
                          self.__layout_data_show = QtWidgets.QVBoxLayout()      #數據(視頻)顯示布局
                          self.button_open_camera = QtWidgets.QPushButton('打開相機')      #建立打開攝像頭的按鍵
                          self.button_close = QtWidgets.QPushButton('退出')      #建立用于退出程序的按鍵
                          self.button_open_camera.setMinimumHeight(50)      #設置按鍵大小
                          self.button_close.setMinimumHeight(50)
                          self.button_close.move(10,100)      #移動按鍵
                          '''信息顯示'''
                          self.label_show_camera = QtWidgets.QLabel()      #定義顯示視頻的Label
                          self.label_show_camera.setFixedSize(641,481)      #給顯示視頻的Label設置大小為641x481
                          '''把按鍵加入到按鍵布局中'''
                          self.__layout_fun_button.addWidget(self.button_open_camera)      #把打開攝像頭的按鍵放到按鍵布局中
                          self.__layout_fun_button.addWidget(self.button_close)      #把退出程序的按鍵放到按鍵布局中
                          '''把某些控件加入到總布局中'''
                          self.__layout_main.addLayout(self.__layout_fun_button)      #把按鍵布局加入到總布局中
                          self.__layout_main.addWidget(self.label_show_camera)      #把用于顯示視頻的Label加入到總布局中
                          '''總布局布置好后就可以把總布局作為參數傳入下面函數'''
                          self.setLayout(self.__layout_main)      #到這步才會顯示所有控件
                      '''初始化所有槽函數'''
                      def slot_init(self):
                          self.button_open_camera.clicked.connect(self.button_open_camera_clicked)      #若該按鍵被點擊,則調用button_open_camera_clicked()
                          self.timer_camera.timeout.connect(self.show_camera)      #若定時器結束,則調用show_camera()
                          self.button_close.clicked.connect(self.close)      #若該按鍵被點擊,則調用close(),注意這個close是父類QtWidgets.QWidget自帶的,會關閉程序
                      '''槽函數之一'''
                      def button_open_camera_clicked(self):
                          if self.timer_camera.isActive() == False:      #若定時器未啟動
                              flag = self.cap.open(self.CAM_NUM)      #參數是0,表示打開筆記本的內置攝像頭,參數是視頻文件路徑則打開視頻
                              if flag == False:      #flag表示open()成不成功
                                  msg = QtWidgets.QMessageBox.warning(self,'warning',"請檢查相機于電腦是否連接正確",buttons=QtWidgets.QMessageBox.Ok)
                              else:
                                  self.timer_camera.start(30)      #定時器開始計時30ms,結果是每過30ms從攝像頭中取一幀顯示
                                  self.button_open_camera.setText('關閉相機')
                          else:
                              self.timer_camera.stop()      #關閉定時器
                              self.cap.release()      #釋放視頻流
                              self.label_show_camera.clear()      #清空視頻顯示區域
                              self.button_open_camera.setText('打開相機')
                      def show_camera(self):
                          flag,self.image = self.cap.read()      #從視頻流中讀取
                          gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
                          xmlfile = r'C:\Users\XXX\AppData\Local\Programs\Python\Python37\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml'
                          face_cascade = cv2.CascadeClassifier(xmlfile)
                          faces = face_cascade.detectMultiScale(
                              gray,
                              scaleFactor=1.15,
                              minNeighbors=5,
                              minSize=(5, 5),
                          )
                          for (x, y, w, h) in faces:
                              cv2.rectangle(self.image, (x, y), (x + w, y + w), (0, 255, 0), 2)
                          show = cv2.resize(self.image,(640,480))      #把讀到的幀的大小重新設置為 640x480
                          show = cv2.cvtColor(show,cv2.COLOR_BGR2RGB)      #視頻色彩轉換回RGB,這樣才是現實的顏色
                          showImage = QtGui.QImage(show.data,show.shape[1],show.shape[0],QtGui.QImage.Format_RGB888)      #把讀取到的視頻數據變成QImage形式
                          self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage))      #往顯示視頻的Label里 顯示QImage
                  if __name__ =='__main__':
                      app = QtWidgets.QApplication(sys.argv)      #固定的,表示程序應用
                      ui = Ui_MainWindow()      #實例化Ui_MainWindow
                      ui.show()      #調用ui的show()以顯示。同樣show()是源于父類QtWidgets.QWidget的
                      sys.exit(app.exec_())      #不加這句,程序界面會一閃而過
                  admin
                  admin

                  他很懶,什么都沒有留下~