Hệ thống kiểm tra thị giác (VIS) là gì?

hệ thống kiểm tra thị giác

Hệ thống kiểm tra thị giác (Vision Inspection System – VIS), còn được gọi là kiểm tra thị giác tự động (Automated Visual Inspection – AVI) hoặc hệ thống máy thị giác (Machine Vision System), là một cấu hình dựa trên máy tính sử dụng camera và phần mềm xử lý ảnh để tự động kiểm tra sản phẩm, vật liệu hoặc quy trình nhằm phát hiện lỗi, sai sót hoặc đánh giá mức độ tuân thủ tiêu chuẩn chất lượng. 

Một hệ thống kiểm tra thị giác (VIS) thường bao gồm các thành phần chính sau: 

  • Camera (một hoặc nhiều camera): Camera dùng để chụp ảnh; đi kèm chiếu sáng có kiểm soát nhằm làm nổi bật các đặc trưng quan trọng của đối tượng cần kiểm tra. 
  • Bộ xử lý (Processing Unit): Có thể là PC công nghiệp, workstation GPU hoặc thiết bị nhúng (ví dụ Jetson, FPGA) để chạy các thuật toán thị giác máy tính. 
  • Phần mềm (Software): “Bộ não” của hệ thống kiểm tra thị giác. Phần mềm có thể là:
    • Thuật toán thị giác cổ điển (ví dụ phát hiện biên, khớp mẫu, lọc hình thái học),
    • Mô hình học sâu (ví dụ CNN cho phân loại; YOLO, Faster R-CNN, RF-DETR cho phát hiện đối tượng; U-Net cho phân đoạn),
    • Thuật toán phát hiện bất thường (ví dụ autoencoder, mô hình one-class). 
  • Phần cứng tích hợp dây chuyền (Hardware/Integration): Các hệ thống phần cứng kết nối với dây chuyền sản xuất, PLC hoặc robot để đưa ra quyết định đạt/không đạt, phân loại, hoặc kích hoạt hành động tiếp theo. 

>>> Xem thêm các bài viết khác:

Hệ thống kiểm tra thị giác
Hệ thống kiểm tra thị giác. (Nguồn: Internet)

Hệ thống kiểm tra thị giác có chức năng gì?

Một hệ thống kiểm tra thị giác có thể đảm nhiệm nhiều tác vụ kiểm tra, đo lường và xác minh trong công nghiệp, điển hình gồm:

Phát hiện lỗi

Đây là ứng dụng phổ biến nhất của hệ thống kiểm tra thị giác: nhận diện các lỗi như vết xước, nứt, móp, thiếu chi tiết, biến dạng trên sản phẩm. Ví dụ:

  • Trong sản xuất ô tô, VIS phát hiện các vết nứt rất nhỏ ở linh kiện động cơ.
  • Trong điện tử, VIS phát hiện mối hàn thiếu hoặc chip đặt sai vị trí trên PCB (bảng mạch in). 

>>> Xem thêm:

CBN chèn hệ thống kiểm tra khuyết tật
CBN chèn hệ thống kiểm tra khuyết tật. (Nguồn: Internet)

Đo lường và kiểm tra kích thước 

Hệ thống kiểm tra thị giác được dùng rộng rãi để đo kiểm kích thước hình học như chiều dài, chiều rộng, đường kính, góc, và thậm chí độ nhám bề mặt. Ví dụ:

  • Trong hàng không vũ trụ, VIS đảm bảo cánh tuabin hoặc bánh răng đạt dung sai kích thước nghiêm ngặt.
  • Trong gia công kim loại, VIS đo bước ren và độ thẳng hàng của lỗ. 
Hệ thống kiểm tra thị giác đo lường và kiểm tra
Hệ thống kiểm tra thị giác để đo khe hở đầu cánh quạt trong tuabin gió. (Nguồn: Internet)

Xác minh mẫu và nhãn

Hệ thống kiểm tra thị giác xác minh logo, chữ in, mã vạch và mã định danh (serialization) có tồn tại, đúng vị trí, và đọc được. Các hệ VIS nâng cao còn kiểm tra chất lượng in, phát hiện lem mực hoặc phai mực. 

Xác minh lắp ráp 

Trong quá trình lắp ráp, hệ thống kiểm tra thị giác đảm bảo mọi thành phần:

  • Có mặt đầy đủ,
  • Đặt đúng vị trí,
  • Căn chỉnh chính xác.

Hệ thống có thể kiểm tra hướng của vít, độ khớp của đầu nối, hoặc tình trạng gioăng đã được đặt đúng hay chưa. Ví dụ: trên dây chuyền lắp ráp ô tô, VIS xác nhận túi khí, vị trí gá dây an toàn và bó dây điện được lắp đúng trước khi xe chuyển sang công đoạn tiếp theo. 

>>> Xem thêm: Xây Dựng Mô Hình Ngôn Ngữ Thị Giác với Next.js & Roboflow

Hệ thống robot lắp ráp bu lông
Hệ thống robot lắp ráp bu lông. (Nguồn: Internet)

Kiểm tra chất lượng bề mặt 

