利用opencv訓練基於Haar特徵、LBP特徵、Hog特徵的分類器cascade.xml

利用opencv訓練基於Haar特徵、LBP特徵、Hog特徵的分類器cascade.xml


author@jason_ql
http://blog.csdn.net/lql0716


1 利用opencv訓練基於Haar特徵、LBP特徵、Hog特徵的分類器cascade.xml

  • 該訓練是基於adaboost算法訓練的。

  • 工具:
    1、opencv_createsamples.exe
    2、opencv_traincascade.exe

    這兩個exe執行程序的路徑爲:

    C:\opencv\build\x64\vc12\bin

    C:\opencv\build\x86\vc12\bin

    在opencv安裝目錄下查找即可找到

1.1 訓練步驟

  • 1、蒐集正樣本、負樣本

    正樣本:只含有目標的局部圖(若是全圖,則需要把目標截取出來,比如訓練人臉,則把人臉從含有人臉的圖片中截取出來,尺寸要一致),且背景不要太過複雜,灰度圖

    正樣本大小:20*20(一般用於Haar特徵),24*24(LBP特徵)

    正樣本數量:一般大於等於2000

    負樣本:不含目標的任何圖片,灰度圖

    負樣本大小:60*60

    負樣本數量:一般大於等於5000

    :正樣本尺寸越小,訓練的時間越短,但正樣本的尺寸要保證小於負樣本的尺寸

  • 2、在路徑C:\opencv\build\x64\vc12\bin下新建3個文件夾:pos、neg、xml

    pos文件夾:存放正樣本

    neg文件夾:存放負樣本

    xml文件夾:存放訓練的xml格式文件

    此處輸入圖片的描述

    :若使用的是路徑C:\opencv\build\x86\vc12\bin,可能會提示錯誤“Training parameters are loaded from the parameter file in data folder! Please empty the data folder if you want to use your own set of parameters”,若不提示錯誤,使用x86路徑或x64路徑均可。

  • 3、將正樣本、負樣本分別複製到pos文件夾、neg文件夾

  • 4、cmd打開dos命令窗口,進入pos路徑下

    • 輸入以下命令,生成pos.txt
      dir/b >pos.txt

    此處輸入圖片的描述

    • 生成pos.txt後,將png替換爲:
      png 1 0 0 24 24
    • 刪除最後一行的pos.txt

    此處輸入圖片的描述

    此處輸入圖片的描述

  • 5、同樣進入neg路徑下

    • 輸入以下命令,生成neg.txt
      dir/b >neg.txt

    此處輸入圖片的描述

    • 生成neg.txt後,將neg.txt中的圖片名字前面加入路徑:
      neg/
    • 刪除最後一行的neg.txt

    此處輸入圖片的描述

  • 6、進入路徑C:\opencv\build\x64\vc12\bin,即pos、neg、xml所在的路徑,輸入以下命令,生成pos.vec

opencv_createsamples.exe -info pos\pos.txt -vec pos.vec -bg neg\neg.txt -num 2000 -w 24 -h 24
  • 7、輸入以下命令開始訓練
opencv_traincascade.exe -data xml -vec pos.vec -bg neg\neg.txt 
-numPos 1800 -numNeg 4000 -numStages 20 -featureType LBP -w 24 -h 24

