5 nhóm bài toán Machine Vision và cách giải: từ có/không đến dẫn hướng
Nhận diện nhóm bài toán, kỹ thuật và con số cần hỏi cho từng nhóm, ví dụ OpenCV chạy được và bảng chấm độ khó 0–16 cho một yêu cầu.
Học xong bài này, bạn sẽ
- Nhận diện bài toán: có/không, đo, kiểm lỗi, nhận dạng, dẫn hướng
- Biết kỹ thuật điển hình cho từng nhóm
- Ước lượng độ khó của một yêu cầu
Nên học trước: Hệ thống Machine Vision gồm những gì?
Nội dung bài viết
- 1. Năm nhóm bài toán
- 2. Bảng tra: nhóm → kỹ thuật → con số → yếu tố gây khó
- 3. Ví dụ nhóm 1 (có/không): kiểm tra đủ linh kiện trên bo mạch
- 4. Ví dụ nhóm 2 (đo lường): vì sao cần subpixel
- 5. Ví dụ nhóm 3 (kiểm lỗi): so với ảnh mẫu chuẩn
- 6. Nhóm 4 và 5 trong một đoạn
- 7. Ước lượng độ khó của một yêu cầu
- 8. Sai lầm thường gặp
- 9. Bài tập
- Tóm tắt
Khách hàng hiếm khi nói "tôi cần một thuật toán đo cạnh subpixel". Họ nói "chai bị thiếu nắp", "trục bị lệch kích thước", "vỏ bị xước", "in sai hạn sử dụng", "robot gắp trượt". Việc đầu tiên của kỹ sư Machine Vision là dịch câu nói đó thành một nhóm bài toán, vì mỗi nhóm có bộ kỹ thuật, bộ thông số và nguồn rủi ro riêng. Bài trước, "Hệ thống Machine Vision gồm những gì?", cho bạn bức tranh phần cứng; bài này cho bạn bức tranh bài toán. Cuối bài bạn có một bảng chấm điểm độ khó để trả lời câu hỏi khách hàng nào cũng hỏi: "làm được không, khó không?".
1. Năm nhóm bài toán
Gần như mọi ứng dụng Machine Vision trong nhà máy rơi vào một (hoặc kết hợp vài) nhóm sau:
- Có/không (presence/absence): đặc điểm có mặt hay vắng mặt. Thiếu nắp, thiếu ốc, thiếu linh kiện, thiếu nhãn, thiếu gioăng.
- Đo lường (gauging, measurement): kích thước, khoảng cách, góc, đường kính, độ đồng tâm có nằm trong dung sai không.
- Kiểm tra lỗi (defect inspection): bề mặt có vết xước, vết bẩn, sứt mẻ, bọt khí, in nhòe không. Lỗi không biết trước vị trí và hình dạng.
- Nhận dạng (identification): đọc mã vạch, mã 2D (QR, DataMatrix), đọc ký tự (OCR), xác nhận ký tự in đúng (OCV), phân biệt mã sản phẩm theo màu hay hình dạng.
- Dẫn hướng (guidance, alignment): tìm vị trí và góc của vật để robot gắp, để máy căn chỉnh, để bước kiểm tra sau đặt ROI đúng chỗ.
Một trạm thật thường kết hợp: trạm kiểm tra nhãn chai vừa dẫn hướng (tìm nhãn ở đâu), vừa có/không (có nhãn không), vừa đo (nhãn lệch bao nhiêu mm), vừa nhận dạng (đọc mã lô). Tách ra từng nhóm giúp bạn ước lượng đúng phần nào dễ, phần nào khó.
2. Bảng tra: nhóm → kỹ thuật → con số → yếu tố gây khó
| Nhóm | Kỹ thuật điển hình | Con số phải hỏi / tính | Yếu tố làm bài toán khó |
|---|---|---|---|
| Có/không | Độ sáng trung bình trong ROI, đếm pixel sau phân ngưỡng, blob (diện tích, số lượng), điểm khớp mẫu (template matching) | Số vị trí cần kiểm; kích thước đặc điểm nhỏ nhất; độ lệch vị trí của vật; năng suất (sản phẩm/phút) | Đặc điểm cùng màu với nền; vật trôi vị trí nên ROI cố định không còn đúng; nhiều mã sản phẩm |
| Đo lường | Profile và tìm cạnh subpixel, công cụ thước kẹp (caliper), fitting đường thẳng/đường tròn, hiệu chuẩn pixel → mm, ống kính telecentric | Kích thước danh định và dung sai (ví dụ 12 ± 0,02 mm); độ lặp lại yêu cầu; mm/pixel; số phép đo mỗi vật | Dung sai nhỏ so với kích thước vật; vật 3D, cạnh vát, bavia; phản xạ ở mép; nhiệt độ; vật không nằm cùng độ cao |
| Kiểm tra lỗi | So với ảnh mẫu chuẩn (golden template), lọc + phân ngưỡng + blob, phân tích texture, deep learning (phân loại, phân đoạn, phát hiện bất thường) | Kích thước lỗi nhỏ nhất (mm) → số pixel trên lỗi; danh sách loại lỗi kèm ảnh; tỉ lệ lọt lỗi và loại nhầm chấp nhận được | Lỗi đa dạng, hiếm; định nghĩa lỗi bằng lời ("xước nhìn thấy được"); bề mặt bóng, cong, có hoa văn; lỗi nhỏ gần ngưỡng |
| Nhận dạng | Thư viện giải mã 1D/2D, OCR/OCV, phân loại màu, khớp mẫu hình dạng | Kích thước module mã / chiều cao ký tự → số pixel; chất lượng in; danh sách ký tự (font); dữ liệu đúng để so lấy từ đâu | In mờ, nhòe, khắc laser trên kim loại; bề mặt cong; font lạ; ký tự dễ nhầm (0/O, 1/I, 8/B) |
| Dẫn hướng | Khớp mẫu hình dạng (shape matching), tâm và góc blob, fitting, hiệu chuẩn camera và hand-eye, vision 3D | Độ chính xác vị trí (mm) và góc (°); vùng làm việc; thời gian; số vật mỗi lần chụp | Vật chồng lên nhau; vật đối xứng (khó xác định góc); sai số hiệu chuẩn; vật có chiều cao thay đổi |
- Có/không, kiểm lỗi: đặc điểm hoặc lỗi nhỏ nhất nên phủ ít nhất khoảng 3×3 pixel; muốn ổn định và đo được kích thước lỗi thì cần nhiều hơn (5–10 pixel).
- Đo lường: sai số của hệ đo nên nhỏ hơn khoảng 1/10 dải dung sai (quy tắc 10:1). Đo cạnh subpixel trong điều kiện tốt cho độ lặp lại cỡ 0,1–0,25 pixel, nên dải dung sai cần trải trên nhiều pixel.
- Mã 2D (DataMatrix, QR): mỗi module thường cần vài pixel (khoảng 3–5 pixel trở lên); mã vạch 1D: vạch hẹp nhất khoảng 1,5–2 pixel trở lên. OCR: chiều cao ký tự thường cần vài chục pixel. Con số chính xác tùy thư viện, hãy đọc khuyến nghị của thư viện bạn dùng.
mm/pixel = FOV (mm) / số pixel theo chiều đó, rồi số pixel trên đặc điểm = kích thước (mm) / (mm/pixel).3. Ví dụ nhóm 1 (có/không): kiểm tra đủ linh kiện trên bo mạch
Bo mạch nằm trong đồ gá (jig) nên vị trí 8 linh kiện đã biết trước. Thuật toán đơn giản nhất: lấy ROI ở lõi mỗi vị trí, tính độ sáng trung bình, so ngưỡng. Thân linh kiện sáng, nền bo mạch tối.
import cv2
import numpy as np
# Bo mạch giả lập: 2 hàng × 4 vị trí linh kiện, vị trí 6 bị thiếu
rng = np.random.default_rng(3)
anh = np.full((240, 400), 60, np.uint8) # nền PCB tối
VI_TRI = [(50 + 90 * c, 50 + 100 * r) for r in range(2) for c in range(4)] # góc trên-trái từng ô
for i, (x, y) in enumerate(VI_TRI, 1):
cv2.rectangle(anh, (x, y), (x + 40, y + 40), 110, 2) # khung pad (luôn có)
if i != 6:
cv2.rectangle(anh, (x + 6, y + 6), (x + 34, y + 34), 200, -1) # thân linh kiện sáng
anh = np.clip(anh + rng.normal(0, 6, anh.shape), 0, 255).astype(np.uint8)
cv2.imwrite("bo_mach.png", anh)
NGUONG = 150 # độ sáng trung bình tối thiểu khi có linh kiện
for i, (x, y) in enumerate(VI_TRI, 1):
roi = anh[y + 10:y + 30, x + 10:x + 30] # chỉ lấy lõi, tránh viền pad
tb = roi.mean()
print(f"vị trí {i}: độ sáng {tb:6.1f} → {'CÓ' if tb > NGUONG else 'THIẾU'}")
vị trí 1: độ sáng 199.9 → CÓ
vị trí 2: độ sáng 199.4 → CÓ
vị trí 3: độ sáng 199.0 → CÓ
vị trí 4: độ sáng 199.3 → CÓ
vị trí 5: độ sáng 199.4 → CÓ
vị trí 6: độ sáng 59.4 → THIẾU
vị trí 7: độ sáng 198.9 → CÓ
vị trí 8: độ sáng 199.5 → CÓ
Những chi tiết nhỏ nhưng quan trọng:
- ROI lấy ở lõi (cách viền 10 pixel), không phủ khung pad. Nếu ROI chạm viền pad, độ sáng của ô "thiếu" sẽ bị kéo lên và khoảng hở với ô "có" hẹp lại.
- Khoảng hở ở đây khoảng 140 mức xám (khoảng 199 so với 59), ngưỡng 150 nằm thoải mái ở giữa. Đây là điều chiếu sáng tốt mang lại (bài trước).
- Phương pháp chỉ đúng khi vật không trôi vị trí. Nếu bo mạch có thể lệch vài mm, bạn cần một bước dẫn hướng trước (tìm dấu định vị, dịch các ROI theo), là nhóm 5.
4. Ví dụ nhóm 2 (đo lường): vì sao cần subpixel
Đo bề rộng một chi tiết thật rộng 37,35 mm với độ phân giải 0,1 mm/pixel (tức 373,5 pixel). Trên dây chuyền, chi tiết dừng mỗi lần lệch một chút, nên mép rơi vào vị trí lẻ của pixel. Ta so hai cách: đếm số pixel sáng, và tìm vị trí mép subpixel bằng nội suy tuyến tính tại mức 50% giữa nền và vật.
import cv2
import numpy as np
TL = 0.1 # mm/pixel (đã hiệu chuẩn)
RONG_THAT = 37.35 # mm = 373,5 pixel
rng = np.random.default_rng(0)
def chup(lech_px):
"""Ảnh 1 hàng của chi tiết sáng, mép trái tại 100 + lech_px (tạo ở độ phân giải ×10 rồi thu nhỏ)."""
lon = np.full((10, 6000), 30, np.uint8)
x1 = int(round((100 + lech_px) * 10))
lon[:, x1:x1 + int(RONG_THAT / TL * 10)] = 220
anh = cv2.resize(lon, (600, 1), interpolation=cv2.INTER_AREA)
anh = cv2.GaussianBlur(anh, (5, 1), 1.0)
return np.clip(anh[0] + rng.normal(0, 3, 600), 0, 255)
def vi_tri_mep(p, muc, tu_trai=True):
"""Vị trí subpixel đầu tiên profile p cắt mức 'muc', nội suy tuyến tính giữa 2 pixel."""
idx = range(len(p) - 1) if tu_trai else range(len(p) - 2, -1, -1)
for i in idx:
a, b = p[i], p[i + 1]
if (a - muc) * (b - muc) <= 0 and a != b:
return i + (muc - a) / (b - a)
return None
print(" lệch(px) đếm pixel(mm) subpixel(mm)")
kq_pixel, kq_sub = [], []
for k in range(10): # chi tiết dừng lệch 0,0 .. 0,9 pixel
p = chup(k / 10)
muc = (p.min() + p.max()) / 2 # mức 50% giữa nền và vật
d_pixel = int((p > muc).sum()) * TL
d_sub = (vi_tri_mep(p, muc, False) - vi_tri_mep(p, muc, True)) * TL
kq_pixel.append(d_pixel)
kq_sub.append(d_sub)
print(f" {k / 10:.1f} {d_pixel:.3f} {d_sub:.3f}")
for ten, d in (("đếm pixel", kq_pixel), ("subpixel", kq_sub)):
print(f"{ten:9s}: sai lệch trung bình {np.mean(d) - RONG_THAT:+.3f} mm, dải dao động {np.ptp(d):.3f} mm")
lệch(px) đếm pixel(mm) subpixel(mm)
0.0 37.400 37.359
0.1 37.400 37.353
0.2 37.400 37.353
0.3 37.400 37.357
0.4 37.400 37.348
0.5 37.300 37.350
0.6 37.300 37.337
0.7 37.300 37.340
0.8 37.300 37.343
0.9 37.300 37.348
đếm pixel: sai lệch trung bình +0.000 mm, dải dao động 0.100 mm
subpixel : sai lệch trung bình -0.001 mm, dải dao động 0.022 mm
- Đếm pixel nhảy giữa 37,4 và 37,3 mm tùy chi tiết dừng ở đâu: sai số lượng tử ±1 pixel. Trung bình thì đúng, nhưng từng lần đo dao động 0,1 mm. Với dung sai ± 0,05 mm, cách này không dùng được.
- Subpixel dao động khoảng 0,02 mm, tức khoảng 0,2 pixel, phù hợp con số kinh nghiệm 0,1–0,25 pixel ở trên.
- Đây mới là ảnh mô phỏng sạch. Ngoài thực tế còn có mép vát, bavia, phản xạ, độ cao vật thay đổi (ống kính thường làm vật gần trông to hơn). Kỹ thuật đo cạnh, fitting và hiệu chuẩn được dạy kỹ ở chặng 7 và chặng 8.
5. Ví dụ nhóm 3 (kiểm lỗi): so với ảnh mẫu chuẩn
Với nhãn in, cách cổ điển là lưu một ảnh mẫu chuẩn (golden template) rồi trừ ảnh: chỗ nào khác nhiều là lỗi. Cách này rất nhạy, và chính vì quá nhạy nên có một cái bẫy: chỉ cần sản phẩm lệch 1 pixel, mọi mép chữ đều thành "lỗi".
import cv2
import numpy as np
rng = np.random.default_rng(5)
def nhan(dx=0, loi=False):
"""Nhãn in: khung, logo tròn, 3 dòng chữ giả. dx: lệch ngang (pixel)."""
a = np.full((200, 300), 200, np.uint8)
cv2.rectangle(a, (20 + dx, 20), (280 + dx, 180), 60, 3)
cv2.circle(a, (70 + dx, 100), 30, 60, -1)
for y in (70, 100, 130):
cv2.line(a, (120 + dx, y), (250 + dx, y), 60, 6)
if loi:
cv2.line(a, (150 + dx, 150), (210 + dx, 165), 120, 2) # vết xước mờ
cv2.circle(a, (240 + dx, 40), 3, 90, -1) # chấm bẩn ~ 7 px
return np.clip(a + rng.normal(0, 4, a.shape), 0, 255).astype(np.uint8)
def tim_loi(anh, mau, nguong=40, dien_tich_min=5):
hieu = cv2.absdiff(anh, mau)
_, m = cv2.threshold(hieu, nguong, 255, cv2.THRESH_BINARY)
n, _, st, _ = cv2.connectedComponentsWithStats(m)
return [int(s) for s in st[1:, cv2.CC_STAT_AREA] if s >= dien_tich_min]
def tim_loi_co_dung_sai(anh, mau, nguong=40, dien_tich_min=5, r=1):
"""So với 'ảnh min' và 'ảnh max' của mẫu (co/giãn r pixel): mép lệch nhẹ không bị coi là lỗi."""
k = np.ones((2 * r + 1, 2 * r + 1), np.uint8)
mau_min, mau_max = cv2.erode(mau, k), cv2.dilate(mau, k)
vuot = np.maximum(cv2.subtract(mau_min, anh), cv2.subtract(anh, mau_max))
_, m = cv2.threshold(vuot, nguong, 255, cv2.THRESH_BINARY)
n, _, st, _ = cv2.connectedComponentsWithStats(m)
return [int(s) for s in st[1:, cv2.CC_STAT_AREA] if s >= dien_tich_min]
mau = nhan() # ảnh mẫu chuẩn (golden)
for ten, anh in (("OK, đúng vị trí", nhan()), ("lỗi, đúng vị trí", nhan(loi=True)),
("OK, lệch 1 px", nhan(dx=1)), ("lỗi, lệch 1 px", nhan(dx=1, loi=True))):
a, b = tim_loi(anh, mau), tim_loi_co_dung_sai(anh, mau)
print(f"{ten:17s} | trừ ảnh: {len(a):2d} vùng | có dung sai mép: {len(b)} vùng {b}")
OK, đúng vị trí | trừ ảnh: 0 vùng | có dung sai mép: 0 vùng []
lỗi, đúng vị trí | trừ ảnh: 2 vùng | có dung sai mép: 2 vùng [29, 170]
OK, lệch 1 px | trừ ảnh: 12 vùng | có dung sai mép: 0 vùng []
lỗi, lệch 1 px | trừ ảnh: 14 vùng | có dung sai mép: 2 vùng [29, 170]
- Trừ ảnh thuần túy bắt đúng 2 lỗi (chấm bẩn 29 pixel, vết xước 170 pixel) khi nhãn đúng vị trí, nhưng báo 12 vùng lỗi giả trên nhãn tốt chỉ lệch 1 pixel. Trên dây chuyền, đó là loại nhầm hàng loạt.
- Cách sửa: tạo "ảnh min" và "ảnh max" bằng erode/dilate ảnh mẫu (bài morphology ở chặng 3). Một pixel chỉ là lỗi khi nó tối hơn ảnh min hoặc sáng hơn ảnh max quá ngưỡng. Mép lệch trong phạm vi
rpixel được bỏ qua, lỗi thật vẫn bị bắt. - Cái giá: lỗi nằm sát mép chữ, trong vùng dung sai, sẽ khó bắt hơn. Mọi kỹ thuật kiểm lỗi đều là đánh đổi giữa lọt lỗi và loại nhầm, chủ đề chính của chặng 5.
- Trước khi trừ ảnh, sản phẩm thường được căn chỉnh về đúng vị trí mẫu bằng khớp mẫu (nhóm 5). Lệch lớn hơn vài pixel thì dung sai mép không cứu được.
6. Nhóm 4 và 5 trong một đoạn
Nhận dạng thường dùng thư viện có sẵn: bộ giải mã mã vạch/2D (OpenCV có bộ đọc QR; các thư viện thương mại đọc DataMatrix khắc laser tốt hơn), OCR cho chữ. Phần việc của kỹ sư là bảo đảm đủ pixel trên module/ký tự, chiếu sáng cho mã rõ, và quyết định so với cái gì: mã đọc được phải khớp dữ liệu nào, lấy từ MES hay từ công thức sản phẩm. Lỗi hay gặp: đọc đúng nhưng so sai dữ liệu, hoặc chấp nhận kết quả đọc có độ tin cậy thấp.
Dẫn hướng trả về tọa độ (x, y, góc) thay vì OK/NG. Bài blob analysis ở chặng 3 đã cho bạn tâm và góc của vật. Phần khó thật sự là đổi tọa độ pixel sang tọa độ robot (hiệu chuẩn, chặng 8) và xử lý vật đối xứng hoặc chồng lấn. Sai số dẫn hướng cộng dồn từ: sai số tìm vật trên ảnh + sai số hiệu chuẩn + sai số robot. Khách hàng yêu cầu "robot gắp chính xác ± 0,1 mm" thì phần của vision phải nhỏ hơn nhiều.
7. Ước lượng độ khó của một yêu cầu
Khi khách hàng hỏi "làm được không?", đừng trả lời theo cảm giác. Chấm 8 yếu tố, mỗi yếu tố 0–2 điểm:
| Yếu tố | 0 điểm | 1 điểm | 2 điểm |
|---|---|---|---|
| Độ phân giải (pixel trên đặc điểm nhỏ nhất; với đo lường: pixel trên dải dung sai) | ≥ 10 (đo: ≥ 20) | 3–10 (đo: 5–20) | < 3 (đo: < 5) |
| Tương phản sau khi thử đèn | Rõ, khoảng hở lớn | Thấy được nhưng hẹp | Chưa thử hoặc gần như không thấy |
| Biến động sản phẩm (màu, mã, lô vật liệu) | Một loại, ổn định | Vài loại | Nhiều loại, thay đổi thường xuyên |
| Vị trí, hướng vật | Cố định trong đồ gá | Lệch nhỏ, cùng hướng | Ngẫu nhiên, xoay tự do, chồng nhau |
| Bề mặt | Mờ, phẳng | Bóng hoặc cong | Bóng và cong, trong suốt, hoa văn |
| Chu kỳ (thời gian cho mỗi sản phẩm) | > 500 ms | 100–500 ms | < 100 ms |
| Định nghĩa NG | Bằng con số đo được | Có ảnh mẫu lỗi, mô tả bằng lời | "Nhìn thấy là lỗi", không có mẫu |
| Yêu cầu lọt lỗi | Cho phép lọt ít, có kiểm tra sau | Thấp, có thống kê | "Không được lọt con nào" |
Tổng 0–4: dễ, làm ngay. 5–9: trung bình, cần thử với mẫu thật trước khi chốt phần cứng. Từ 10 trở lên: khó, phải làm thử nghiệm khả thi (feasibility study, proof of concept) trước khi báo giá. Bảng chấm này không phải tiêu chuẩn ngành, mà là cách hệ thống hóa kinh nghiệm để bạn không quên yếu tố nào. Áp dụng cho ba yêu cầu:
def muc_do_phan_giai(fov_mm, so_pixel, kich_thuoc_mm, la_do_luong=False):
"""Điểm 0–2 cho độ phân giải. Đo lường: tính số pixel trên DẢI dung sai; còn lại: trên đặc điểm nhỏ nhất."""
mm_px = fov_mm / so_pixel
px = kich_thuoc_mm / mm_px
if la_do_luong:
diem = 0 if px >= 20 else 1 if px >= 5 else 2
else:
diem = 0 if px >= 10 else 1 if px >= 3 else 2
return diem, px, mm_px
def danh_gia(ten, fov_mm, so_pixel, kich_thuoc_mm, la_do_luong, **cac_yeu_to):
d_pg, px, mm_px = muc_do_phan_giai(fov_mm, so_pixel, kich_thuoc_mm, la_do_luong)
tong = d_pg + sum(cac_yeu_to.values())
muc = "DỄ" if tong <= 4 else "TRUNG BÌNH" if tong <= 9 else "KHÓ: làm thử trước khi báo giá"
print(f"{ten}\n {mm_px:.4f} mm/px, {px:.1f} px trên đặc điểm → điểm phân giải {d_pg}")
khac = ", ".join(f"{k}={v}" for k, v in cac_yeu_to.items())
print(f" {khac}\n TỔNG {tong}/16 → {muc}")
# Thang 0–2 cho mỗi yếu tố: tuong_phan, bien_dong, vi_tri, be_mat, chu_ky, dinh_nghia_ng, yeu_cau_lot
danh_gia("A. Có/không nắp chai (đèn nền)", 120, 1280, 10, False,
tuong_phan=0, bien_dong=0, vi_tri=1, be_mat=0, chu_ky=0, dinh_nghia_ng=0, yeu_cau_lot=1)
danh_gia("B. Đo đường kính trục 12 ± 0,02 mm", 20, 2448, 0.04, True,
tuong_phan=0, bien_dong=0, vi_tri=1, be_mat=1, chu_ky=1, dinh_nghia_ng=0, yeu_cau_lot=2)
danh_gia("C. Vết xước ≥ 0,1 mm trên vỏ nhôm bóng 150×75 mm", 160, 4096, 0.1, False,
tuong_phan=2, bien_dong=1, vi_tri=1, be_mat=2, chu_ky=1, dinh_nghia_ng=2, yeu_cau_lot=2)
A. Có/không nắp chai (đèn nền)
0.0938 mm/px, 106.7 px trên đặc điểm → điểm phân giải 0
tuong_phan=0, bien_dong=0, vi_tri=1, be_mat=0, chu_ky=0, dinh_nghia_ng=0, yeu_cau_lot=1
TỔNG 2/16 → DỄ
B. Đo đường kính trục 12 ± 0,02 mm
0.0082 mm/px, 4.9 px trên đặc điểm → điểm phân giải 2
tuong_phan=0, bien_dong=0, vi_tri=1, be_mat=1, chu_ky=1, dinh_nghia_ng=0, yeu_cau_lot=2
TỔNG 7/16 → TRUNG BÌNH
C. Vết xước ≥ 0,1 mm trên vỏ nhôm bóng 150×75 mm
0.0391 mm/px, 2.6 px trên đặc điểm → điểm phân giải 2
tuong_phan=2, bien_dong=1, vi_tri=1, be_mat=2, chu_ky=1, dinh_nghia_ng=2, yeu_cau_lot=2
TỔNG 13/16 → KHÓ: làm thử trước khi báo giá
- A dễ: đặc điểm phủ hơn 100 pixel, đèn nền cho tương phản tuyệt đối.
- B trung bình nhưng có một điểm đỏ: dải dung sai 0,04 mm chỉ trải trên 4,9 pixel. Theo quy tắc 10:1, sai số đo phải dưới 0,004 mm ≈ 0,5 pixel. Làm được với đo subpixel, đèn nền, ống kính telecentric và hiệu chuẩn cẩn thận; hoặc thu nhỏ FOV/tăng độ phân giải để dễ thở hơn. Phải nói rõ điều này với khách hàng từ đầu.
- C khó: vết xước 0,1 mm chỉ phủ 2,6 pixel với một camera 4096 pixel nhìn toàn bộ vỏ, bề mặt nhôm bóng, định nghĩa lỗi mơ hồ. Hướng đi thực tế: chụp nhiều ảnh (nhiều camera, hoặc camera line scan quét), thử nhiều kiểu đèn, thu thập mẫu lỗi, và thống nhất với khách hàng định nghĩa lỗi bằng con số trước khi báo giá.
8. Sai lầm thường gặp
- Nhận lời "kiểm tra mọi lỗi". Không có trạm nào kiểm "mọi lỗi". Yêu cầu khách hàng liệt kê từng loại lỗi, kích thước nhỏ nhất, kèm mẫu thật.
- Tính độ phân giải theo chiều rộng sản phẩm, quên chiều cao FOV. FOV phải chứa cả sản phẩm lẫn độ lệch vị trí của nó, theo cả hai chiều, cộng thêm biên.
- Coi đo lường như có/không. "Có lỗ không" thì dễ; "đường kính lỗ 5 ± 0,01 mm" là bài toán khác hẳn về quang học và hiệu chuẩn.
- Dùng deep learning cho bài có/không đơn giản. Nếu ngưỡng độ sáng trong ROI đã tách sạch, thêm mô hình chỉ thêm rủi ro, thời gian huấn luyện và khó giải thích.
9. Bài tập
Bài 1. Xếp mỗi yêu cầu sau vào nhóm (có thể nhiều nhóm): (a) kiểm tra vỉ thuốc đủ 10 viên; (b) robot gắp bánh răng từ băng tải; (c) kiểm tra khe hở giữa nắp và thân hộp ≤ 0,3 mm; (d) đọc mã DataMatrix khắc laser trên chi tiết và gửi lên MES; (e) phát hiện bọt khí trong tấm nhựa trong; (f) kiểm tra nhãn dán đúng loại sản phẩm và không lệch quá 1 mm.
Xem đáp án
- (a) Có/không (thêm kiểm lỗi nếu cần phát hiện viên vỡ).
- (b) Dẫn hướng (cần hiệu chuẩn camera–robot).
- (c) Đo lường.
- (d) Nhận dạng.
- (e) Kiểm lỗi (vật trong suốt: thường thử đèn nền hoặc chiếu sáng trường tối).
- (f) Nhận dạng (đúng loại nhãn: khớp mẫu hoặc đọc mã) + đo lường (lệch bao nhiêu mm) + dẫn hướng (tìm vị trí nhãn).
Bài 2. Mã DataMatrix có module 0,25 mm. Camera 1280×1024 pixel. Tính số pixel trên một module khi FOV ngang là 40 mm và khi là 80 mm. Trường hợp nào an toàn?
Xem đáp án
module_mm, so_pixel = 0.25, 1280
for fov in (40, 80):
mm_px = fov / so_pixel
print(f"FOV {fov} mm: {mm_px:.4f} mm/px → {module_mm / mm_px:.1f} px/module")
FOV 40 mm: 0.0312 mm/px → 8.0 px/module
FOV 80 mm: 0.0625 mm/px → 4.0 px/module
FOV 40 mm cho 8 pixel/module: thoải mái. FOV 80 mm chỉ còn 4 pixel/module: nằm ở biên dưới của khuyến nghị, đọc được khi in đẹp nhưng dễ thất bại khi mã khắc laser mờ hoặc hơi mất nét. Nếu buộc phải có FOV 80 mm (vì vị trí mã thay đổi), hãy chọn camera độ phân giải cao hơn.
Bài 3. Trong ví dụ mục 5, nếu chấm bẩn nằm ngay sát mép chữ, phương pháp "có dung sai mép" có thể bỏ sót. Đề xuất hai cách giảm rủi ro này mà không quay lại trừ ảnh thuần túy.
Xem đáp án
- Căn chỉnh chính xác hơn trước khi so (khớp mẫu subpixel, hoặc đồ gá tốt hơn), để giảm được bán kính dung sai
r, thu hẹp vùng "mù". - Dùng ngưỡng khác nhau theo vùng: ngưỡng chặt ở vùng nền phẳng, ngưỡng nới ở vùng sát mép. Đây là ý tưởng của các mô hình biến thiên (variation model) trong thư viện thương mại: học độ biến động của từng pixel từ nhiều ảnh OK thay vì dùng một ảnh mẫu.
- Thêm một tiêu chí khác, ví dụ đo độ dày nét chữ: chấm bẩn dính vào nét làm nét dày lên bất thường.
Tóm tắt
- Năm nhóm: có/không, đo lường, kiểm lỗi, nhận dạng, dẫn hướng. Một trạm thật thường kết hợp vài nhóm.
- Mỗi nhóm có con số riêng phải hỏi: kích thước đặc điểm, dung sai, kích thước lỗi nhỏ nhất, kích thước module/ký tự, độ chính xác vị trí.
- Luôn tính
mm/pixelvà số pixel trên đặc điểm; đo lường cần quy tắc 10:1 và kỹ thuật subpixel. - Trừ ảnh mẫu rất nhạy với lệch vị trí; cần căn chỉnh và dung sai mép.
- Chấm độ khó theo 8 yếu tố; từ 10/16 trở lên phải làm thử với mẫu thật trước khi cam kết.
Bài tiếp theo: Halcon, VisionPro, OpenCV, smart camera: chọn công cụ cho từng loại dự án và ngân sách.