Hệ thống kiểm tra thị giác phát hiện lỗi bề mặt trên sơn, lớp phủ, đường hàn, kính, hoặc đường mạch trên PCB. Ví dụ:

  • Trong thiết bị điện tử tiêu dùng, VIS phát hiện vết xước trên màn hình điện thoại.
  • Trong sản xuất thép, VIS phát hiện rỗ bề mặt, bong vảy (scaling) hoặc vết xước trên tấm cán. 
Hệ thống kiểm tra bề mặt màn hình điện thoại thông minh
Hệ thống kiểm tra bề mặt màn hình điện thoại thông minh. (Nguồn: Internet)

Xác minh màu sắc và sắc độ 

Một số sản phẩm phải tuân thủ nghiêm ngặt chuẩn màu hoặc lớp hoàn thiện. Khi đó, hệ thống kiểm tra thị giác sẽ so sánh màu thu được từ camera với giá trị tham chiếu để đảm bảo tính nhất quán màu sắc. 

>>> Xem thêm:

Kiểm tra và phân loại màu SICK
Kiểm tra và phân loại màu SICK. (Nguồn: Internet)

Định vị và căn chỉnh

Ngoài kiểm tra chất lượng, hệ thống kiểm tra thị giác còn làm “mắt dẫn đường” cho robot/máy bằng cách phản hồi vị trí và hướng của chi tiết. Ví dụ: trong hệ pick-and-pack ngành điện tử, VIS căn chỉnh chip với độ chính xác dưới milimet trước khi gắp đặt lên PCB. 

Hệ thống gắp và đặt tự động bằng thị giác của Oxipitalai
Hệ thống gắp và đặt tự động bằng thị giác của Oxipitalai. (Nguồn: Internet)

Đếm và phân loại 

Hệ thống kiểm tra thị giác có thể đếm số lượng vật thể trong một lô (ví dụ số viên thuốc trong vỉ, số trứng trong khay) và tự động phân loại theo nhóm tốt/xấu, theo dải kích thước hoặc theo loại lỗi. Ứng dụng này rất phổ biến trong logistics, nông nghiệp và chế biến thực phẩm. 

>>> Xem thêm

Hệ thống kiểm tra thị giác dùng để phân loại đậu lăng xanh
Hệ thống kiểm tra thị giác dùng để phân loại đậu lăng xanh. (Nguồn: Internet)

Kiểm tra an toàn và tuân thủ 

Trong các ngành có quy định chặt, hệ thống kiểm tra thị giác đảm bảo sản phẩm đạt yêu cầu về dấu hiệu an toàn, tem niêm phong chống giả/mở, và ký hiệu quy chuẩn. Ví dụ: trong đóng gói dược phẩm, VIS kiểm tra nhãn an toàn trẻ em bị thiếu hoặc thông tin liều dùng in sai. 

Hệ thống kiểm tra thị giác kiểm tra sự tuân thủ quy định trong ngành dược phẩm
Hệ thống kiểm tra thị giác Systech dùng để kiểm tra sự tuân thủ quy định trong ngành dược phẩm. (Nguồn: Internet)

Các loại hệ thống kiểm tra thị giác

Hệ thống kiểm tra thị giác thường được phân loại theo cách chụp ảnh, phân tích ảnh, và cách triển khai. Tài liệu này trình bày theo ba nhóm chính:

1. Theo phương thức thu nhận ảnh

  • Hệ thống thị giác 2D: dùng camera area-scan hoặc line-scan để thu ảnh phẳng; ứng dụng điển hình gồm kiểm tra PCB, xác minh nhãn và kiểm tra chai/lon. 
  • Hệ thống thị giác 3D: dùng stereo vision, laser triangulation, structured light hoặc camera ToF để thu độ sâu và biên dạng bề mặt; ứng dụng gồm kiểm tra đường hàn, đo hình dạng và dẫn hướng robot. 
  • Hệ thống đa phổ/siêu phổ (Multispectral/Hyperspectral): thu thông tin vượt dải nhìn thấy (hồng ngoại, UV, hyperspectral) để phát hiện thành phần hóa học, nhiễm bẩn hoặc các lỗi rất tinh vi. 
Hệ thống kiểm tra thị giác 3D của Cognex 2
Hệ thống kiểm tra thị giác 3D của Cognex 2. (Nguồn: Internet)

2. Theo phương pháp xử lý 

  • Hệ thống kiểm tra thị giác dựa luật/cổ điển (Rule-Based/Classical VIS): dựa trên đặc trưng định nghĩa trước, ngưỡng (threshold), phát hiện biên và khớp mẫu; ưu điểm là nhanh và dễ giải thích nhưng kém linh hoạt. 
  • Hệ thống kiểm tra thị giác học sâu (Deep Learning Based VIS): dùng CNN và các kiến trúc học sâu hiện đại cho phân loại, phát hiện, phân đoạn; thường bền vững hơn trước thay đổi chiếu sáng, tư thế và nhiễu. 
  • Hệ thống kiểm tra thị giác phát hiện bất thường (Anomaly Detection VIS): huấn luyện chủ yếu trên mẫu “tốt”, sau đó đánh dấu các sai lệch; phù hợp khi mẫu lỗi hiếm hoặc khó định nghĩa (ví dụ các bộ dữ liệu MVTec AD, Kolektor). 

3. Theo nhiệm vụ kiểm tra 

