Phát hiện đối tượng – P1: lý thuyết

Phát hiện đối tượng là để trả lời câu hỏi: “Đối tượng cần tìm có ở trong ảnh hay không?” và “Nếu có thì nằm ở vị trí nào?”

Trong các phương pháp phát hiện đối tượng hiện nay có Haar cascade là phương pháp phổ biến nhất. Quy trình bao gồm:

Bước 1: Dùng tool của Opencv cung cấp để rút trích đặc trưng của đối tượng (gọi là haar-like) ghi vào tập dữ liệu (*.xml). Đó là các đặc trưng đường chéo, đường ngang, đường dọc của đối tượng.

Bước 2: Viết chương trình để tìm đối tượng. Sau khi load các đặc trưng từ file xml đã huấn luyện, thuật toán của OpenCV sẽ lần lượt quét qua các vùng trên ảnh để tìm đối tượng. Đối tượng nào có đặc trưng giống với tập dữ liệu & thoả mãn các tham số thì xem như đó là đối tượng cần tìm.

Bước 1: Rút trích đặc trưng

Bước này còn được gọi là huấn luyện (training)

Bạn cần chuẩn bị 2 bộ ảnh, một bộ ảnh có chứa đối tượng gọi là ảnh dương. Bộ còn lại là những ảnh bất kỳ không chứa đối tượng gọi là ảnh âm. Số lượng ảnh âm & dương càng nhiều thì độ chính xác càng cao & thời gian huấn luyện càng lâu.

Khi training, chương trình sẽ rút ra đặc trưng rồi so sánh với các ảnh âm, nếu đặc trưng đó được tìm thấy trong ảnh âm thì đặc trưng đó không phù hợp.

Ví dụ
Để phát hiện biển số xe, bạn cần khoảng 2000 ảnh biển số & 1000 ảnh không chứa biển số. Ảnh không có biển số có thể là ảnh hoa lá cành, đồ vật bất kỳ...

Tiếp theo, bạn phải chỉ định rõ vị trí hình chữ nhật chứa đối tượng cần tìm và lưu vào file chỉ mục. Có 2 cách thực hiện:

    – Crop ảnh chỉ lấy vùng chữ nhật chứa đối tượng: file chỉ mục chỉ chứa tên file ảnh
    – Ghi lại thông số x y width height của vùng chữ nhật vào file: file chỉ mục gồm tên file ảnh, số vùng chữ nhật trong ảnh và các toạ độ x y width height

Mình có viết tool Object Locator để giúp bạn thực hiện bước trên

Khi đã có file chỉ mục, các bạn sẽ làm 2 bước để tạo tập dữ liệu (*.xml), thuật toán của 2 bước này được viết sẵn:
– Bước 1.1: dùng opencv_createsamples.exe tạo file vecto chứa ảnh thumbnail của vùng hình chữ nhật. Bước này nhanh, 2000 ảnh mất chưa tới 1 phút.
– Bước 1.2: dùng opencv_traincascade.exe lấy ảnh trong file vecto đặt ngẫu nhiên vào các ảnh âm để rút trích các đặc trưng. Bước này chậm, 2000 ảnh mất từ 1 ngày đến 1 tuần tuỳ theo độ chính xác các bạn yêu cầu.

Hoàn thành 2 bước này bạn sẽ có file xml

Bước 1.1 tạo file vecto

Đầu tiên các bạn tìm chương trình opencv_createsamples.exe trong lib Opencv theo đường dẫn opencv300\build\bin\Release và truyền các tham số sau:

-info file chỉ mục mà bạn đã tạo
-img khi bạn chỉ có 1 ảnh dương (như là logo cty chẳng hạn) thì bỏ qua tham số -info và truyền tên file ảnh vào đây
-vec file output cho bước tiếp theo
-bg file ảnh âm khi bạn chỉ có 1 ảnh dương
-num số lượng file ảnh dương
-bgcolor khi bạn không chỉ định ảnh âm thì có thể chỉ định 1 màu để làm ảnh âm
-inv -randinv -bgthresh -maxidev -maxxangle -maxyangle -maxzangle các tham số để tạo thêm các ảnh ngẫu nhiên bằng cách xoay trong không gian 3 chiều
-show hiện ảnh trong quá trình tạo mẫu
-w chiều rộng của mẫu được tạo
-h chiều cao của mẫu được tạo

