Thực hành nhận dạng biển số xe máy
Trong bài này sẽ hướng dẫn các bạn nhận diện biển số xe máy. Đây là đề tài khá hấp dẫn vì mang tính thực tiễn cao, mặc dù đã nhiều người làm tuy nhiên độ chính xác chưa đạt được mức thương mại.

Để huấn luyện được Cascade thì các bạn nên đọc và hiểu hết lý thuyết trong phần 1 để dễ dàng thay đổi, tinh chỉnh các thiết lập, và cũng hiểu được các bộ dữ liệu mình chuẩn bị sẵn cho các bạn.

Nếu bạn không biết dùng command line, không biết cấu trúc của OpenCV thì bạn nên tìm hiểu trước khi đọc tiếp.

Các công cụ cần thiết

1. OpenCV 2.4.9 Đây là phiên bản ổn định (stable), các bạn có thể dùng phiên bản cao hơn vẫn ok
2. Tập dữ liệu dương: mình sử dụng bộ ảnh của công ty Green Parking. Trong file zip chứa 1749 ảnh
3. Tập dữ liệu âm: bao gồm 3000 hình ảnh bất kỳ không chứa biển số xe
4. Object locator: dùng để khoanh vùng đối tượng
5. Cascade analytics: dùng để đánh giá độ chính xác sau khi huấn luyện xong

Bắt đầu thực hiện

Các bước thực hiện như sau:

  1. Khoanh vùng đối tượng bằng tool Object locator
  2. Tạo tập ảnh sample bằng tool opencv_createsamples
  3. Huấn luyện bằng tool opencv_traincascade

Bước 1: Khoanh vùng đối tượng

Các bạn dùng tool Object locator vẽ hình chữ nhật bao lấy đối tượng, sau khi làm xong các bạn sẽ được file location.txt nằm trong thư mục chứa ảnh.

Mình đã tạo sẵn file location.txt cho các bạn. Và trong thư mục ảnh âm mình cũng có tạo file bg.txt chứa danh sách các file ảnh âm.

Trong thư mục ảnh âm có file _create_bg_file.bat. Các bạn chạy file đó để tạo ra file bg.txt có chứa đường dẫn tuyệt đối (để tránh lỗi tìm không thấy file)

Bước 2: Tạo tập ảnh samples

Dùng lệnh sau để tạo tập ảnh
opencv_createsamples -info E:\GreenParking\location.txt -vec GreenParking.vec -w 30 -h 20 -num 1749

Ý nghĩa lệnh: bạn tạo file vecto tên là GreenParking.vec chứa 1749 ảnh crop biển số, mỗi ảnh có kích thước 30×20 pixels.

Bước 3: Huấn luyện

Tạo folder để chứa dữ liệu các bước huấn luyện, mình tạo folder E:\train

Dùng lệnh sau để huấn luyện
opencv_traincascade -data E:\train -vec GreenParking.vec -bg E:\negatives\bg.txt -numPos 1749 -numNeg 3000 -w 30 -h 20 -featureType LBP -mode ALL

Ý nghĩa lệnh: huấn luyện để tạo file E:\train\cascade.xml, với 1749 ảnh dương và 3000 ảnh âm, kích thước bằng kích thước samples đã được tạo, sử dụng LBP feature vì kết quả chính xác tương đương Haar feature nhưng lại nhanh hơn rất nhiều, phù hợp cho việc thử nghiệm

Khi huấn luyện chương trình sẽ hiển thị như thế này

Có 1 mẹo ở đây là tạo 3500 samples nhưng khi huấn luyện chỉ dùng 3000, điều đó giúp cho chương trình chạy không bị crash. Đó là bug của phiên bản Opencv 2.x.x, các bạn download Opencv 3.x.x sẽ hết lỗi này.


Với câu lệnh như vậy mình huấn luyện trên máy CPU Intel core i5 2500 mất hơn 3 giờ

Kiểm tra độ chính xác bằng tool

Sau khi huấn luyện xong bạn sẽ được file E:\train\cascade.xml, dùng chương trình Cascade analytics để đánh giá độ chính xác. Mình đã test thử file kết quả thì độ phát hiện được 2848/3536 ảnh.

cascade.xml (22KB)
Download Cascade Analytics

Code detect object C++

Code detect object Python

https://github.com/opencv/opencv/blob/master/samples/python/facedetect.py