Các hệ thống thuộc danh mục này được phân nhóm dựa trên nhiệm vụ cụ thể mà chúng thực hiện:

  • Hệ thống phân loại: quyết định đạt/không đạt hoặc gán nhóm lỗi (ví dụ vải OK vs NG). 
Phân loại khuyết tật.
Phân loại khuyết tật. (Nguồn: Internet)
  • Hệ thống phát hiện đối tượng : định vị và nhận diện lỗi/thiếu linh kiện (ví dụ PCB bị short, thiếu vít). 
Xác định vị trí linh kiện và lắp ráp
Hệ thống kiểm tra thị giác xác định vị trí linh kiện và lắp ráp. (Nguồn: Internet)
  • Hệ thống phân đoạn: tạo bản đồ lỗi theo từng pixel để đo kích thước/hình dạng chính xác (ví dụ nứt, lỗi bề mặt thép). 
Phát hiện và phân tích lỗi
Hệ thống kiểm tra thị giác phát hiện và phân tích lỗi. (Nguồn: Internet)
  • Hệ thống OCR: đọc và xác minh chữ in/khắc, số seri, mã vạch, QR và hạn sử dụng trên sản phẩm. 
Hệ thống kiểm tra thị giác dùng để đọc văn bản
Hệ thống kiểm tra thị giác dùng để đọc văn bản. (Nguồn: Internet)

Cách chọn công cụ hệ thống kiểm tra thị giác phù hợp

Việc chọn đúng hệ thống kiểm tra thị giác bắt đầu bằng cách đối chiếu công cụ với bài toán. Trước tiên là yếu tố thu nhận ảnh: kiểm tra tiêu chuẩn như PCB có thể chỉ cần camera thường, trong khi các bài toán chuyên biệt về an toàn thực phẩm hoặc dược phẩm có thể cần ảnh đa phổ/siêu phổ. 

Tiếp theo là phương pháp xử lý: thị giác cổ điển nhanh và dễ giải thích nhưng hạn chế linh hoạt; học sâu xử lý biến thiên và độ phức tạp tốt hơn; phát hiện bất thường hữu ích khi lỗi hiếm hoặc khó định nghĩa. Một nền tảng tốt cần hỗ trợ huấn luyện, triển khai và bảo trì mô hình thuận lợi trên các hướng tiếp cận này. 

Bạn cũng cần đảm bảo hệ thống hỗ trợ đúng nhiệm vụ kiểm tra: phân loại cho đạt/không đạt, phát hiện đối tượng cho thiếu linh kiện, phân đoạn cho đo lường chính xác, hoặc OCR cho văn bản và mã định danh. Có nền tảng chỉ hỗ trợ một tác vụ, trong khi các nền tảng như Roboflow có thể hỗ trợ tổng hợp. 

Cuối cùng là khả năng mở rộng và tích hợp: một hệ thống kiểm tra thị giác tốt phải kết nối được với hệ tự động hóa (API, thiết bị biên, hoặc giao thức công nghiệp như MQTT và OPC-UA) và mở rộng từ thử nghiệm sang sản xuất. 

Roboflow được mô tả như một nền tảng “tất cả trong một”: hỗ trợ nhiều loại camera (webcam, IP, RTSP, camera công nghiệp) giúp không cần thay phần cứng; chuẩn hóa quản trị dữ liệu, gán nhãn, huấn luyện, đánh giá và triển khai. Mô hình có thể chạy trên thiết bị biên như Raspberry Pi/Jetson hoặc chạy trên cloud qua API; đồng thời hỗ trợ huấn luyện với dữ liệu nhỏ (vài trăm ảnh gán nhãn), cho phép ghép nhiều tác vụ kiểm tra trong cùng workflow và theo dõi hiệu năng mô hình theo thời gian. 

Hướng dẫn xây dựng hệ thống kiểm tra thị giác với Roboflow (bài toán lỗi PCB)

Phần này minh họa cách xây dựng một hệ thống kiểm tra thị giác để phát hiện lỗi PCB, cụ thể là phát hiện “missing holes” (lỗ bị thiếu) trên PCB. Quy trình gồm: huấn luyện mô hình trong Roboflow, tạo workflow hoàn chỉnh và triển khai qua ứng dụng Flet để kiểm tra trực tiếp. 

PCB là “xương sống” của điện tử hiện đại; chỉ một lỗi nhỏ cũng có thể gây trục trặc, giảm độ tin cậy hoặc làm hỏng toàn bộ sản phẩm. Vì vậy, hệ thống kiểm tra thị giác là thành phần trọng yếu trong sản xuất PCB, nhằm tự động phát hiện các lỗi như missing holes, mouse bites, open circuits, shorts, spurs và các vệt đồng thừa (spurious copper traces). So với kiểm tra thủ công, kiểm tra thị giác tự động nhanh hơn, chính xác hơn và ổn định hơn, đặc biệt trong môi trường sản xuất số lượng lớn. 

Hệ thống kiểm tra thị giác phát hiện sáu loại khuyết tật nhỏ trên mạch in
Hệ thống kiểm tra thị giác phát hiện sáu loại khuyết tật nhỏ trên mạch in (PCB). (Nguồn: Internet)

