

UGRectRingPipeline
Trái tim của bộ phát hiện Ultimate Goal chính là pipeline. Pipeline chỉ là một cách gọi “hoa mỹ” để mô tả chuỗi các chỉ dẫn được thực thi liên tục nhằm thao tác trên hình ảnh (trong trường hợp này là hình ảnh mà camera nhìn thấy). Nếu bỏ qua phần code phức tạp, pipeline có thể được rút gọn thành các bước sau:
Nhận dữ liệu đầu vào (Receiving the Input)
Ở dòng này, những gì camera nhìn thấy được truyền vào và biểu diễn dưới dạng một ma trận (matrix).
Xử lý dữ liệu đầu vào (Manipulating the Input)
Dòng đầu tiên sẽ chuyển không gian màu của ma trận đầu vào từ RGB sang YCrCb.
Do cách YCrCb biểu diễn màu sắc bằng:
Y: độ chói (luminance)
Cr: sắc độ đỏ (chroma of red)
Cb: sắc độ xanh lam (chroma of blue)
nên các giá trị màu sẽ ổn định hơn dưới các điều kiện ánh sáng khác nhau.
Tiếp theo, ta vẽ 2 hình chữ nhật lên màn hình với vị trí được xác định trước:
Hình chữ nhật phía trên: nơi vòng thứ 4 sẽ xuất hiện
Hình chữ nhật phía dưới: nơi vòng đầu tiên sẽ xuất hiện
Sau đó, ta trích xuất giá trị Cb của từng vùng xác định để so sánh.
Tìm giá trị Cb (Finding CB Values)
Ở đây, ta cắt ma trận để chỉ giữ phần nằm bên trong hai hình chữ nhật.
Sau đó, ta tính giá trị trung bình của các pixel trong từng vùng và lưu chúng vào:
bottomAveragetopAverage
Tạo một instance của UGRectDetector
UGRectDetector là một class minh họa cách sử dụng pipeline.
Để có giải thích chi tiết hơn về từng thành phần hoặc các chức năng mở rộng, vui lòng truy cập tại đây.
Đầu tiên, tạo một instance của UGRectDetector. Constructor của detector được overload, bạn có thể chọn một trong hai:
hMap: một instance của
HardwareMapwebcamName: tên của webcam
Nếu sử dụng constructor thứ nhất, detector sẽ dùng camera của điện thoại. Nếu sử dụng constructor thứ hai, detector sẽ dùng webcam.
Điều chỉnh cài đặt Detector (Manipulating Detector Settings)
Bạn có thể thay đổi hướng, chiều rộng và chiều cao của camera cho tất cả các instance (vì camera không thay đổi giữa các lần chạy).
Bạn cập nhật các cài đặt này bằng cách thay đổi các biến static:
Thiết lập vị trí hình chữ nhật (Setting Rectangle Positions)
topRectHeightPercentage: phần trăm chiều cao của ảnh đầu vào (dưới 1), dùng để tính tọa độ y đầu tiên của hình chữ nhật trên
topRectWidthPercentage: phần trăm chiều rộng của ảnh đầu vào (dưới 1), dùng để tính tọa độ x đầu tiên của hình chữ nhật trên
bottomRectHeightPercentage: phần trăm chiều cao của ảnh đầu vào (dưới 1), dùng để tính tọa độ y đầu tiên của hình chữ nhật dưới
bottomRectWidthPercentage: phần trăm chiều rộng của ảnh đầu vào (dưới 1), dùng để tính tọa độ x đầu tiên của hình chữ nhật dưới
rectangleWidth: chiều rộng hình chữ nhật (pixel)
rectangleHeight: chiều cao hình chữ nhật (pixel)
Sau khi tạo detector và thiết lập vị trí hình chữ nhật, hãy liên tục gọi:
để lấy số vòng trong chồng.
UGContourRingPipeline
Vision Pipelines là trái tim của mọi Ultimate Goal Detector. Pipeline là tập hợp các chỉ dẫn được áp dụng cho mỗi frame từ camera.
Pipeline này sử dụng Contours (đường bao) và Aspect Ratio (tỉ lệ hình dạng) để xác định số vòng hiện có trong chồng vòng.
Sử dụng Detector (Using the Detector)
Contour pipeline đi kèm một detector dựng sẵn có thể dùng ngay trong opmode.
UGContourRingDetector là object chạy pipeline này.
Để tạo detector, có nhiều constructor khác nhau (một số có tham số tùy chọn):
Bạn có thể điều chỉnh các cài đặt của contour detector tương tự detector hình chữ nhật.
Khởi tạo detector
Lệnh này khởi tạo pipeline với các cài đặt đã cấu hình.
Để lấy chiều cao (số vòng) mà pipeline xác định, gọi:
Tinh chỉnh (Tuning)
Pipeline có nhiều giá trị có thể điều chỉnh để tăng hoặc giảm độ chính xác.
Tất cả các giá trị cấu hình được lưu trong companion object tên là Config.
Trong Config có 6 biến, trong đó 2 biến là hằng số và không thể thay đổi.
lowerOrange: ngưỡng cam dưới dùng khi tạo mask
upperOrange: ngưỡng cam trên dùng khi tạo mask
CAMERA_WIDTH: độ phân giải chiều rộng của camera
HORIZON: giá trị đường chân trời trên trục y, dùng cho kiểm tra horizon
MIN_WIDTH: giá trị chiều rộng tối thiểu sinh ra bằng thuật toán
BOUND_RATIO: giá trị tỉ lệ hình dùng để phân biệt 1 vòng và 4 vòng
HORIZON là giá trị bạn rất có thể phải tinh chỉnh. Giá trị mặc định có thể quá nghiêm ngặt hoặc không.
Giá trị này sẽ hiển thị trên ảnh dưới dạng đường màu đỏ. Mọi thứ nằm trên đường đỏ sẽ bị bỏ qua trong tính toán pipeline. Hãy đảm bảo rằng cạnh dưới của khung contour chồng vòng nằm dưới đường horizon.
LƯU Ý:
Ảnh trả về từ pipeline sẽ chủ yếu là màu đen để minh họa phần logic bị bỏ qua.
Tất cả contour được vẽ màu xanh lá
Hình chữ nhật bao quanh contour lớn nhất dưới horizon được vẽ màu xanh dương
Do Config là companion object, nên mọi instance của UGContourRingPipeline đều dùng chung cấu hình.
Các giá trị này có thể thay đổi trong các bản phát hành tương lai.
Giải thích thuật toán của Pipeline
Nhận dữ liệu đầu vào
Những gì camera nhìn thấy được truyền vào pipeline dưới dạng OpenCV Mat (viết tắt của matrix).
Xử lý dữ liệu đầu vào
Đầu tiên, ta chuyển Mat sang không gian màu YCrCb để hỗ trợ threshold tốt hơn.
Ta thực hiện phép inRange và lưu kết quả vào mask.
Mask là ảnh trắng–đen:
Pixel trắng: nằm trong ngưỡng màu cam
Pixel đen: không nằm trong ngưỡng màu cam
Dùng Gaussian Blur để loại bỏ nhiễu giữa các vòng trong chồng.
Do ánh sáng hoặc bóng, có thể xuất hiện khoảng trống không mong muốn.
Tìm Contours
Contour là đường cong nối các điểm liên tục có cùng màu hoặc cường độ.
Contour rất hữu ích trong phân tích hình dạng và nhận dạng vật thể.
Sau khi tìm contour, ta duyệt tuyến tính qua danh sách contour.
Với mỗi contour:
Tính bounding rectangle
Chọn rectangle có chiều rộng lớn nhất
Mục đích là tránh nhầm chồng vòng với các vật thể màu cam khác.
Chồng vòng thường là khối màu cam lớn nhất trong tầm nhìn.
Pipeline cũng có kiểm tra horizon:
Bất cứ thứ gì nằm trên horizon đều bị bỏ qua, kể cả khi có chiều rộng lớn nhất.
Điều này giúp tránh nhầm red goal với vòng cam, vì YCrCb rất kém trong việc phân biệt đỏ và cam.
Tính Aspect Ratio
Hoặc tương đương:
Sau khi xác định contour rộng nhất (giả định là chồng vòng), ta tính tỉ lệ chiều cao / chiều rộng của bounding rectangle.
Câu hỏi thường gặp
Vì sao không chỉ đo chiều cao của bounding rectangle?
→ Vì độ phân giải camera khác nhau sẽ cho chiều cao pixel khác nhau dù đều là 4 vòng.
Nhưng bạn vẫn dùng chiều rộng (pixel) mà?
→ Đúng, nhưng chiều rộng chồng vòng là hằng số (luôn chỉ rộng bằng 1 vòng).
Nhờ vậy ta có thể sinh ra MIN_WIDTH bằng thuật toán, còn chiều cao thì không.

