標籤:

使用opencv製作分類器

之前一直在學習opencv,但是並沒有很多實質性的成果,最近有時間來使用opencv的庫做一些有意思的識別。我先是使用mit人臉庫把程序跑通,其他的訓練方式也就可以照著來了。

這個過程大概分為三步;

第一步,製作訓練集的數據集,這一步是最能做文章的一步,因為訓練集的質量直接決定了最後識別的效果,所以可以儘可能的把數據集做到精準。

第二步,訓練分類器。

第三步,使用分類器進行分類。

(1)製作數據集

數據集主要分兩部分,一部分是正例,一部分反例。正例是指該圖片種只有我們要識別的物體,其他的干擾項最要都要剔除。最好背景色都能是同一種顏色,如果說彩色要將其轉換成灰度圖。

正例部分:要歸一化為相同的大小,比如30*30,圖像越小相對來說訓練時間會變短,此外如果想要有很好的泛化能力,最好多找一些不同的目標物的圖片,從各個角度的,每一張圖片都有很好的代表性,只有這樣才能很好的從場景中識別出目標物體。

反例部分:首先說明一下反例存在的意義,比方說我們現在要識別杯子,那麼我們可以想像杯子一般會出現在哪些場景,在桌子上,但是我們怎麼能告訴電腦哪些是杯子哪些不是杯子呢,正例的部分就告訴電腦這些是杯子,而反例部分就是告訴電腦哪些不是杯子,所以我們在反例中加入杯子出現的背景,而且不能出現杯子! 總而言之,反例是目標物可能出現的場景,大小相同也是統一的,顏色是灰色的最好。

下面開始來進行訓練

(2)訓練分類器

1. 創建樣本

◆ 樣本分兩種: 正樣本與負樣本(也有人翻譯成:正例樣本和反例樣本),其中正樣本是指待檢目標樣本(例如人臉,汽車,鼻子等),負樣本指其它任意圖片。

◆ 所有樣本圖片都應該有同一尺寸,如20 * 20,並放在相應文件目錄下,

◆ 集合文件格式(collection file format)和描述文件格式(description file format)

集合文件格式(collection file format)就是如下形的描述文件:

[filename]

[filename]

[filename]

描述文件格式(description file format)就是如下形的描述文件:

[filename] [# of objects] [[x y width height] [... 2nd object] ...]

[filename] [# of objects] [[x y width height] [... 2nd object] ...]

[filename] [# of objects] [[x y width height] [... 2nd object] ...]

….

(x, y) 指左上角的坐標,width和 height 分別是樣本的寬和高,這裡我的圖片是20*20的,所以兩個值都是20

為正樣本創建描述文件格式文件info.txt,並且把這個文件放在與樣本圖片同一目錄下,例如我的目錄為C:/OpenCV2.1/bin/posdata

a) 在命令行下 輸入以下命令: dir /b > info.txt

b) 打開info.txt, 按ctrl+h, 把所有的bmp 換成 bmp 1 0 0 20 20

c) 刪除info.txt最後一行的 「info.txt」

d) 結果如下:(1代表一個文件,0 0 20 20表示這個文件的2個頂點位置坐標)

同樣為負樣本創建集合文件格式文件bg.txt, 並且把這個文件放在與樣本圖片同一目錄下,例如我的目錄為I:/negdata

a) 在命令行下 輸入以下命令: dir /b > bg.txt

b) 刪除bg.txt最後一行的 「bg.txt」

這樣就算是把數據集準備好了,然後就是開始進行生成樣本,我們在opencv文件夾找到opencv_createsamples.exe,把它放進訓練集目錄中,然後輸入