Các lỗi này được thể hiện trong hình trên, đại diện cho những vấn đề chất lượng phổ biến nhưng nghiêm trọng cần được xác định trước khi lắp ráp và triển khai. Hệ thống kiểm tra thị giác tự động mang lại kết quả nhanh hơn, chính xác hơn và nhất quán hơn so với việc kiểm tra thủ công, khiến nó trở nên không thể thiếu trong các môi trường sản xuất khối lượng lớn. Trong ví dụ này, chúng tôi tập trung vào việc phát hiện các lỗ bị thiếu (missing holes), một trong những lỗi PCB cơ bản nhất sử dụng quy trình thị giác máy tính toàn diện của Roboflow.

Bước 1: Chuẩn bị dữ liệu cho phát hiện lỗi PCB

Bước đầu tiên để xây dựng hệ thống kiểm tra thị giác cho PCB là tạo một project Object Detection mới. Bạn tải lên ảnh PCB có chứa lỗi nhìn thấy được, tập trung vào loại lỗi muốn phát hiện (trong ví dụ này là missing holes). Sau đó dùng công cụ gán nhãn để vẽ bounding box quanh từng vị trí lỗ bị thiếu, gán nhãn “missing hole” cho mỗi box; nếu muốn mở rộng, có thể thêm các nhóm lỗi khác như short, open circuit hoặc spur. 

Chú thích hình ảnh để phát hiện lỗi PCB trong Roboflow
Chú thích hình ảnh để phát hiện lỗi PCB trong Roboflow. (Nguồn: Internet)

Gán nhãn chính xác là điều kiện quyết định: bounding box cần ôm sát vùng lỗi, tránh lấy quá nhiều nền để mô hình học đúng đặc trưng của lỗi. 

Hình ảnh được chú thích cho "lỗ bị thiếu" trên PCB
Hình ảnh được chú thích cho “lỗ bị thiếu” trên PCB. (Nguồn: Internet)

Sau khi gán nhãn, bạn tạo các phiên bản dataset trong Roboflow với tiền xử lý (auto-orient, resize) và tăng cường dữ liệu (xoay, chỉnh sáng, crop). Mục tiêu là làm mô hình bền vững hơn trước biến thiên thực tế như khác biệt ánh sáng hoặc góc camera. 

Roboflow cũng hỗ trợ chia bộ dữ liệu thành train/validation/test để đánh giá công bằng; mỗi phiên bản vẫn giữ nhãn gốc, cho phép bạn thử nhiều chiến lược tiền xử lý và augmentation, huấn luyện nhiều mô hình và so sánh hiệu năng để xây dựng workflow phát hiện lỗi đáng tin cậy.

Bộ dữ liệu PCB
Bộ dữ liệu PCB. (Nguồn: Internet)

Bước 2: Huấn luyện mô hình phát hiện đối tượng

Khi dataset sẵn sàng, bước tiếp theo là huấn luyện mô hình phát hiện lỗi PCB. Quá trình huấn luyện bắt đầu bằng việc chọn kiến trúc; Roboflow hỗ trợ các lựa chọn như RF-DETR, Roboflow 3.0, YOLOv11… mỗi lựa chọn có ưu/nhược về độ chính xác, tốc độ và hiệu quả. Trong ví dụ, tác giả chọn Roboflow 3.0 làm mô hình nền. 

Chọn kiến ​​trúc mô hình
Chọn kiến ​​trúc mô hình. (Nguồn: Internet)

Tiếp theo là chọn kích thước mô hình (Fast, Accurate, Medium, Large, Extra Large) để cân bằng tốc độ và độ chính xác theo yêu cầu triển khai. Với bài toán kiểm tra PCB, lựa chọn “Accurate” nhằm đảm bảo phát hiện đáng tin cậy các lỗi nhỏ như missing holes. 

Roboflow cũng mô tả các chiến lược huấn luyện:

  • Train from Previous Checkpoint: tiếp tục cải thiện một mô hình đã huấn luyện.
  • Train from Public Checkpoint: khởi tạo từ trọng số pretrained (ví dụ MS COCO) rồi fine-tune cho lỗi PCB.
  • Train from Random Initialization: huấn luyện từ đầu (không khuyến nghị trừ khi dữ liệu rất lớn). 

Trong ví dụ này, tác giả chọn Train from Public Checkpoint (MS COCO) để tận dụng pretrained trên bộ dữ liệu chuẩn lớn và thích nghi cho tác vụ phát hiện lỗi PCB. Sau khi xác nhận thiết lập, nhấn Start Training để chạy huấn luyện; hoàn tất xong thì mô hình sẵn sàng để đánh giá và triển khai trong workflow kiểm tra PCB. 

Điểm kiểm tra huấn luyện
Điểm kiểm tra huấn luyện. (Nguồn: Internet)

Bước 3: Xây dựng Roboflow Workflow cho kiểm tra lỗi PCB

Bước tiếp theo là tạo workflow kiểm tra lỗi PCB trong Roboflow để kết nối mô hình với các khối hiển thị và đầu ra. Workflow nhận ảnh PCB đầu vào, chạy qua mô hình phát hiện đối tượng đã huấn luyện và tạo:

  • Kết quả trực quan (bounding box quanh missing holes),
  • Kết quả dạng JSON cấu trúc (tọa độ và confidence). 