-numStages的參數一般默認爲20,最好大於等於20,級數太小的話,訓練的效果較差

  • 1、錯誤提示:
    “Traincascade Error:Bad argument(Can not get new positive sample.The most possible reason is insufficient count of samples in given vec-file.”
    出現這個提示,可能是正樣本參數太接近總的正樣本數導致。
  • 2、錯誤提示:
    “Required leaf false alarm rate achieved. Branch training terminated – it’s impossible to build classifier with good false alarm on this negative images. Check your negative images are really negative”
    出現這個提示,可能是因爲負樣本中有類似正樣本的圖片,把這些圖片篩掉
  • 8、訓練結束後,xml文件夾下的cascade.xml文件就是訓練好的分類器

1.2 批量調整樣本圖片尺寸的方法

使用python可以很方便的批量調整圖片的尺寸(也可以用C++,但是代碼寫起來比較麻煩),方法如下。

  • 1、視頻逐幀讀取爲圖片
    逐幀讀取圖片,並按從1開始對圖片進行編號
import numpy as np
import cv2
cap = cv2.VideoCapture('C:/Users/vid.mp4')  #讀取視頻
c = 1
while (cap.isOpened()):
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    cv2.imshow('frame', gray)
    cv2.imwrite('C:/Users/photo/' + '%s'%c + '.jpg', frame)  #圖片寫入相應的路徑
    c = c + 1
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
  • 2、批量調整圖片尺寸
c = 1
for i in range(1, 2000):
    img = cv2.imread('D:/test/' + str(i) + '.jpg') #按序號讀取圖片
    if img==None:  #如果圖片不存在,則跳過本次循環
        continue
    dst1 = img[:120, :120] #截取120*120的圖片
    dst2 = cv2.resize(dst1, (60,60), 0, 0, cv2.INTER_LINEAR)   #調整圖片大小,即縮放,其中60爲圖片尺寸
    dst3 = cv2.resize(img, (60,60), 0, 0, cv2.INTER_LINEAR)  #該操作是直接對原圖進行縮放,這樣會使得圖片變形,故最好先截取爲等寬等長的圖片,再進行縮放
    cv2.imwrite('D:/test/photo/'+str(c)+'.png', dst2)
    c = c + 1
print 'its over'

1.3 訓練步驟中的參數詳解

無論是Haar特徵訓練,還是LBP特徵訓練或Hog特徵訓練,其圖片尺寸都不要太大

一般,訓練Haar所需的正樣本圖片爲:20*20,訓練LBP所需的正樣本圖片爲:24*24,訓練HOG所需的正樣本圖片爲:60*60,負樣本圖片要大於等於正樣本圖片

  • 1、生成pos.vec的命令:
opencv_createsamples.exe -info pos\pos.txt -vec pos.vec -bg neg\neg.txt -num 2000 -w 24 -h 24
  • 2、生成pos.vec的參數:

    -info 輸入正樣本描述文件,默認NULL

    -img 輸入圖像文件名,默認NULL

    -bg 負樣本描述文件,文件中包含一系列的被隨機選作物體背景的圖像文件名,默認NULL

    -num 生成正樣本的數目,默認1000

    -bgcolor 背景顏色,表示透明顏色,默認0

    -bgthresh 顏色容差,所有處於bgcolor-bgthresh和bgcolor+bgthresh之間的像素被置爲透明像素,也就是將白噪聲加到前景圖像上,默認80

    -inv 前景圖像顏色翻轉標誌,如果指定顏色翻轉,默認0(不翻轉)

    -randinv 如果指定顏色將隨機翻轉,默認0

    -maxidev 前景圖像中像素的亮度梯度最大值,默認40

    -maxxangle X軸最大旋轉角度,以弧度爲單位,默認1.1

    -maxyangle Y軸最大旋轉角度,以弧度爲單位,默認1.1

    -maxzangle Z軸最大旋轉角度,以弧度爲單位,默認0.5
    輸入圖像沿着三個軸進行旋轉,旋轉角度由上述3個值限定。

    -show 如果指定,每個樣本都將被顯示,按下Esc鍵,程序將繼續創建樣本而不在顯示,默認爲0(不顯示)

    -scale 顯示圖像的縮放比例,默認4.0

    -w 輸出樣本寬度,默認24

    -h 輸出樣本高度,默認24

    -vec 輸出用於訓練的.vec文件,默認NULL

  • 3、訓練命令:

opencv_traincascade.exe -data xml -vec pos.vec -bg neg\neg.txt 
-numPos 1800 -numNeg 4000 -numStages 20 -featureType LBP -w 24 -h 24
  • 4、訓練參數:

-data 目錄名xml,存放訓練好的分類器,如果不存在訓練程序自行創建

-vec pos.vec文件,由opencv_createsamples生成

-bg 負樣本描述文件, neg\neg.txt

-numPos 每級分類器訓練時所用到的正樣本數目

-numNeg 每級分類器訓練時所用到的負樣本數目,可以大於-bg指定的圖片數目

-numStages 訓練分類器的級數,默認20級,一般在14-25層之間均可。
如果層數過多,分類器的fals alarm就更小,但是產生級聯分類器的時間更長,分類器的hitrate就更小,檢測速度就慢。如果正負樣本較少,層數沒必要設置很多。

-precalcValBufSize 緩存大小,用於存儲預先計算的特徵值,單位MB

-precalcIdxBufSize 緩存大小,用於存儲預先計算的特徵索引,單位M幣

-baseFormatSave 僅在使用Haar特徵時有效,如果指定,級聯分類器將以老格式存儲

  • 5、級聯參數cascadeParams:

    -stageType 級聯類型,staticconst char* stageTypes[] = { CC_BOOST };

    -featureType 特徵類型,staticconst char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };

    -w
    -h 訓練樣本的尺寸,必須跟使用opencv_createsamples創建的訓練樣本尺寸保持一致

  • 6、Boosted分類器參數stageParams:

    -bt Boosted分類器類型
    DAB-discrete Adaboost, RAB-RealAdaboost, LB-LogiBoost, GAB-Gentle Adaboost

    -minHitRate 分類器的每一級希望得到的最小檢測率,總的最大檢測率大約爲min_hit_rate^number_of_stages

    -maxFalseAlarmRate 分類器的每一級希望得到的最大誤檢率,總的誤檢率大約爲max_false_rate^number_of_stages

    -weightTrimRate Specifies whether trimming should beused and its weight. 一個還不錯的數值是0.95

    -maxDepth 弱分類器的最大深度,一個不錯數值是1,二叉樹

    -maxWeightCount 每一級中弱分類器的最大數目

  • 7、Haar特徵參數featureParams

    -mode 訓練過程使用的Haar特徵類型,CORE-Allupright ALL-All Features BASIC-Viola