Ví dụ: opencv_createsamples.exe -vec D:\bienso.vec -info D:\plate_image\positive\location.txt -num 2000 -w 40 -h 30
OpenCV sẽ tạo file D:\bienso.vec có chứa 2000 ảnh thumbnail, mỗi ảnh có kích thước 40 x 30 pixels.

Bước 1.2 huấn luyện

train cascade

opencv_traincascade

Các bạn lấy file opencv_traincascade.exe truyền các tham số sau (do nhiều tham số nên mình chỉ ghi các tham số quan trọng):
-data Thư mục rỗng dành để chứa các step và các file tạm trong quá trình huấn luyện, file xml thu được cũng nằm trong này
-vec file vec bạn tạo ở bước 1.1
-bg file text chứa danh sách các file ảnh âm
-numPos số lượng ảnh dương
-numNeg số lượng ảnh âm
-numStage số lượng bước huấn luyện bạn muốn, càng lớn (14 -> 20) thì thời gian huấn luyện càng lâu và kết quả càng chính xác
-w chiều rộng của mẫu được tạo (ở bước 1.1 bao nhiêu thì ở đây cũng vậy)
-h chiều cao của mẫu được tạo (ở bước 1.1 bao nhiêu thì ở đây cũng vậy)
-minHitRate tỉ lệ chính xác của ảnh dương. ,
-maxFalseAlarmRate tỉ lệ cho phép sai số tối đa của ảnh âm.

Ví dụ: opencv_traincascade.exe -data D:\output -vec D:\bienso.vec -bg D:\plate_image\negative\list.txt -numPos 2000 -numNeg 1000 -numStage 20 -minHitRate 0.995 -maxFalseAlarmRate 0.5 -w 40 -h 30
Chương trình sẽ tạo file D:\output\cascade.xml chứa các đặc trưng của biển số xe. minHitRate=0.995 nghĩa là phải đúng 995/1000 ảnh. maxFalseAlarmRate=0.5 nghĩa là cứ mỗi 1000 ảnh chỉ được detect nhầm tối đa 500 ảnh.

Các file xml được huấn luyện sẵn nằm trong lib opencv theo đường dẫn: opencv300\sources\data\haarcascades hoặc các bạn có thể search trên Internet

Bước 2: Sử dụng tập dữ liệu để phát hiện đối tượng

Trước khi thực hiện thuật toán phát hiện đối tượng, ảnh phải chuyển sang ảnh xám (gray). Đồng thời cũng câng bằng sáng (equalize hist) để ảnh được đồng nhất về độ tương phản, không bị ảnh hưởng bởi ánh sáng môi trường.

OpenCV sẽ quét qua toàn bộ ảnh để so sánh với tập dữ liệu. Lần đầu tiên sẽ lấy hình chữ nhật kích thước bằng max-size được chỉ định (hoặc bằng kích thước ảnh). Sau đó thu nhỏ lại theo tỉ lệ được chỉ định rồi lại so sánh với tập dữ liệu, cứ như thế cho đến khi vùng quét bằng kích thước min-size thì dừng.


Để sử dụng, bạn cần load data từ file xml, sau đó dùng hàm detectMultiScale(const Mat& image, vector& objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size()) để tìm đối tượng trong ảnh. Các tham số truyền vào bao gồm:
image: ảnh input
objects: kết quả trả về là các hình chữ nhật
scaleFactor tỉ lệ vùng chữ nhật được thu nhỏ sau mỗi lần quét (default là 1.1)
minNeighbors số khung hình chữ nhật trùng nhau tối thiểu để được xem là 1 đối tượng (default là 3)
flags phương thức quét
minSize và maxSize: kích cỡ tối thiểu, kích cỡ tối đa.

Hình bên dưới là test detect nhầm biển số xe hơi. Mặc dù đó không phải là biển số nhưng có đủ đặc trưng khi huấn luyện thì cũng được xem là biển số.
bugorfeature

Đọc thêm

Phần 2: thực hành: hướng dẫn các bước cụ thể để thực hành huấn luyện tạo file xml đặc trưng và viết chương trình thử nghiệm.

Phần 3: hỏi đáp Chia sẻ các kinh nghiệm và giải đáp thắc mắc của các bạn.

Các file xml được huấn luyện sẵn có khá nhiều trên mạng, mình có tổng hợp lại trong bài Tổng hợp data xử lý ảnh