Các khối trong workflow gồm: 

  • Inputs: định nghĩa dữ liệu đầu vào (ảnh PCB có thể có lỗi).
  • Object Detection Model: gọi mô hình phát hiện lỗi (ví dụ pcb-missing-hole-detection/5). Với mỗi dự đoán, mô hình xuất:
    • chiều rộng/cao ảnh,
    • tọa độ tâm bounding box (x, y),
    • chiều rộng/cao bounding box,
    • điểm tin cậy (confidence). 
  • Bounding Box Visualization: phủ bounding box lên ảnh PCB để đối chiếu trực quan vị trí lỗi. 
  • Label Visualization: hiển thị nhãn lỗi (ví dụ “missing hole”) kèm confidence phía trên bounding box. 
  • Outputs: thu kết quả cuối dưới hai dạng:
    • ảnh PCB đã chú thích (bounding box + nhãn),
    • JSON cấu trúc chứa kích thước, tọa độ và confidence để phục vụ báo cáo, phân tích hoặc tích hợp vào hệ QA sản xuất. 
Quy trình kiểm tra lỗi PCB
Quy trình kiểm tra lỗi PCB. (Nguồn: Internet)

Hệ thống kiểm tra thị giác này tiếp nhận ảnh PCB (Bảng mạch in), phát hiện và định vị các lỗ bị thiếu, cung cấp ảnh có chú thích để kiểm tra nhanh, và xuất dữ liệu dự đoán có cấu trúc để sử dụng trong các ứng dụng kiểm soát chất lượng tiếp theo.

Kết quả của quy trình làm việc
Kết quả của quy trình làm việc. (Nguồn: Internet)

Bước 4: Triển khai workflow vào ứng dụng kiểm tra trực tiếp (Flet)

Khi workflow hoàn tất, bước cuối cùng là triển khai thành ứng dụng chạy thực tế. Trong ví dụ, tác giả xây dựng ứng dụng desktop dựa trên Flet, kết nối Roboflow workflow, xử lý frame video/luồng camera theo thời gian thực và hiển thị:

  • ảnh trực quan có bounding box + nhãn,
  • cảnh báo trực tiếp khi phát hiện lỗi. 

Các thư viện cần thiết: 

  • pip install inference-sdk flet

Dưới đây là mã nguồn tham khảo (giữ nguyên để bạn có thể chạy trực tiếp theo đúng logic của ví dụ): 

# app.py

import base64

import threading

import cv2

import flet as ft

import numpy as np

import os

import time

from typing import Any, Dict, List, Tuple

from inference import InferencePipeline

TRANSPARENT_PX = (

 “iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAA”

 “AAC0lEQVR42mP8/x8AAwMB/axpQX0AAAAASUVORK5CYII=”

)

def np_to_b64_jpg(arr, assume_bgr=True, quality=85):

 if not assume_bgr:

  try:

   arr = cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)

  except Exception:

   pass

 ok, buf = cv2.imencode(“.jpg”, arr, [cv2.IMWRITE_JPEG_QUALITY, quality])

 if not ok:

  return None

 return base64.b64encode(buf).decode(“ascii”)