Kinh nghiệm xương máu

– Không nên sử dụng laptop hoặc máy yếu, cố gắng tìm 1 máy tính mạnh để training
– Nếu nơi bạn cúp điện thường xuyên thì hãy cố gắng tìm nguồn dự phòng hoặc sử dụng laptop
– Để tốc độ training được nhanh thì nên dùng LBP thay cho HAAR, vài giờ đã training xong 2000 ảnh size 30×30

Các sai sót thường gặp

– Đường dẫn ảnh có khoảng trắng hoặc ký tự đặc biệt
– Ảnh quá lớn, đề nghị ảnh tầm 1024×768 trở lại
– Ảnh vừa chụp xong vẫn còn metadata như góc xoay, phải loại bỏ trước khi training

Tổng quát

  1. Có phải Cascade phát hiện được bất kỳ đối tượng nào
  2. – Theo lý thuyết thì được nếu các tham số được chỉ định đúng, bộ dữ liệu đầy đủ mẫu. Tuy nhiên chỉ thực hiện tốt với các trường hợp: đối tượng rõ ràng, không bị overlap nhau, tỉ lệ width/height tương đối giống nhau. (cho nên nhận diện khuôn mặt là hình vuông)

    – Tuy nhiên đối tượng nào có hình dạng đơn giản sẽ dễ nhận sai vì chứa ít đặc trưng, cho nên Cascade không phải là vạn năng.

  3. Để phát hiện tốt hơn có cần chuyển sang ảnh trắng đen hoặc tiền xử lý?
  4. – Chuyển sang trắng đen là bắt buộc từ lúc tạo tập mẫu đến lúc phát hiện, nếu không thuật toán sẽ không chạy được. Do đó chuyển sang ảnh xám không tăng độ chính xác

    – Tiền xử lý sẽ giúp nhận diện tốt hơn, các gồm các thuật toán cân bằng sáng, lọc nhiễu,… Và độ chính xác cũng phụ thuộc vào chất lượng hình ảnh.

Ảnh dương

  1. Tại sao gọi là ảnh dương?
  2. – Vì nó có chứa đối tượng cần phát hiện. Ngược lại, ảnh không chứa đối tượng được gọi là ảnh âm

  3. File Vectơ là gì?
  4. – Khi bạn tạo file vectơ bằng chương trình opencv_createsamples.exe chương trình sẽ tạo ra các ảnh thumbnail với kích thước được chỉ định bởi -w và -h và đóng gói lại thành file vectơ. File vectơ có chứa header: số lượng mẫu, chiều rộng, chiều cao và phần thân chứa các ảnh thumbnail

  5. File_chỉ_mục.txt là gì?
  6. – Trên mỗi ảnh dương có thể có vài đối tượng cần phát hiện. Bạn cần chỉ cho máy tính biết đâu là đối tượng và đâu là không phải bằng cách vẽ khung chữ nhật với toạ độ x,y và width, height bao lấy đối tượng. Bạn có thể tạo file với nội dung:
    tên_ảnh số_đối_tượng x y width height x y width height x y width height....

    positve\image1.jpg 1 10 10 20 20
    positve\image1.jpg 2 30 30 50 50 60 60 70 70

  7. Tại sao phải cần file_chỉ_mục.txt ngay khi ảnh chỉ chứa 1 đối tượng?
  8. – Tại vì chương trình cần file này để crop lấy phần cần thiết để rút trích đặc trưng của đối tượng. Nếu bạn không chỉ ra rõ ràng khung hình chữ nhật thì chương trình sẽ lấy toàn bộ ảnh. Nếu bạn cần thì tự viết 1 chương trình để tạo file vectơ.

  9. Các background có cần phải khác nhau?
  10. – Cần, điều này rất quan trọng. Trên mỗi ảnh dương ngoài đối tượng thì có background. Thử thay đổi background bằng cách thêm vào những hình vẽ, noise để tạo sự khác biệt giữa các background. Tránh trường hợp background giống nhau liên tục.

  11. Tất cả ảnh dương đều phải cùng kích cỡ?
  12. – Không, ảnh gốc có thể có kích cỡ bất kỳ. Nhưng điều quan trọng là chiều rộng và chiều cao của khung chữ nhật phải cùng tỉ lệ với -w -h

  13. -w -h là gì? Nó cần phải luôn luôn là hình vuông?
  14. – Bạn có thể đặt bất kỳ giá trị -w và -h tuỳ thuộc vào tỉ lệ của đối tượng. Nhưng những đối tượng có kích cỡ nhỏ hơn kích cỡ -w -h này sẽ không được phát hiện. Nếu sử dụng cho khuôn mặt thì thường sử dụng giá trị là 24×24, 20×20. Nhưng bạn có thể sử dụng 24×20, 20×24,….

    – Tuy nhiên bạn nên giữ tỉ lệ width/height như nhau để đạt kết quả tốt nhất. Và tỉ lệ nhận dạng chính xác nhất với width/height = 1

