Sử dụng thư viện Thread building blocks trong OpenCV C++

tutorial
computer-vision

#1

Mình tham khảo bài viết gốc của tác giả ở đây : (https://www.theimpossiblecode.com/blog/faster-opencv-smiles-tbb/)

Link git gốc của tác giả : https://github.com/sagi-z/OpenCVPipeline

Trong tutorial này, mình sẽ sử dụng thư viện TBB(Thread building blocks) với thư viện OpenCV để tận dụng CPU tăng tốc độ xử lý bằng C++.

1. Lập trình đa luồng. (Multithread Programming)

Với những bạn chưa đã biết sơ qua về lập trình đa luồng, các bạn có thể bỏ qua phần này luôn. Thread là thành phần nhỏ nhất mà các chương trình có thể chia ra được. Hiểu đơn giản nó là một bước trong một chương trình. Mình tạm dùng thread là bước nhỏ. Thường các chương trình có thể được chia làm nhiều bước nhỏ.

Ví dụ: Chương trình của bạn nhận vào 1 chuỗi(string), chuyển tất cả chữ viết thường thành chữ viết hoa, in ra màn hình. Bước nhỏ đầu tiên là nhận vào, bước nhỏ thứ 2 là chuyển viết thường thành viết hoa, bước nhỏ cuối cùng là in ra. Ta giả sử chương trình nhận vào nhiều chuỗi.

Nếu lập trình đơn luồng, các bạn có thể làm theo từng bước 1 như miêu tả : Chuỗi 1 -> bước nhỏ 1 -> bước nhỏ 2 -> bước nhỏ 3 -> màn hình -> chuỗi 2 -> …

Đối với lập trình đa luồng, ta chia 3 bước nhỏ đó ra. Khi bước nhỏ thứ 3 đang in ra chuỗi đầu tiên, bước nhỏ 2 sẽ chuyển chuỗi thứ 2, bước nhỏ thứ nhất sẽ nhận vào chuỗi 1. 3 bước nhỏ này được thực hiện độc lập và đồng thời.

Ưu điểm trong trường hợp này là bước nhỏ 1 không phải đợi bước nhỏ 3 in kết quả ra màn hình xong mới nhận chuỗi, mà có thể nhận chuỗi mới ngay trong khi bước nhỏ 2 đang làm việc của mình. Đây chỉ là giới thiệu sơ lược.

2. Thư viện TBB

Việc lập trình đồng bộ thuần bằng thư viện thread của C++ thường khá phức tạp, cần phải chú ý nhiều đến race condition, thread safe, các khóa mutex,…

Thư viện Threading Building Blocks là thư viện C++ phục vụ lập trình đa luồng để ta có thể dễ dàng phân tách các chương trình ra nhiều bước nhỏ khác nhau. TBB đơn giản hóa quá trình phân chia này. Chương trình chính/ hàm chính sẽ chuyển thành một chu trình (pipeline), các bước nhỏ sẽ được phân thành các filter. Việc sử dụng các khóa mutex, đảm bảo thread-safe sẽ do thư viện tự động xử lý.

3. Sử dụng thư viện TBB

Trong tutorial này, ta sẽ làm 1 chương trình đơn giản detect face và mặt cười bằng bộ phân lớp HaarCascade. Sau đó vẽ hình ảnh mặt+ mặt cười, đo mức độ “vui vẻ” của nhận vật trong hình. Do chương trình này đơn giản, mình sẽ chỉ để souce code https://github.com/NguyenVanThanhHust/OpenCV_with_TBB/blob/master/Example_Project/Source/smile_face.cpp Chương trình có 2 hàm :

  • main() : nhận khung hình từ video, đo lường thời gian xử lý của chương trình
  • detectAndDraw(): nhận khung hình, detect mặt và vẽ hình.

Ta thấy hàm detectAndDraw nhiều hàm con. Hàm này có chu trình (pipeline) như sau :

Ta thấy các hàm con trong hàm này gặp phải vấn đề là các hàm con đợi lẫn nhau. Ta có thể chia hàm này ra để trong lúc hàm con này xử lý kết quả từ frame này thì hàm con trước nó không cần phải đợi mà có thể xử lý kết quả từ frame tiếp theo luôn.

Để đảm bảo kết quả của bước này có thể sử dụng ở bước tiếp theo mà ko cần chỉnh sửa nhiều, ta sẽ định nghĩa 1 struct mới

2

Ta sẽ định nghĩa chu trình bằng với thư viện TBB : 2

Với mỗi hàm con trong chu trình, ta sẽ tạo một filter để xử lý. Điều này sẽ giúp ta xử lý đồng bộ nhiều frame cùng một lúc, vì trong lúc filter này đang xử lý kết quả của frame khác. Mình sẽ ví dụ 1 filter đầu tiên, các bạn có thể làm tương tự với các filter tiếp theo.

Souce code full : https://github.com/NguyenVanThanhHust/OpenCV_with_TBB/blob/master/Example_Project/Source/smile_face_tbb.cpp Ở đây mình sẽ thử nghiệm với một video dài 6p6s : John Snow knows nothing

4. Kết quả :

Mình dùng Window 10 : chip AMD Ryzen 5, RAM 8G, Visual Studio 2015 Community Với video dài 6p6s, thời gian xử lý với khi ko sử dụng TBB là 864s, có sử dụng TBB là 622s, cpu usage tăng từ 46% lên 75% (xem = task manager)

Các bạn có thể thấy là sử dụng thư viện TBB giúp bạn tận dụng tối ưu hơn nguồn tài nguyên CPU của bạn, giảm thời gian xử lý. Nếu có gì thắc mắc/ góp ý, các bạn comment dưới post này để mình sửa nhé. Đây là post đầu tiên mình viết