def main(page: ft.Page):

 page.title = “Roboflow Workflow (Model Visualization + Snapshot + Alerts)”

 page.window_width, page.window_height = 1120, 780

 # Controls

 api_key = ft.TextField(label=”API Key”, password=True,

  can_reveal_password=True, width=360)

 workspace = ft.TextField(label=”Workspace”, value=”tim-4ijf0″, width=200)

 workflow_id = ft.TextField(label=”Workflow ID”, value=”pcb-defect-inspection”,

  width=240)

 source = ft.TextField(label=”Video Source (0 / path / rtsp://…)”, value=”0″,

  width=360)

 assume_bgr_chk = ft.Checkbox(label=”Assume visualization is BGR”, value=True)

 start_btn = ft.ElevatedButton(“Start”)

 stop_btn = ft.ElevatedButton(“Stop”, disabled=True)

 snapshot_btn = ft.ElevatedButton(“Snapshot”, disabled=True)

 status = ft.Text(“Idle”)

 info = ft.Text(“”)

 debug = ft.Text(“”, size=11, color=ft.Colors.GREY_700) # shows parsed preds/frame

 save_info = ft.Text(“”)

 img_vis = ft.Image(src_base64=TRANSPARENT_PX, width=820, height=615,

  fit=ft.ImageFit.CONTAIN)

 # Alerts panel (right) — snapshot style (no scrolling/append)

 alerts_header = ft.Text(“Alerts (live)”, weight=ft.FontWeight.BOLD, size=16)

 alerts_count = ft.Text(“No detections yet”)

 clear_alerts_btn = ft.TextButton(“Clear”, icon=ft.Icons.CLEANING_SERVICES)

 # A Column we re-render entirely when detections change

 alert_list_col = ft.Column(spacing=6) # no auto-scroll, no append spam

 alerts_panel = ft.Container(

  width=280,

  height=650,

  padding=10,

  bgcolor=ft.Colors.BLUE_GREY_50,

  content=ft.Column(

   [

    ft.Row([alerts_header, clear_alerts_btn],

     alignment=ft.MainAxisAlignment.SPACE_BETWEEN),

    alerts_count,

    ft.Divider(),

    alert_list_col,

   ],

   expand=True,

  ),

  border_radius=12,

 )

 left_col = ft.Column(

  [

   ft.Row([api_key, workspace, workflow_id]),

   ft.Row([source, assume_bgr_chk]),

   ft.Row([start_btn, stop_btn, snapshot_btn, status]),

   ft.Row([info]),

   img_vis,

   debug,

   save_info,

  ],

  spacing=8,

 )

 page.add(ft.Row([left_col, alerts_panel],

  alignment=ft.MainAxisAlignment.START, spacing=12))

 # Runtime state

 state = {

  “running”: False,

  “pipeline”: None,

  “thread”: None,

  “started”: False,

  “last_vis_bgr”: None,

  “last_alert_signature”: None, # NEW: signature of last rendered detections

 }

 last_lock = threading.Lock()

 # Rendering helpers

 MAX_SHOW = 20 # cap cards shown to avoid overflow

 def make_alert_card(clz: str, x: float, y: float, conf: float, det_id: str) -> ft.Container:

  ts = time.strftime(“%H:%M:%S”)

  return ft.Container(

   bgcolor=ft.Colors.AMBER_50,

   border=ft.border.all(1, ft.Colors.AMBER_200),

   border_radius=8,

   padding=8,

   content=ft.Column(

    [

     ft.Row(

      [

       ft.Icon(ft.Icons.WARNING_AMBER, size=16, color=ft.Colors.AMBER_700),

       ft.Text(clz, weight=ft.FontWeight.BOLD, size=13, color=ft.Colors.AMBER_900),

      ],

      spacing=6,

     ),

     ft.Text(f”({x:.1f}, {y:.1f}) • conf {conf:.2%}”, size=12, color=ft.Colors.GREY_800),

     ft.Text(f”id: {det_id[:8]}… at {ts}”, size=11, color=ft.Colors.GREY_700),

    ],

    spacing=2,

   ),

  )

 def render_alert_snapshot(preds: List[Dict[str, float | str]]):

  “””Replaces the alert panel contents with the current detections (no scrolling).”””

  alert_list_col.controls.clear()

  if not preds:

   # Calm empty state

   alert_list_col.controls.append(

    ft.Container(

     bgcolor=ft.Colors.GREEN_50,

     border=ft.border.all(1, ft.Colors.GREEN_200),

     border_radius=8,

     padding=10,

     content=ft.Row(

      [

       ft.Icon(ft.Icons.CHECK_CIRCLE, color=ft.Colors.GREEN_600, size=18),

       ft.Text(“No defects detected”, color=ft.Colors.GREEN_800, size=12),

      ],

      spacing=8,

     ),

    )

   )

   alerts_count.value = “No detections”

  else:

   shown = 0

   for p in preds:

    if shown >= MAX_SHOW:

     break

    alert_list_col.controls.append(

     make_alert_card(p[“class”], p[“x”], p[“y”], p[“confidence”], p[“detection_id”])

    )

    shown += 1

   plural = “s” if len(preds) != 1 else “”

   alerts_count.value = f”{len(preds)} detection{plural}”

 def predictions_from_detections_obj(det_obj: Any) -> List[Dict[str, Any]]:

  “””

  Extracts predictions from a Roboflow `Detections` object with fields:

  – xyxy: Nx4 -> [x1, y1, x2, y2]

  – confidence: (N,)

  – data: dict with arrays (e.g. ‘class_name’, ‘detection_id’)

  Returns list of dicts with keys: class, x, y, confidence, detection_id

  “””

  preds: List[Dict[str, Any]] = []

  if det_obj is None:

   return preds

  xyxy = getattr(det_obj, “xyxy”, None)

  conf = getattr(det_obj, “confidence”, None)

  data = getattr(det_obj, “data”, {}) or {}

  if xyxy is None or conf is None:

   return preds

  try:

   xyxy = np.asarray(xyxy)

   conf = np.asarray(conf)

  except Exception:

   return preds

  n = min(len(xyxy), len(conf))

  if n == 0:

   return preds

  class_names = (data.get(“class_name”) if isinstance(data, dict) else None)

  det_ids = (data.get(“detection_id”) if isinstance(data, dict) else None)

  try:

   class_names = np.asarray(class_names) if class_names is not None else None

  except Exception:

   class_names = None

  try:

   det_ids = np.asarray(det_ids) if det_ids is not None else None

  except Exception:

   det_ids = None

  for i in range(n):

   try:

    x1, y1, x2, y2 = [float(v) for v in xyxy[i]]

    cx = (x1 + x2) / 2.0

    cy = (y1 + y2) / 2.0

    c = float(conf[i])

    cls_name = None

    if class_names is not None and i < len(class_names):

     cls_name = str(class_names[i])

    if not cls_name:

     cls_name = “defect”

    did = None

    if det_ids is not None and i < len(det_ids):

     did = str(det_ids[i])

    if not did:

     did = f”{cls_name}@{round(cx)},{round(cy)}”

    preds.append({“class”: cls_name, “x”: cx, “y”: cy, “confidence”: c, “detection_id”: did})

   except Exception:

    continue

  return preds

 def signature_for_preds(preds: List[Dict[str, Any]]) -> Tuple:

  # Round numeric fields to reduce jitter; sort to make order-independent.

  sig_items = []

  for p in preds:

   sig_items.append((

    p.get(“detection_id”),

    p.get(“class”),

    round(float(p.get(“x”, 0.0)), 1),

    round(float(p.get(“y”, 0.0)), 1),

    round(float(p.get(“confidence”, 0.0)), 3),

   ))

  sig_items.sort()

  return tuple(sig_items)

 def on_prediction(result, video_frame):

  try:

   # Visualization

   lv = None

   if isinstance(result, dict):

    lv = result.get(“label_visualization”)

   elif hasattr(result, “label_visualization”):

    lv = getattr(result, “label_visualization”)

   if lv is not None and hasattr(lv, “numpy_image”):

    vis_arr = lv.numpy_image

    if not state[“started”]:

     state[“started”] = True

     status.value = “Running”

    if assume_bgr_chk.value:

     vis_bgr = vis_arr

    else:

     try:

      vis_bgr = cv2.cvtColor(vis_arr, cv2.COLOR_RGB2BGR)

     except Exception:

      vis_bgr = vis_arr

    with last_lock:

     state[“last_vis_bgr”] = vis_bgr.copy()

    b64 = np_to_b64_jpg(vis_arr, assume_bgr=assume_bgr_chk.value, quality=85)

    if b64:

     img_vis.src_base64 = b64

     h, w = vis_arr.shape[:2]

     info.value = f”{w}x{h}”

     snapshot_btn.disabled = False

   # Extract predictions (Detections object)

   det_obj = None

   if isinstance(result, dict):

    det_obj = result.get(“model_predictions”)

   elif hasattr(result, “model_predictions”):

    det_obj = getattr(result, “model_predictions”)

   preds = predictions_from_detections_obj(det_obj)

   # Update alerts ONLY if the set changed (signature diff)

   sig = signature_for_preds(preds)

   changed = sig != state[“last_alert_signature”]

   if changed:

    render_alert_snapshot(preds)

    state[“last_alert_signature”] = sig

   debug.value = f”Debug: parsed {len(preds)} preds; changed={changed}”

   page.update()

  except Exception as e:

   status.value = f”Frame error: {e}”

   page.update()

 def run_pipeline():

  src = source.value.strip()

  try:

   video_reference = int(src)

  except ValueError:

   video_reference = src

  try:

   status.value = “Starting pipeline…”

   state[“started”] = False

   page.update()

   pipe = InferencePipeline.init_with_workflow(

    api_key=api_key.value.strip(),

    workspace_name=workspace.value.strip(),

    workflow_id=workflow_id.value.strip(),

    video_reference=video_reference,

    max_fps=30,

    on_prediction=on_prediction,

   )

   state[“pipeline”] = pipe

   pipe.start()

   if hasattr(pipe, “join”):

    pipe.join()

   else:

    while state[“running”]:

     time.sleep(0.1)

  except Exception as ex:

   status.value = f”Start failed: {ex}”

   page.update()

  finally:

   stop_btn.disabled = True

   start_btn.disabled = False

   snapshot_btn.disabled = True

   status.value = “Stopped”

   page.update()

   state[“running”] = False

   state[“pipeline”] = None

   with last_lock:

    state[“last_vis_bgr”] = None

 def start_clicked(e):

  if state[“running”]:

   return

  state[“running”] = True

  start_btn.disabled = True

  stop_btn.disabled = False

  snapshot_btn.disabled = True

  save_info.value = “”

  status.value = “Starting…”

  state[“started”] = False

  state[“last_alert_signature”] = None

  # Fresh empty panel

  alert_list_col.controls.clear()

  alerts_count.value = “Cleared. Waiting for detections…”

  debug.value = “”

  page.update()

  t = threading.Thread(target=run_pipeline, daemon=True)

  state[“thread”] = t

  t.start()

 def stop_pipeline():

  try:

   if state[“pipeline”] is not None:

    if hasattr(state[“pipeline”], “stop”):

     state[“pipeline”].stop()

    elif hasattr(state[“pipeline”], “terminate”):

     state[“pipeline”].terminate()

  except Exception:

   pass

  finally:

   state[“pipeline”] = None

 def stop_clicked(e):

  status.value = “Stopping…”

  page.update()

  state[“running”] = False

  stop_pipeline()

  stop_btn.disabled = True

  start_btn.disabled = False

  snapshot_btn.disabled = True

  page.update()

 def snapshot_clicked(e):

  with last_lock:

   frame = state[“last_vis_bgr”].copy() if state[“last_vis_bgr”] is not None else None

  if frame is None:

   save_info.value = “No frame available yet.”

   page.update()

   return

  os.makedirs(“snapshots”, exist_ok=True)

  fname = time.strftime(“snapshots/vis_%Y%m%d_%H%M%S.jpg”)

  ok = cv2.imwrite(fname, frame)

  save_info.value = f”Saved: {fname}” if ok else “Failed to save snapshot.”

  page.update()

 def clear_alerts(e=None):

  alert_list_col.controls.clear()

  alerts_count.value = “Cleared. Waiting for detections…”

  state[“last_alert_signature”] = None

  page.update()

 clear_alerts_btn.on_click = clear_alerts

 def on_disconnect(e):

  state[“running”] = False

  stop_pipeline()

 start_btn.on_click = start_clicked

 stop_btn.on_click = stop_clicked

 snapshot_btn.on_click = snapshot_clicked

 page.on_disconnect = on_disconnect

if __name__ == “__main__”:

 ft.app(target=main)

Ứng dụng được thiết kế với hai panel chính:

  • Bên trái: hiển thị video/camera trực tiếp của PCB, vẽ bounding box quanh lỗi phát hiện được.
  • Bên phải: panel cảnh báo hiển thị thông báo dạng “snapshot” mỗi khi phát hiện lỗi (ví dụ missing hole). Danh sách cảnh báo được làm mới khi tập phát hiện thay đổi để người vận hành nắm nhanh trạng thái hiện tại. 

Ứng dụng cung cấp các điều khiển để nhập API key, workspace, workflow ID, chọn nguồn video (webcam, file video, RTSP), cùng các nút start/stop/snapshot để kiểm soát phiên kiểm tra. Snapshot có thể lưu lại để báo cáo hoặc truy vết. 

Ở tầng xử lý, ứng dụng chạy pipeline inference của Roboflow trên một luồng riêng, xử lý liên tục các frame từ nguồn video. Các lỗi phát hiện được được chuyển thành dự đoán có cấu trúc (class, tọa độ, confidence), hiển thị đồng thời trên ảnh trực quan và panel cảnh báo. Khi không có lỗi, hệ thống tự làm sạch cảnh báo; khi phát hiện mới xuất hiện, bộ đếm được cập nhật. 

Lệnh chạy ví dụ: 

  • flet run app.py hoặc python app.py

Bạn sẽ thấy đầu ra tương tự như sau:

Kết quả đầu ra của ứng dụng flet
Kết quả đầu ra của ứng dụng flet. (Nguồn: Internet)

Sau đây là đoạn video minh họa:

  • Chạy web app: flet run –web app.py

Việc này sẽ khởi động máy chủ web và chạy ứng dụng trong trình duyệt web.

Kết quả đầu ra của ứng dụng flet
Kết quả đầu ra của ứng dụng flet. (Nguồn: Internet)

Bước triển khai này biến quy trình công việc Roboflow đã được đào tạo thành một công cụ kiểm tra thực tiễn, thân thiện với người vận hành, có khả năng trực quan hóa theo thời gian thực, cảnh báo lỗi, và chụp ảnh nhanh, giúp việc kiểm tra PCB có thể sử dụng được trong môi trường sản xuất thực tế.

Kết luận về hệ thống kiểm tra thị giác

Hệ thống kiểm tra thị giác ngày càng trở thành hạ tầng thiết yếu trong sản xuất hiện đại, giúp sản phẩm đạt tiêu chuẩn chất lượng, an toàn và hiệu năng. Từ phát hiện lỗi, đo lường, xác minh nhãn, đếm và phân loại cho đến kiểm tra tuân thủ, thị giác máy tính đang mở rộng phạm vi ứng dụng trên nhiều ngành như điện tử, ô tô, dược phẩm và chế biến thực phẩm. Cùng với tiến bộ của học sâu, phần cứng thu nhận ảnh và nền tảng triển khai, các hệ thống này ngày càng chính xác, dễ mở rộng và linh hoạt hơn. 

Trong tài liệu, chúng ta đã đi qua nền tảng của VIS: thành phần, phân loại và ứng dụng; đồng thời xây dựng một ví dụ đầu-cuối phát hiện missing holes trên PCB và triển khai thành công cụ thân thiện cho vận hành. Ví dụ này cho thấy việc thiết kế và triển khai giải pháp kiểm tra tùy biến đã trở nên dễ tiếp cận hơn, không nhất thiết phải “phát minh lại bánh xe” từ đầu

Nguồn tham khảo: https://blog.roboflow.com/vision-inspection-systems/

TOT là đơn vị tiên phong trong hành trình chuyển đổi số. Chúng tôi mang đến giải pháp thiết kế website, mobile appviết phần mềm theo yêu cầu với dịch vụ linh hoạt, tối ưu theo đúng nhu cầu của doanh nghiệp.

Lấy cảm hứng từ triết lý “Công nghệ vì con người”, TOT giúp doanh nghiệp vận hành hiệu quả hơn, nâng tầm trải nghiệm khách hàng và tạo dấu ấn bền vững cho thương hiệu.

Thông tin liên hệ TopOnTech (TOT):

🌐 Website TOT

📞 Hotline/WhatsApp/Zalo: 0906 712 137

✉️ Email: long.bui@toponseek.com

🏢 Địa chỉ: 31 Hoàng Diệu, Phường 12, Quận 4, Thành phố Hồ Chí Minh, Việt Nam

Liên hệ

Bạn đã sẵn sàng chưa?

Cùng TOT bắt đầu hành trình xây dựng dự án ngay hôm nay!

Gửi tin nhắn cho chúng tôi. Chúng tôi sẽ đề xuất giải pháp để nâng tầm doanh nghiệp của bạn.

Sự khác biệt:

Đặt lịch tư vấn miễn phí