Ảnh âm

  1. Lấy ảnh âm từ đâu?
  2. – Bạn có thể sử dụng bất kỳ hình ảnh nào mà OpenCV hỗ trợ miễn là không chứa đối tượng. Nhưng chúng phải khác nhau (rất quan trọng).

    – Cách tốt nhất là bạn download các tập ảnh âm được chuẩn bị sẵn, chúng tôi cũng có sẵn bộ ảnh âm .

  3. Ảnh âm phải cùng kích cỡ với nhau?
  4. – Không. Nhưng kích cỡ phải lớn hơn -w -h

  5. Cần bao nhiêu ảnh dương/ảnh âm?
  6. – Tuỳ thuộc vào công việc của bạn. Để phát hiện theo thời gian thực cần khoảng 1000 ảnh dương và 2000 ảnh âm.
    Tỉ lệ tốt nhất là ảnh âm gấp đôi ảnh dương, nhưng quy tắc này không cố định. Tôi khuyến cáo đầu tiên sử dụng ít mẫu, tạo cascade rồi mở rộng số lượng mẫu

Thực hiện huấn luyện

  1. Falsealarm và hitrate của bước dự đoán là gì?
  2. – Bạn phải đọc lý thuyết adaboost về phân lớp mạnh. Stage là phân lớp mạnh, tóm tắt lại như thế này:
    • Bạn có 1000 ảnh dương và bạn muốn hệ thống phát hiện được 900. Như vậy tỉ lệ là 900/1000=0.9. Bình thường thì minhitrate=0.999
    • Bạn có 1000 ảnh âm và bạn không muốn hệ thống phát hiện chúng. Nhưng vì 1 số lỗi hệ thống lại phát hiện. Nếu phát hiện sai 490 mẫu thì falsealarm=490/1000=0.49. Bình thường nó là 0.5

  3. Falsealarm và hitrate phụ thuộc vào nhau?
  4. – Đúng, bạn không thể đặt minhitrate=1.0 và maxfalsealarm =0.0
    Đầu tiên, hệ thống xây dựng bộ phân lớp với hirate mong muốn, sau đó sẽ tính toán falsealarm. Nếu falsealarm cao hơn maxfalselarm, hệ thống sẽ bỏ qua và nhảy qua bước tiếp theo

  5. Cần làm bao nhiêu stages?
  6. Thông thường thì từ 14-18 stages:
    – Nếu bạn dùng nhiều stage, thì bạn sẽ có tỉ lệ falsealarm tốt hơn nhưng tốn nhiều thời gian hơn.
    – Nó sẽ không hiệu quả khi bạn đặt nhiều stages mà có ít ảnh dương và ít ảnh âm

  7. Những tham số weighttrimming, eqw, bt, nonsym option là gì?
  8. – Những cái này liên quan tới Adaboost, tóm tắt:
    • nonsym: nếu ảnh dương không đối xứng theo trục X hoặc Y thì đặt là -nonsym, mặc định là -sym
    • eqw: nếu bạn có số lượng ảnh dương khác số lượng ảnh âm thì đặt no eqw sẽ tốt hơn
    • weighttrimming: dùng cho tối ưu tính toán. Nó có thể giảm thời gian huấn luyện 1 chút nhưng chất lượng sẽ tệ hơn.
    • bt: thuật toán Adaboost sẽ sử dụng: realAB, gentle AB,…

  9. Minpos, nsplits, maxtreesplits là gì?
  10. – Đây là những tham số liên quan tới gom cụm. Trong adaboost sự phân lớp yếu có thể sử dụng là: stump-based hoặc tree-based. Nếu bạn chọn nsplits>0, tree-based sẽ được sử dụng và bạn cần thiết lập minpos và maxtreeplits
    • nsplits: số lượng nút trên cây
    • maxtreesplits: số lượng nút tối đa. Nếu maxtreesplitsLàm sao test thử file XML?

    – Có công cụ opencv_performance.exe để kiểm tra. Bạn cần có có ảnh dương chưa được sử dụng để huấn luyện và file_chỉ_mục của những ảnh này. Cú pháp như sau:
    performance -data haarcascade -w 20 -h 20 -info positive_description.txt -ni
    performance -data haarcascade.xml -info postive_description.txt -ni

    – Hoặc bạn sử dụng tool Cascada Analytics để đánh giá cũng được

  11. Thời gian trung bình để huấn luyện trên máy tính?
  12. Tuỳ thuộc vào công việc và cấu hình máy tính của bạn. Có 1 số quy tắc sau:
    + Càng nhiều stages thì càng chính xác, ngược lại tốc độ huấn luyện và phát hiện chậm hơn
    + Càng nhiều ảnh thì càng chính xác, và ngược lại tốc độ huấn luyện và phát hiện chậm hơn
    + LBP feature nhanh hơn Haar feature, theo đánh giá thì LBP có độ chính xác gần bằng Haar