1.4 測試分類器的效果

以下測試效果爲opencv自帶的人臉分類器測試效果代碼。對於自己訓練的分類器,只需將分類器文件及路徑在以下代碼中替換一下就可以了。

1.4.1 視頻中識別目標

  • 1、C++代碼
#include <opencv2\objdetect\objdetect.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(){

    cv::Mat img, gray;
    std::vector<Rect> face;
    CascadeClassifier face_cascade;
    if (!face_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml")){ printf("--(!)Error loading face\n"); return -1; };

    cv::VideoCapture cap(0);
    if (!cap.isOpened()){
        return -1;
    }

    cv::namedWindow("Video", 1);
    while (1){

        char key = cv::waitKey(1);
        if (key == 'q'){
            cv::destroyWindow("Video");
            break;
        }

        cap >> img;
        cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);

        face_cascade.detectMultiScale(gray, face, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
        for (size_t i = 0; i < face.size(); i++){
            cv::Point center(face[i].x + face[i].width*0.5, face[i].y + face[i].height*0.5);
            cv::ellipse(img, center, Size(face[i].width*0.5, face[i].height*0.5), 0, 0, 360, Scalar(255, 0, 0), 4, 8, 0);
        }

        cv::imshow("Video", img);
    }

    cap.release();
    return 0;
}
  • 2、python代碼
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 21 17:37:53 2017