opencv_createsamples.exe -info e: estposdata0info.txt -vec e: estposdata0pos.vec -num 120 -w 20 -h 20

  • createsamples具體訓練參數意思如下:
    • -vec <vec_file_name>訓練好的正樣本的輸出文件名。
    • -img<image_file_name>源目標圖片(例如:一個公司圖標)
    • -bg<background_file_name>背景描述文件。
    • -num<number_of_samples>要產生的正樣本的數量,和正樣本圖片數目相同。
    • -bgcolor<background_color> 背景色(假定當前圖片為灰度圖)。背景色制定了透明色。對於壓縮圖片,顏色方差量由bgthresh參數來指定。則在bgcolor-bgthresh 和bgcolor+bgthresh 中間的像素被認為是透明的。
    • -bgthresh<background_color_threshold>

    • -inv 如果指定,顏色會反色
    • -randinv如果指定,顏色會任意反色
    • -maxidev<max_intensity_deviation>背景色最大的偏離度。
    • -maxangel<max_x_rotation_angle>
    • -maxangle<max_y_rotation_angle>,
    • -maxzangle<max_x_rotation_angle>最大旋轉角度,以弧度為單位。
    • -show 如果指定,每個樣本會被顯示出來,按下"esc"會關閉這一開關,即不顯示樣本圖片,而創建過程繼續。這是個有用的debug 選項。
    • -w<sample_width> 輸出樣本的寬度(以像素為單位)
    • -h<sample_height>輸出樣本的高度,以像素為單位。
    • 註:正樣本也可以從一個預先標記好的圖像集合中獲取。這個集合由一個文本文件來描述。每一個文本行對應一個圖片。每行的第一個元素是圖片文件名,第二個元素是對象實體的個數。後面緊跟著的是與之匹配的矩形框(x, y, 寬度,高度)。

    下面開始正式訓練

    我們找到opencv_haartraining.exe文件在opencv文件夾中,然後在cmd中輸入

    opencv_haartraining.exe -data e: estdata0cascade0 -vec e: estposdata0pos.vec -bg e: est
    egdata0
    egdata0.txt -npos 120 -nneg 120 -nsplits 2 -mem 512 -nonsym -w 20 -h 20 -minpos 100 -nstages 4

    Haartraining 的命令行參數如下:

    • -data<dir_name>存放訓練好的分類器的路徑名。
    • -vec<vec_file_name>正樣本文件名 由trainingssamples 程序或者由其他的方法創建
    • -bg<background_file_name>背景描述文件。
    • -npos<number_of_positive_samples>,

    • -nneg<number_of_negative_samples>用來訓練每一個分類器階段的正/負樣本。合理的值是:nPos = 7000;nNeg = 3000
    • -nstages<number_of_stages>訓練的階段數。
    • -nsplits<number_of_splits> 決定用於階段分類器的弱分類器。如果1,則一個簡單的stump classifier 被使用。如果是2 或者更多,則帶有number_of_splits 個內部節點的CART 分類器被使用。
    • -mem<memory_in_MB>預先計算的以MB 為單位的可用內存。內存越大則訓練的速度越快。
    • -sym(default)

    • -nonsym 指定訓練的目標對象是否垂直對稱。垂直對稱提高目標的訓練速度。例如,正面部是垂直對稱的。
    • -minhitrate<min_hit_rate> 每個階段分類器需要的最小的命中率。總的命中率為min_hit_rate 的number_of_stages 次方。
    • -maxfalsealarm<max_false_alarm_rate> 沒有階段分類器的最大錯誤報警率。總的錯誤警告率為max_false_alarm_rate 的
    • number_of_stages 次方。
    • -weighttrimming<weight_trimming> 指定是否使用權修正和使用多大的權修正。一個基本的選擇是0.9
    • -eqw

    • -mode<basic(default)|core|all> 選擇用來訓練的haar 特徵集的種類。basic 僅僅使用垂直特徵。all 使用垂直和45 度角旋轉特徵。
    • -w<sample_width>

    • -h<sample_height> 訓練樣本的尺寸,(以像素為單位)。必須和訓練樣本創建的尺寸相同

    這樣就算是訓練好了,生成的xml文件就可以使用了,然後我們就可以在網上找一個opencv的載入聯級分類器代碼的框架進行使用了。

    #!/usr/bin/env pythonimport numpy as npimport cv2#import cv2.cv2 as cv#from video import create_capture#from common import clock, draw_strhelp_message = USAGE: facedetect.py [--cascade <cascade_fn>] [--nested-cascade <cascade_fn>] [<video_source>]def detect(img, cascade): rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30), flags = cv.CV_HAAR_SCALE_IMAGE) if len(rects) == 0: return [] rects[:,2:] += rects[:,:2] return rectsdef draw_rects(img, rects, color): for x1, y1, x2, y2 in rects: cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)if __name__ == __main__: import sys, getopt print (help_message) args, video_src = getopt.getopt(sys.argv[1:], , [cascade=, nested-cascade=]) try: video_src = video_src[0] except: video_src = 0 args = dict(args) cascade_fn = args.get(--cascade,rD:OpenCVopencvsourcesdatahaarcascadeshaarcascade_frontalface_default.xml) nested_fn = args.get(--nested-cascade, rD:OpenCVopencvsourcesdatahaarcascadeshaarcascade_eye.xml) cascade = cv2.CascadeClassifier(cascade_fn) nested = cv2.CascadeClassifier(nested_fn) cam = create_capture(video_src, fallback=synth:bg=../cpp/lena.jpg:noise=0.05) while True: ret, img = cam.read() gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) t = clock() rects = detect(gray, cascade) vis = img.copy() draw_rects(vis, rects, (0, 255, 0)) for x1, y1, x2, y2 in rects: roi = gray[y1:y2, x1:x2] vis_roi = vis[y1:y2, x1:x2] subrects = detect(roi.copy(), nested) draw_rects(vis_roi, subrects, (255, 0, 0)) dt = clock() - t draw_str(vis, (20, 20), time: %.1f ms % (dt*1000)) cv2.imshow(facedetect, vis) if 0xFF & cv2.waitKey(5) == 27: break cv2.destroyAllWindows()

    下面我匯總了一些可能遇到的問題從網路上面以供查閱。

    1. 如果跑到某一個分類器時,幾個小時也沒有反應,而且顯示不出訓練百分比,這是因為你的負樣本數量太少,或者負樣本的尺寸太小,所有的負樣本在這個分類器都被reject了,程序進入不了下一個循環,果斷放棄吧。解決方法:負樣本盡量要大一些,比如我的正樣本是40*15,共300個,負樣本是640*480,共500個。(我當時的錯誤就出現在這,把負本改大後,就成功了)

    2. 讀取樣本時報錯:Negative or too large argument of CvAlloc function,網上說這個錯誤是因為opencv規定單幅iplimage的內存分配不能超過10000,可是我的每個負樣本都不會超過這個大小,具體原因不明。後來我把負樣本的數量減少,尺寸加大,這個問題就解決了。

    3. 訓練的過程可能經常出錯,耐心下來不要著急,我在訓練MRI分類器的時候失敗了無數次。失敗的時候有兩件事可以做,第一,調整正負樣本的數量,再試。第二,調整負樣本的大小,祝大家好運。

    這是第一次在知乎上面寫,之前寫的由於網路斷了,完全都沒有了。。。這次有很多是轉載自csdn的。

    地址:

    OpenCV訓練分類器製作xml文檔 - liulina603的專欄 - 博客頻道 - CSDN.NET

    OpenCV訓練分類器製作xml文檔_yumantang_新浪博客
    推薦閱讀:

    【小林的OpenCV基礎課 4】滑動條什麼的
    通俗的講,網路爬蟲到底是什麼?
    為什麼說浮點數缺乏精確性? python中浮點數運算問題
    零基礎如何自學Python?
    Python數據分析及可視化實例之爬蟲源碼(01)

    TAG:OpenCV | Python |