Các lỗi xảy ra khi train cascade

  1. Lỗi khi tạo file vectơ: Incorrect size of input array, 0 kb vec file
  2. – Đầu tiên bạn phải kiểm tra file_chỉ_mục: tên_file_ảnh phải đúng
    – Không được có dòng rỗng
    – Độ phân giải của ảnh dương không được nhỏ hơn -w -h
    – Kiểm tra ảnh có tồn tại hoặc có bị lỗi hay không
    – Có thể định dạng ảnh không được chấp nhận. Loại được chấp nhận là jpg, bmp, ppm.
    Note: từ opencv 3.x trở đi lỗi này được chỉ ra rõ ràng hơn, giúp bạn biết lỗi ở đâu

  3. opencv_haarcascade has stoped working…
  4. Lỗi này do nhiều nguyên nhân, chủ yếu là tham số sai. Các bạn comment câu lệnh lên đây mình sẽ tìm lỗi giùm.

  5. Corrupt JPEG data: premature end of data segment
  6. Lỗi này do ảnh dương hoặc ảnh âm không đúng format. Bạn nên dùng 1 công cụ convert ảnh hàng loạt để chuyển ảnh đó sang ảnh đúng định dạng.

  7. Parameters can not be written, because file E:\HaarCascade\params.xml can not be opened.
  8. Lỗi này do thư mục E:\HaarCascade\ chưa được tạo ra

  9. OpenCV Error: Assertion failed (elements_read == 1) in icvGetHaarTraininDataFromVecCallback….
  10. Khi bạn create_sample với n ảnh thì khi training bạn nên chọn npos ít hơn

  11. Train dataset for temp stage can not be filled. Branch training terminated
  12. Lỗi này là do đường dẫn ảnh âm trong file chỉ mục bị sai. Có 2 cách khắc phục:
    1. Thay bằng đường dẫn ảnh tuyệt đối
    2. Thêm vào 2 ký tự ./ trước mỗi ảnh, lưu ý ảnh và file chỉ mục phải chung folder. Ví dụ: bgimg1.jpg => ./bgimg1.jpg

  13. Opencv Error: Assertion failed (elements_read==1)in unknown function, file c:\path\cvhaartraining.cpp, line 1858
  14. error

    Để khắc phục lỗi này bạn cần chỉ định npos (haartraining) nhỏ hơn num (create_samples) theo công thức sau: num >= (npos + (nstages-1) * (1 – minHitRate) * npos) + S. Với:
    num là số sample trong file vec
    nstages: số bước huấn luyện
    minHitRate: độ chính xác
    S: số file background

    Ví dụ: tạo file vec có 2000 mẫu (-num 1000), có 1500 ảnh background (S), 14 stages, minHitRate là 0.995 thì tính được nPos là:
    2000 >= (nPos + (14-1) * (1-0.995) * nPos) + 1500
    <=> 500 >= (nPos + 13 * 0.005 * nPos)
    <=> 500 >= 1.065 * nPos
    <=> nPos = 470

Nguồn: https://thigiacmaytinh.com/phat-hien-vat-the-p2-thuc-hanh/

7/1/2019 5:18:43 PM