@author: User
"""

##******************************************************************************
##                       利用opencv的分類器,檢測視頻中的人臉
##******************************************************************************
import cv2

face_haar = cv2.CascadeClassifier("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml")  #讀取人臉分類器,可在opencv的相應路徑下找到

path = 'D:/test/test.avi'  #視頻

cam = cv2.VideoCapture(0)  #讀取攝像頭
if cam==False:  #如果未發現攝像頭,則讀取視頻
    cam = cv2.VideoCapture(path)

while True:

    _, img = cam.read()
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    faces = face_haar.detectMultiScale(gray_img, 1.3, 5)  #檢測人臉
    for face_x,face_y,face_w,face_h in faces:
        cv2.rectangle(img, (face_x, face_y), (face_x+face_w, face_y+face_h), (0,255,0), 2)

    cv2.imshow('img', img)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        cv2.destroyAllWindows()
        break

cam.release()
cv2.waitKey(0)
cv2.destroyAllWindows()

1.4.2 圖片中識別目標

  • 1、C++代碼
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(){

    cv::Mat img, gray;
    std::vector<Rect> face;
    CascadeClassifier face_cascade;
    if (!face_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml")){
        printf("--(!)Error loading face\n");
        return -1;
    };

    img = cv::imread("d:/photo/08.jpg");
    cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
    //cv::GaussianBlur(gray, gray, Size(5, 5), 0, 0, 4);  //高斯濾波
    face_cascade.detectMultiScale(gray, face, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
    for (size_t i = 0; i < face.size(); i++){
        cv::Point center(face[i].x + face[i].width*0.5, face[i].y + face[i].height*0.5);
        cv::ellipse(img, center, Size(face[i].width*0.5, face[i].height*0.5), 0, 0, 360, Scalar(255, 0, 0), 4, 8, 0);
    }

    cv::imwrite("d:/photo/08_1.jpg", img);
    cv::namedWindow("img", cv::WINDOW_NORMAL);
    cv::imshow("img", img);
    cv::waitKey(0);

    return 0;
}

原圖:
此處輸入圖片的描述

效果圖:
此處輸入圖片的描述

效果圖中出現了誤識別,所以opencv所帶的分類器準確率並不是很高,但也可以通過調整函數detectMultiScale()的參數來提高識別率,或者檢測之前進行高斯濾波。

  • 2、python代碼
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 21 17:37:53 2017

@author: User
"""

#******************************************************************************
#                       利用opencv的分類器,檢測單張圖片的人臉
#******************************************************************************
import cv2

img = cv2.imread('D:/photo/08.jpg')

# 加載分類器
face_haar = cv2.CascadeClassifier("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml")

# 把圖像轉爲黑白圖像
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#gray_img = cv2.GaussianBlur(gray_img, (5,5), 0, 0) #高斯濾波
# 檢測圖像中的所有臉
faces = face_haar.detectMultiScale(gray_img, 1.1, 4)
for face_x,face_y,face_w,face_h in faces:
    cv2.rectangle(img, (face_x, face_y), (face_x+face_w, face_y+face_h), (0,255,0), 2)

#cv2.imwrite('d:/photo/08_3.jpg', img)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.imshow('img', img)
cv2.waitKey(0) 
cv2.destroyAllWindows()

效果圖:
此處輸入圖片的描述

先高斯濾波再檢測人臉的效果圖:
此處輸入圖片的描述

1.4.3 detectMultiScale()函數參數

Detects objects of different sizes in the input image. The detected objects are returned as a list of rectangles.

C++: void CascadeClassifier::detectMultiScale(const Mat& image, vector<Rect>& objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())

Python: cv2.CascadeClassifier.detectMultiScale(image[, scaleFactor[, minNeighbors[, flags[, minSize[, maxSize]]]]]) → objects

Python: cv2.CascadeClassifier.detectMultiScale(image, rejectLevels, levelWeights[, scaleFactor[, minNeighbors[, flags[, minSize[, maxSize[, outputRejectLevels]]]]]]) → objects
  • Parameters:

    • cascade – Haar classifier cascade (OpenCV 1.x API only). It can be loaded from XML or YAML file using Load(). When the cascade is not needed anymore, release it using cvReleaseHaarClassifierCascade(&cascade). 傳入生成的cascade.xml分類器文件

    • image – Matrix of the type CV_8U containing an image where objects are detected. 灰度圖

    • objects – Vector of rectangles where each rectangle contains the detected object.

    • scaleFactor – Parameter specifying how much the image size is reduced at each image scale. 圖像尺度參數,默認1.1

    • minNeighbors – Parameter specifying how many neighbors each candidate rectangle should have to retain it. 爲每一個級聯矩形應該保留的臨近個數,默認爲3,即至少有3次檢測到目標,才認爲是目標。

    • flags – Parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade.

      • CV_HAAR_DO_CANNY_PRUNING,利用邊緣檢測來排除一些邊緣很少或者很多的圖像區域
      • CV_HAAR_SCALE_IMAGE,按正常比例檢測
      • CV_HAAR_FIND_GIGGEST_OBJECT,只檢測最大的物體
      • CV_HAAR_DO_ROUGH_SEARCH,只做粗略檢測,默認值爲0
    • minSize – Minimum possible object size. Objects smaller than that are ignored.

    • maxSize – Maximum possible object size. Objects larger than that are ignored.

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章