52 thoughts on “Phát hiện đối tượng – P1: lý thuyết

  1. Hi anh ! Cảm ơn bài viết của anh ! :D, em cũng có làm và nó nhận diện khá ổn! Nhưng vấn đề của em là: Em đang nhận diện đối tượng là người, nhưng không chỉ là người đi bình thường, mà còn người già đi khom, người đang ngồi đang nằm.
    Em nghĩ là mình train cho hắn tất cả những hình người đang đứng, đang đi, đi khom, ngồi nằm cho hắn luôn! Mà em thấy độ chính xác nó không có cao! Anh có thể chia sẻ gì thêm không ạ ? 😀 Em cảm ơn anh nhiều ^^

    1. Để chính xác thì bạn set minHitRate bằng 0.999999 (default là 0.99).

      Để có thể phát hiện nhiều hình dáng thì phải có tập mẫu đủ lớn, mỗi hình dạng tầm 1000 ảnh

  2. Chào bạn @vohungvi
    Cho mình hỏi – Có thể chạy opencv_createsamples.exe trực tiếp tất cả ảnh trong thư mục không. Hay bắt buộc phải tìm từng điểm đặc trưng của anh rồi lưu vào location.txt. Mấy cái icon của mình nguyên ảnh icon nó là điểm đặt trưng rồi nên mình cũng k dùng tool để định vị. Các cách nào để nó chạy luôn mấy ảnh icon không bạn.

    Cảm ơn

    1. Ý bạn là phát hiện các icon trong ảnh? Như vậy thì được vì đối tượng để train đã được loại bỏ dữ liệu không cần thiết

    2. Ảnh của mình có size 12×28 tương ứng với Icon luôn – Mình có 1000 ảnh nên k rút trích đặc trưng từng ảnh bằng tool được

    3. Tương ứng với icon thì được rồi.

      Còn 1000 ảnh là chuyện bình thường thôi bạn, vài ngàn ảnh vẫn phải làm

  3. anh ơi em làm theo cơ mà bị lỗi anh ạ . Info file name: C:\opencv\My.Project\GreenParking\location.txt
    Img file name: (NULL)
    Vec file name: C:\opencv\My.Project\bienso.vec
    BG file name: (NULL)
    Num: 518
    BG color: 0
    BG threshold: 80
    Invert: FALSE
    Max intensity deviation: 40
    Max x angle: 1.1
    Max y angle: 1.1
    Max z angle: 0.5
    Show samples: FALSE
    Width: 40
    Height: 30
    Max Scale: -1
    RNG Seed: 12345
    Create training samples from images collection…
    OpenCV: terminate handler is called! The last OpenCV error is:
    OpenCV(4.0.0-alpha) Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in cv::Mat::Mat, file C:\build\master_winpack-build-win64-vc14\opencv\modules\core\src\matrix.cpp, line 465

  4. chào bạn . bạn giúp mình lỗi này đc k
    E:\opencv\opencv\build\x64\vc14\bin>opencv_createsamples -vec C:\bienso.vec -info C:\GreenParking\location.txt -num 1000 -w 40 -h 30
    Info file name: C:\GreenParking\location.txt
    Img file name: (NULL)
    Vec file name: C:\bienso.vec
    BG file name: (NULL)
    Num: 1000
    BG color: 0
    BG threshold: 80
    Invert: FALSE
    Max intensity deviation: 40
    Max x angle: 1.1
    Max y angle: 1.1
    Max z angle: 0.5
    Show samples: FALSE
    Width: 40
    Height: 30
    Max Scale: -1
    RNG Seed: 12345
    Create training samples from images collection…
    Unable to open file: C:\bienso.vec
    Done. Created 0 samples

    1. có thể là bạn để trong ổ C nên không có quyền tạo file, bạn chuyển sang ổ D xem thử

    1. sử dụng phiên bản opencv cũ hơn sẽ có, mình đang sử dụng 3.4.2

    1. Tùy vào loại vết xước, màu sắc, chất liệu của vật thể thì bạn lựa chọn thuật toán cho phù hợp:
      – Nếu vết xước lớn, có hình dạng dễ nhìn thì sử dụng contour
      – Nếu vết xước tạo màu khác biệt (như làm xước sơn) thì sử dụng HSV
      – …
      Tốt nhất là bạn vào group upload hình vết xước để mọi người hỗ trợ https://www.facebook.com/groups/thigiacmaytinh

    2. Anh cho em hỏi là sau khi mình có kêt quả xử lí ảnh rồi. Em muốn giao tiếp giữa opencv với 1 vi điều khiển (arduino) thì làm thế nào ạ?

    3. Bản chất của việc gửi dữ liệu tới Arduino là gửi dữ liệu kiểu serial tới cổng COM. Trong example của Arduino có phần 04.Communication, bạn vào đó tìm hiểu cách nhận dữ liệu của Arduino. Còn gửi dữ liệu thì bạn tìm theo từ khóa như
      c++ send serial data arduino, ví dụ như bài: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498

      Còn nếu không sử dụng được để mình viết 1 bài về giao tiếp cơ bản

    4. Em đã copy code cũng như làm theo 1 một số hướng dẫn nước ngoài nhưng cái visual 2015 nó không chạy được. Anh có thể gửi cho em 1 bài giao tiếp cơ bản c++ với arduino được không ạ (gmail:phungducdung97@gmail.com)? em cảm ơn rất nhiều!!!

      Anh cho em hỏi làm thêm phần giao diện trên c++ kết hợp với xử lí ảnh thì làm thế nào ạ? em biết nhiều người dùng c#(hạn chế về open cv) và dùng MFC(khó hiểu ạ). Anh có hướng nào không ạ? em cảm ơn!!

    5. Bạn có tài liệu về giao tiếp giữa Visual Studio và Arduino ko? Cho mình xin với! Hihi

  5. opencv_createsamples.txt -vec D:\bienso.vec -info D:\plate_image\positive\location.txt -num 2000 -w 40 -h 30
    Em xin hỏi cái lệnh này làm viết trong visual c++ hay trong file opencv_creatsaple.exe vậy?

  6. Cho em hỏi các thông số phụ mà anh không đề cập như: rngseed và maxscale để làm gì ạ?
    Thêm nữa dãy các thông số [inv], [randinv],… là để tạo thêm ảnh DƯƠNG ngẫu nhiên đúng không ạ?
    Em xin cảm ơn!

    1. “rngseed và maxscale”: thông số này lạ quá, chắc version mới có thêm mà mình chưa biết. Còn [inv], [randinv] đúng là tạo mẫu thêm bằng cách inverse ảnh

  7. Để thực hiện việc phát hiện biển số xe (cả biển số dài và biển số vuông)
    Có thể dùng 1 file cascade hay không. hay cần phải tách ra dữ liệu cascade cho biển số dài và cascade cho biển số vuông.
    Vì trong cascade mình thấy có mục with và height

    1. Bạn cần train 2 file riêng vì kích thước của 2 biển là khác nhau hoàn toàn nhé

  8. Anh ơi em tạo file cascade thì bị lỗi này. Em tìm mãi ko biết tại sao anh xem em với

    C:\OpenCV3.4\opencv\build\x64\vc15\bin>opencv_traincascade.exe -data D:\UMC_LCA\Haidh\CrawlScrapingData\SetUp\ComputerVision\DragDropImage\DataOut -vec D:\UMC_LCA\Haidh\CrawlScrapingData\SetUp\ComputerVision\DragDropImage\shape.vec -bg D:\UMC_LCA\Haidh\CrawlScrapingData\SetUp\ComputerVision\DragDropImage\Negative\location.txt -numPos 9 -numNeg 6 -numStages 20 -minHitRate 0.995 -maxFalseAlarmRate 0.5 -w 40 -h 30
    PARAMETERS:
    cascadeDirName: D:\UMC_LCA\Haidh\CrawlScrapingData\SetUp\ComputerVision\DragDropImage\DataOut
    vecFileName: D:\UMC_LCA\Haidh\CrawlScrapingData\SetUp\ComputerVision\DragDropImage\shape.vec
    bgFileName: D:\UMC_LCA\Haidh\CrawlScrapingData\SetUp\ComputerVision\DragDropImage\Negative\location.txt
    numPos: 9
    numNeg: 6
    numStages: 20
    precalcValBufSize[Mb] : 1024
    precalcIdxBufSize[Mb] : 1024
    acceptanceRatioBreakValue : -1
    stageType: BOOST
    featureType: HAAR
    sampleWidth: 40
    sampleHeight: 30
    boostType: GAB
    minHitRate: 0.995
    maxFalseAlarmRate: 0.5
    weightTrimRate: 0.95
    maxDepth: 1
    maxWeakCount: 100
    mode: BASIC
    Number of unique features given windowSize [40,30] : 700300

    ===== TRAINING 0-stage =====
    <BEGIN
    POS count : consumed 9 : 9
    Train dataset for temp stage can not be filled. Branch training terminated.
    Cascade classifier can't be trained. Check the used training parameters.

    1. cần vài ngàn ảnh để train nhé bạn, có vài ảnh không train được đâu

  9. Anh cho e hỏi :
    – file location.txt phải đặt trong thư mục chứa ảnh dương.
    – file list.txt phải đặt trong thư mục chứa ảnh âm.
    Phải ko hả anh?
    Nếu copy 2 file đó ra thư mục khác thì nó không train đc hả anh?
    Cám ơn anh

    1. ý bạn file list.txt là file chỉ mục các ảnh negative phải không?
      Còn file thì nó phụ thuộc vào đường dẫn tuyệt đối và tương đối, nếu không nắm rõ bạn cứ để đường dẫn tuyệt đối cho chắc ăn nhé

    2. Vâng file list.txt là chỉ mục của các file ảnh âm anh. E có thắc mắc là:
      – trong nội dung của file đó chứa thông tin của các ảnh(name, size, count) mà ko chứa location của các ảnh, thì ko hiểu làm cách nào chương trình lại lấy đc ảnh để so sánh ạ.
      – Vì thế nên em mới hỏi anh là phải đặt file chỉ mục cùng với thư mục chứa các ảnh

    3. Mình ko nhớ kỹ nhưng hầu hết các chương trình sẽ nối folder hiện tại vào các file name, như comment trước thì bạn nên để đường dẫn như D:\image\a.jpg

    4. Anh ơi e vẫn chưa làm đc file xml. Em run opencv_trancascade.exe … các thông số
      thì ct báo lỗi như sau:

      OpenCV: terminate handler is called! The last OpenCV error is:
      OpenCV(3.4.11) Error: Assertion failed (_img.rows * _img.cols == vecSize) in CvCascadeImageReader::PosReader::get, file C:\build\3_4_winpack-build-win64-vc15\opencv\apps\traincascade\imagestorage.cpp, line 153

      Thật sự em thử thay đổi các thông số khi truyền vào vẫn bị lỗi đó.
      EM LÀM ĐƠN GIẢN LÀ TẠO FILE .XML CHO KHI TÌM LOGO TRONG ẢNH

    5. Lỗi này do bạn tạo file .vec bị sai width, height. Bạn xem lại width – height lúc tạo mẫu với lúc train có giống nhau không?

    6. – Em tạo file vec chỉ có 1 ảnh dương là ảnh logo
      – sau đó train call opencv_traincascade.exe thì truyền tham số bg là file text chứa tên của các ảnh negative(file này được tạo từ ứng app: Object Locator của anh.

      Chương trình vẫn báo lỗi ở trên. Thật sự em ko biết làm thế nào nữa anh ạ

    7. Còn các ảnh mẫu trong thư mục pos vaf nega thì có size khác nhau. Không biết có phải vấn đề ở đây ko anh?

  10. Em sai ở w và h em vừa ktra lại rồi hết lỗi ở trên nhưng lại sinh ra lỗi này anh ạ.
    Call lệnh train mà tham số có 1 ảnh dương(là ảnh loggo) numPos=1
    thì chương trình lại báo lỗi là
    POS count : consumed 1 : 1

    Train dataset for temp stage can not be filled. Branch training terminated.
    Cascade classifier can’t be trained. Check the used training parameters.

    1. 1 ảnh không làm được đâu, cho dù train được thì cũng không sử dụng được, bạn nên tìm nhiều ảnh hoặc tự tạo nhiều ảnh từ 1 ảnh gốc để training

    2. Anh ơi em generate file chỉ mục ảnh âm từ App Object Locator của anh ra file location.txt
      Nội dung trong file kiểu nhứ sau:
      1.jpg
      10.jpg
      100.jpg
      101.jpg
      102.jpg
      103.jpg
      104.jpg
      105.jpg
      ….
      không biết có đúng không anh
      Mà em chạy nó vẫn báo cái lỗi này:
      POS count : consumed 1500 : 1500
      Train dataset for temp stage can not be filled. Branch training terminated.
      Cascade classifier can’t be trained. Check the used training parameters.

      Làm phiền anh quá 🙁

    3. Từ opencv 3.x thì bạn nên để đường dẫn tuyệt đối nhé, nếu bạn download bộ ảnh của mình thì chạy file _create_bg_file.bat là sẽ tạo file bg.txt tự động

Leave a Reply