⭐ Vision Engineer · Chặng 6Bài 5/8Bài học~60 phút

7 kiểu chiếu sáng Machine Vision: chọn đèn theo bề mặt và loại lỗi

Backlight, đồng trục, vòm, dark field góc thấp, đèn thanh, laser: hình học bright/dark field, mô phỏng CNR từng loại lỗi và quy trình thử đèn có chấm điểm.

7 kiểu chiếu sáng Machine Vision: chọn đèn theo bề mặt và loại lỗi

Học xong bài này, bạn sẽ

  • Chọn backlight, ring, coaxial, dome, low-angle…
  • Liên hệ kiểu chiếu sáng với loại lỗi
  • Thử nghiệm chiếu sáng có phương pháp

Nên học trước: Ống kính telecentric: khi nào cần?

Nội dung bài viết
  1. 1. Ánh sáng đến camera bằng con đường nào?
  2. 2. Bright field và dark field: chỉ là chuyện góc
  3. 3. Bảy kiểu chiếu sáng
  4. 4. Mô phỏng: cùng một bề mặt dưới bốn kiểu đèn
  5. 5. Bảng tra: loại lỗi × bề mặt → đèn thử trước
  6. 6. Thử nghiệm chiếu sáng có phương pháp
  7. 7. Sai lầm thường gặp
  8. 8. Bài tập
  9. Tóm tắt

Kỹ sư Machine Vision có kinh nghiệm hay nói: "chiếu sáng quyết định một nửa thành công của hệ thống". Mục tiêu của chiếu sáng không phải là làm ảnh "đẹp", mà là làm lỗi cần tìm nổi bật và làm mọi thứ khác chìm đi. Một vết xước có thể sáng rực, tối đen hoặc biến mất hoàn toàn trên cùng một chi tiết, chỉ tùy đèn đặt ở đâu. Ở bài Ống kính telecentric: khi nào cần? bạn đã thấy đèn nền chiếu song song đi cặp với ống kính telecentric; bài này mở rộng ra toàn bộ 7 kiểu chiếu sáng, giải thích bằng hình học phản xạ vì sao mỗi kiểu làm nổi một loại lỗi, kiểm chứng bằng mô phỏng có số liệu, và cho bạn một quy trình thử đèn có chấm điểm. Bài sau, Màu đèn, kính lọc và phân cực, sẽ chọn tiếp bước sóng và bộ lọc cho kiểu đèn đã chọn ở đây.

Mục tiêu cuối bài(1) Gọi đúng tên và mô tả hình học của backlight, đèn vòng, đồng trục, vòm, góc thấp, thanh, ánh sáng có cấu trúc; (2) với một loại lỗi trên một loại bề mặt, dự đoán được lỗi sẽ sáng hay tối dưới từng kiểu đèn và giải thích bằng góc phản xạ; (3) thử nghiệm chiếu sáng có phương pháp: cùng bộ mẫu, cùng chỉ số (CNR, độ đều, bão hòa), quyết định bằng số.

1. Ánh sáng đến camera bằng con đường nào?

Khi ánh sáng gặp bề mặt, có ba hiện tượng chính mà kỹ sư chiếu sáng cần phân biệt:

  • Phản xạ gương (specular): tia phản xạ đối xứng với tia tới qua pháp tuyến bề mặt (góc tới bằng góc phản xạ). Kim loại mài, kính, nhựa bóng, sơn bóng phản xạ chủ yếu kiểu này. Chỉ cần bề mặt nghiêng α độ, tia phản xạ lệch 2α: một chỗ móp nghiêng 5° đủ để hắt ánh sáng ra khỏi ống kính.
  • Phản xạ khuếch tán (diffuse, mô hình Lambert): ánh sáng tỏa đều mọi hướng, độ sáng tỉ lệ với cos góc giữa pháp tuyến và hướng tới đèn, gần như không phụ thuộc hướng nhìn. Giấy, nhựa mờ, gỗ, kim loại phun cát là bề mặt khuếch tán. Thông tin chính trên các bề mặt này là hệ số phản xạ (màu, mực in) và hướng nghiêng so với đèn.
  • Truyền qua / bị chặn: ánh sáng đi xuyên qua vật trong suốt hoặc bị vật đục chặn lại. Đây là cơ sở của đèn nền (backlight).

Từ đó, câu hỏi đầu tiên khi chọn đèn cho một loại lỗi luôn là: lỗi này làm ánh sáng đổi hướng (thay đổi hình học bề mặt), đổi cường độ (thay đổi hệ số phản xạ, màu) hay chặn ánh sáng (biên dạng)?

Lỗi thay đổiVí dụKiểu đèn làm nổiKiểu đèn làm chìm
Hướng bề mặt (hình học)Xước, móp, vết dập, chữ dập nổi, ba viaChiếu có hướng: đồng trục trên mặt bóng, góc thấp, thanh một phíaVòm (dome) khuếch tán đều
Hệ số phản xạ / màuMực in, vết bẩn, vết cháy, nhãnKhuếch tán đều: vòm, đèn vòng có tấm tán xạ; chọn màu đèn (bài sau)Góc thấp (mực phẳng không tán xạ khác nền nhiều)
Biên dạng, có/khôngĐường kính lỗ, chiều dài, đếm chi tiết, mức chất lỏngĐèn nền (backlight)Đèn chiếu mặt trên lên vật nhiều màu, nhiều độ bóng
Chiều cao (3D)Chiều cao keo, độ phẳng, thể tíchÁnh sáng có cấu trúc (vạch laser, sọc)Mọi kiểu đèn 2D (chiều cao chỉ thấy gián tiếp)

2. Bright field và dark field: chỉ là chuyện góc

Hai thuật ngữ này không phải tên đèn mà là quan hệ hình học giữa đèn, bề mặt và ống kính:

  • Bright field (trường sáng): phản xạ gương của đèn trên phần bề mặt phẳng, bình thường đi vào ống kính. Nền sáng; chỗ nào làm tia lệch đi (xước, móp, bụi, vết khắc nhám) thì tối.
  • Dark field (trường tối): phản xạ gương của phần bề mặt bình thường đi ra ngoài ống kính. Nền tối; chỉ chỗ nào nghiêng đúng góc hoặc tán xạ (thành vết xước, mép, bụi, chữ dập) mới hắt ánh sáng về camera và hiện sáng.

Điều kiện cụ thể: ống kính nhận ánh sáng trong một hình nón nửa góc β = atan(D/2 / WD) với D là đường kính đồng tử vào. Đèn lệch trục θ, chiếu lên mặt nghiêng α, tia phản xạ lệch trục |θ − 2α|. Ánh sáng vào ống kính khi |θ − 2α| ≤ β. Tính cho một ống kính có đồng tử 10 mm đặt cách vật 200 mm:

import math

# A. Mặt phẳng nghiêng α phản xạ gương vào ống kính khi nào?
WD, D_PUPIL = 200.0, 10.0                         # mm: khoảng làm việc, đường kính đồng tử vào
beta = math.degrees(math.atan(D_PUPIL / 2 / WD))  # nửa góc nhận ánh sáng của ống kính
print(f"Nửa góc nhận của ống kính: β = {beta:.1f}°")
print("đèn lệch trục θ | mặt phẳng (α=0) | mặt nghiêng α hắt vào ống kính")
for theta in (0, 1, 10, 30, 60, 80):
    lo, hi = max(0.0, (theta - beta) / 2), (theta + beta) / 2
    loai = "SÁNG (bright field)" if theta <= beta else "tối  (dark field) "
    print(f"{theta:13d}°  | {loai} | α từ {lo:4.1f}° đến {hi:4.1f}°")

# B. Đèn vòng trên mặt phẳng bóng: vòng chói xuất hiện ở bán kính nào trên vật?
Zc = 200.0                                        # camera (đồng tử vào) cao 200 mm
print("\nĐèn vòng bán kính R, cao Zl → vòng chói tại x = R·Zc/(Zl + Zc)")
for R, Zl in ((40, 100), (40, 30), (60, 20), (90, 10)):
    x = R * Zc / (Zl + Zc)
    print(f"R = {R:3d} mm, Zl = {Zl:3d} mm: vòng chói bán kính {x:5.1f} mm, "
          f"góc tới {math.degrees(math.atan((R - x) / Zl)):4.1f}°")
Nửa góc nhận của ống kính: β = 1.4°
đèn lệch trục θ | mặt phẳng (α=0) | mặt nghiêng α hắt vào ống kính
            0°  | SÁNG (bright field) | α từ  0.0° đến  0.7°
            1°  | SÁNG (bright field) | α từ  0.0° đến  1.2°
           10°  | tối  (dark field)  | α từ  4.3° đến  5.7°
           30°  | tối  (dark field)  | α từ 14.3° đến 15.7°
           60°  | tối  (dark field)  | α từ 29.3° đến 30.7°
           80°  | tối  (dark field)  | α từ 39.3° đến 40.7°

Đèn vòng bán kính R, cao Zl → vòng chói tại x = R·Zc/(Zl + Zc)
R =  40 mm, Zl = 100 mm: vòng chói bán kính  26.7 mm, góc tới  7.6°
R =  40 mm, Zl =  30 mm: vòng chói bán kính  34.8 mm, góc tới  9.9°
R =  60 mm, Zl =  20 mm: vòng chói bán kính  54.5 mm, góc tới 15.3°
R =  90 mm, Zl =  10 mm: vòng chói bán kính  85.7 mm, góc tới 23.2°

Phần A cho thấy ống kính chỉ "nhìn" một hình nón rất hẹp (±1,4°). Đèn đặt lệch trục hơn β là dark field đối với mặt phẳng; đèn càng thấp thì mặt phải nghiêng càng nhiều mới hắt vào ống kính: đèn 80° chỉ "bắt" các mặt nghiêng khoảng 40°, chính là thành của một vết xước sâu, mép của chữ dập. Đó là lý do đèn góc thấp làm vết xước sáng rực mà gần như bỏ qua vết móp nông. Thực tế đèn có kích thước và bề mặt có độ nhám, nên dải α rộng hơn vài độ, nhưng xu hướng giữ nguyên.

Phần B giải thích hiện tượng hay gặp với đèn vòng trên vật bóng: với camera thật (phối cảnh), mỗi điểm trên vật được nhìn dưới một góc khác nhau, nên luôn có một vòng tròn trên vật mà tại đó phản xạ gương của đèn đi đúng vào ống kính, tạo vòng chói bán kính x = R·Zc/(Zl + Zc). Đèn vòng to, cao 100 mm cho vòng chói 26,7 mm, nằm giữa ảnh: rất khó chịu. Hạ đèn sát vật và mở rộng bán kính (hàng cuối) đẩy vòng chói ra 85,7 mm, ngoài trường nhìn: trong FOV chỉ còn dark field. Cùng một chiếc đèn vòng, đổi độ cao là đổi từ bright field sang dark field.

Bề mặt quyết định, không phải tên đènTrên vật khuếch tán (giấy, nhựa mờ), khái niệm bright/dark field gần như không có ý nghĩa vì vật tỏa sáng mọi hướng: đèn nào cũng cho nền sáng, chỉ độ đều và độ tương phản bóng đổ thay đổi. Hai khái niệm chỉ có tác dụng mạnh trên bề mặt có thành phần phản xạ gương lớn. Luôn hỏi "bề mặt bóng hay mờ?" trước khi hỏi "dùng đèn gì?".

3. Bảy kiểu chiếu sáng

KiểuHình họcNền / lỗi hiện raDùng choKhông hợp
1. Đèn nền (backlight)Đèn sau vật, đối diện cameraVật đen như bóng, nền trắngBiên dạng, lỗ xuyên, đếm, mức chất lỏng, vật trong suốtBất cứ thứ gì trên mặt trên của vật
2. Đèn vòng (ring, bright field)Vòng LED quanh ống kính, chiếu gần trụcMặt mờ sáng đều; mặt bóng có vòng chóiNhãn, in ấn, có/không linh kiện trên vật mờVật cong, bóng
3. Đồng trục (coaxial)Gương bán phản xạ 45° đưa ánh sáng đi dọc trục cameraMặt phẳng bóng sáng đều; xước, móp, vết khắc tốiKim loại mài phẳng, wafer, kính, mã khắc trên mặt phẳng bóngVật cong, nghiêng, mặt mờ (ít lợi ích)
4. Vòm (dome, cloudy day)Ánh sáng tán xạ trong vòm, tới vật từ mọi hướngChói và địa hình bị xóa; chỉ còn khác biệt phản xạ (màu, mực)Vật cong, bóng, nhăn: lon, vỉ thuốc, linh kiện mạ, túi nilonLỗi chỉ có hình học (móp nông, xước "sạch")
5. Góc thấp (low-angle, dark field)Vòng hoặc thanh chiếu gần song song mặt vật (10–30° so với mặt)Mặt phẳng tối; mép, xước, chữ dập, bụi sángXước trên kim loại, kính; ký tự dập nổi/khắc sâu; bụiMực in phẳng, vật cao thấp nhiều (đèn phải sát vật)
6. Đèn thanh (bar) / đèn lineMột hay nhiều thanh LED, góc tùy chỉnh; đèn line đi với camera line scanBóng đổ có hướng: gờ, móp hiện sáng một bên, tối một bênVật lớn, băng tải, line scan, tạo bóng có hướngKhi cần độ đều trên vật cong, bóng
7. Ánh sáng có cấu trúc (structured light)Vạch laser hoặc mẫu sọc chiếu xiên, camera nhìn từ góc khácVạch cong theo chiều caoChiều cao keo, độ phẳng, thể tích, mối hàn, đo 3DĐọc in ấn, màu sắc

3.1. Đèn nền (backlight)

Camera chỉ thấy bóng của vật, nên kết quả gần như không phụ thuộc màu, độ bóng, vết bẩn trên mặt vật: đây là kiểu đèn ổn định nhất cho đo kích thước. Hai biến thể: đèn nền khuếch tán (rẻ, phổ biến, dùng cho đếm, có/không, đo dung sai rộng) và đèn nền chiếu song song (collimated) đi với ống kính telecentric, cho biên sắc và không bị phản xạ từ thành bên của chi tiết trụ bóng làm "ăn" vào biên. Đèn nền còn dùng cho vật trong suốt: mức chất lỏng, bọt khí, vết nứt chai lọ (vết nứt làm khúc xạ lệch tia nên hiện tối trên nền sáng). Lưu ý: chỉ đo được lỗ xuyên; lỗ không xuyên (lỗ mù) phải dùng đèn chiếu mặt trên.

3.2. Đèn vòng (ring light)

Rẻ, gọn, gắn ngay đầu ống kính, nên thường là chiếc đèn đầu tiên người mới mua. Trên vật mờ (giấy, nhựa, bìa carton) nó cho ảnh đều và đủ sáng. Trên vật bóng nó tạo vòng chói như tính ở mục 2; trên vật cong bóng (lon, chai) nó tạo các vệt sáng chạy theo đường cong. Thêm tấm tán xạ (diffuser) giảm chói nhưng không hết. Đèn vòng góc thấp (low-angle ring) là một kiểu khác hẳn, xếp vào nhóm dark field.

3.3. Đèn đồng trục (coaxial)

Một gương bán phản xạ đặt nghiêng 45° trước ống kính: ánh sáng từ bên hông bị phản xạ xuống dọc trục quang, ánh sáng từ vật đi ngược lên xuyên qua gương vào camera. Kết quả là chiếu sáng bright field đúng nghĩa trên toàn trường nhìn: mặt phẳng bóng sáng đều, mọi chỗ làm tia lệch quá vài độ đều tối. Nhược điểm: gương 50/50 làm mất một nửa ánh sáng ở chiều đi và một nửa ở chiều về, chỉ tối đa khoảng 25% ánh sáng của đèn tới được camera; chỉ hiệu quả khi mặt cần xem vuông góc trục camera (nghiêng 1–2° là sáng không đều); kích thước đèn phải lớn hơn FOV.

3.4. Đèn vòm (dome)

Ánh sáng LED chiếu vào mặt trong một vòm sơn trắng mờ, tán xạ rồi tới vật từ gần như mọi hướng, giống bầu trời nhiều mây nên còn gọi cloudy day illumination. Vì mọi hướng phản xạ gương đều "nhìn thấy" một vùng vòm sáng như nhau, chói và địa hình bề mặt bị xóa, chỉ còn khác biệt về hệ số phản xạ. Camera nhìn qua lỗ trên đỉnh vòm, nên mặt phẳng bóng nằm giữa ảnh phản chiếu đúng cái lỗ đó thành một đốm tối; loại vòm phẳng hoặc vòm có bù đồng trục khắc phục điều này. Vòm phải đặt sát vật (mép vòm cách vật vài mm đến vài chục mm), cồng kềnh và cản đường robot gắp.

3.5. Chiếu góc thấp (low-angle, dark field)

Ánh sáng tới gần như song song mặt vật (thường 10–30° so với mặt, tức 60–80° so với trục camera). Mặt phẳng phản xạ ánh sáng đi tiếp sang phía đối diện nên tối; mọi cạnh, thành xước, hạt bụi, chữ dập nổi làm tia đổi hướng lên camera nên sáng. Đây là lựa chọn số một cho vết xước trên kim loại và kính, ký tự dập, khắc sâu. Đèn phải đặt rất gần vật và đúng độ cao: vật cao thấp vài mm là vùng sáng dịch đi, nên cần đồ gá ổn định.

3.6. Đèn thanh (bar) và đèn line

Thanh LED gắn trên khớp chỉnh góc là "dụng cụ đa năng" khi thử nghiệm: đặt cao gần trục là bright field cho vật mờ, đặt thấp một phía là chiếu có hướng tạo bóng, làm nổi gờ và vết móp (một bên sáng, một bên tối). Bốn thanh quanh vật thay được đèn vòng cỡ lớn. Với camera line scan, đèn line (thanh hẹp có thấu kính hội tụ thành một dải sáng mạnh) là bắt buộc vì mỗi dòng chỉ phơi sáng vài chục µs.

3.7. Ánh sáng có cấu trúc (structured light)

Chiếu một vạch laser (hoặc mẫu sọc từ máy chiếu) xiên góc θ, camera nhìn thẳng: chỗ nào cao h thì vạch dịch ngang h·tan θ. Đây là nguyên lý đo tam giác (triangulation) của các cảm biến profile laser và camera 3D. Tính độ phân giải chiều cao với pixel 0,05 mm trên vật:

import math

# Camera nhìn thẳng xuống, vạch laser chiếu xiên góc θ so với phương thẳng đứng.
# Vật cao h làm vạch dịch ngang d = h · tan(θ) trên mặt vật.
pixel_mm = 0.05            # kích thước pixel trên vật (mm)
subpixel = 0.1             # tìm tâm vạch laser chính xác ~1/10 pixel
print("θ (độ) | dịch vạch khi h = 1 mm | độ phân giải chiều cao (1 px) | với subpixel 0,1 px")
for theta in (15, 30, 45, 60):
    t = math.tan(math.radians(theta))
    print(f"{theta:6d} | {t:8.3f} mm = {t / pixel_mm:5.1f} px    | "
          f"{pixel_mm / t:7.3f} mm                  | {subpixel * pixel_mm / t:6.4f} mm")
θ (độ) | dịch vạch khi h = 1 mm | độ phân giải chiều cao (1 px) | với subpixel 0,1 px
    15 |    0.268 mm =   5.4 px    |   0.187 mm                  | 0.0187 mm
    30 |    0.577 mm =  11.5 px    |   0.087 mm                  | 0.0087 mm
    45 |    1.000 mm =  20.0 px    |   0.050 mm                  | 0.0050 mm
    60 |    1.732 mm =  34.6 px    |   0.029 mm                  | 0.0029 mm

Góc lớn cho độ phân giải chiều cao tốt hơn nhưng vùng bị che khuất (occlusion: phía sau một bậc cao, camera hoặc laser không nhìn tới) lớn hơn; 30–45° là mức thường dùng. Bề mặt bóng phản xạ vạch laser gương ra ngoài hoặc tạo vệt phản xạ phụ, nên đo laser trên kim loại bóng khó hơn trên bề mặt mờ.

4. Mô phỏng: cùng một bề mặt dưới bốn kiểu đèn

Lý thuyết dễ quên, con số thì không. Đoạn mã sau tạo một bề mặt tổng hợp 160 × 360 pixel (mỗi pixel khoảng 20 µm) gồm: vân mài nhẹ, một vết xước sâu khoảng 40 µm có thành dốc khoảng 40° và đáy bị cày xới, một vết móp nông dốc tối đa khoảng 8°, và chữ "A7" in bằng mực mờ (chỉ đổi hệ số phản xạ, không đổi chiều cao). Từ bản đồ chiều cao, ta tính pháp tuyến bề mặt rồi dựng ảnh bằng mô hình phản xạ đơn giản: Lambert cho phần khuếch tán (kd · cos) và Blinn-Phong cho phần phản xạ gương (ks · cosn của góc giữa pháp tuyến và vector nửa đường giữa hướng đèn và hướng camera). Số mũ n = 200 cho thùy phản xạ hẹp như thép mài bóng; n = 10 cho nhựa mờ.

Chỉ số đánh giá là CNR (contrast-to-noise ratio, tỉ số tương phản trên nhiễu) = |chênh lệch mức xám trung bình giữa vùng lỗi và nền| / độ lệch chuẩn của nền. Dùng giá trị tuyệt đối vì một lỗi có thể sáng ở một mép và tối ở mép kia. Độ lệch chuẩn của nền gồm cả nhiễu cảm biến lẫn vân bề mặt: đúng thứ sẽ gây báo nhầm. Mỗi ảnh được chỉnh "phơi sáng" để điểm sáng nhất bằng 230, rồi cộng nhiễu cảm biến σ = 2 mức xám. Mô phỏng chạy khoảng 1–2 giây.

import numpy as np
import cv2

H, W = 160, 360                       # ảnh 160 × 360 pixel, mỗi pixel ≈ 20 µm trên vật
yy, xx = np.mgrid[0:H, 0:W].astype(np.float64)
rng = np.random.default_rng(0)

# --- 1. Bản đồ chiều cao z (đơn vị: pixel = 20 µm) --------------------------
nham = cv2.GaussianBlur(rng.normal(0, 1, (H, W)), (0, 0), 3)
z = 0.08 * nham / nham.std()                                # vân mài: dốc khoảng 1–2°
doc = (yy > 20) & (yy < 140)
z -= 2.0 * np.exp(-(xx - 60) ** 2 / (2 * 1.3 ** 2)) * doc   # vết xước: rãnh sâu ~40 µm, thành dốc ~40°
z -= 1.8 * np.exp(-((xx - 170) ** 2 + (yy - 80) ** 2) / (2 * 8.0 ** 2))  # vết móp: sâu ~36 µm, dốc ≤ 8°

# --- 2. Mặt nạ các vùng: chữ in chỉ đổi hệ số phản xạ, không đổi chiều cao
chu = np.zeros((H, W), np.uint8)
cv2.putText(chu, "A7", (250, 110), cv2.FONT_HERSHEY_SIMPLEX, 2.0, 255, 8)
VUNG = {"xước": doc & (np.abs(xx - 60) < 3),
        "móp": np.hypot(xx - 170, yy - 80) < 16,
        "chữ": chu > 0}
nen = (np.abs(xx - 60) > 12) & (np.hypot(xx - 170, yy - 80) > 20) & (chu == 0)

# --- 3. Pháp tuyến bề mặt từ gradient chiều cao
gx = cv2.Sobel(z, cv2.CV_64F, 1, 0, ksize=3) / 8
gy = cv2.Sobel(z, cv2.CV_64F, 0, 1, ksize=3) / 8
n = np.dstack([-gx, -gy, np.ones_like(z)])
n /= np.linalg.norm(n, axis=2, keepdims=True)
V = np.array([0.0, 0.0, 1.0])         # camera nhìn thẳng xuống


def huong(zenith, azimuth):
    """Vector đơn vị chỉ tới đèn; zenith = góc so với trục camera (độ)."""
    t, p = np.radians(zenith), np.radians(azimuth)
    return np.array([np.sin(t) * np.cos(p), np.sin(t) * np.sin(p), np.cos(t)])


def render(den, kd, ks, shine):
    """Lambert (khuếch tán) + Blinn-Phong (phản xạ gương) cho một danh sách đèn."""
    if den == "dome":                   # vòm sáng đều, lỗ camera được bù (dome + đồng trục)
        r_z = 2 * n[..., 2] ** 2 - 1    # thành phần z của hướng phản xạ gương
        return kd * (1 + n[..., 2]) / 2 + ks * (r_z > 0)
    img = np.zeros((H, W))
    for L, w in den:
        hv = (L + V) / np.linalg.norm(L + V)
        img += w * (kd * np.clip(n @ L, 0, None) + ks * np.clip(n @ hv, 0, None) ** shine)
    return img


DEN = {
    "Đồng trục (bright field)": [(huong(0, 0), 1.0)],
    "Vòng góc thấp (dark field)": [(huong(80, a), 1 / 24) for a in range(0, 360, 15)],
    "Thanh góc thấp 1 phía": [(huong(75, 0), 1.0)],
    "Vòm (dome)": "dome",
}


DAY_XUOC = (0.45, 0.30)   # (kd, ks) của đáy rãnh bị cày xới: nhám, tán xạ mạnh hơn nền


def thi_nghiem(ten_vl, kd_nen, ks_nen, shine):
    day = VUNG["xước"] & (np.abs(xx - 60) < 2)
    kd = np.where(VUNG["chữ"], 0.05, np.where(day, DAY_XUOC[0], kd_nen))
    ks = np.where(VUNG["chữ"], 0.02, np.where(day, DAY_XUOC[1], ks_nen))
    print(f"== {ten_vl}")
    print(f"{'Chiếu sáng':26s} {'nền μ±σ':>9s} | {'xước Δ':>6s} {'CNR':>5s} | "
          f"{'móp Δ':>5s} {'CNR':>5s} | {'chữ Δ':>5s} {'CNR':>5s}")
    anh = []
    for ten, den in DEN.items():
        raw = render(den, kd, ks, shine)
        raw *= 230 / raw.max()                        # chỉnh phơi sáng: điểm sáng nhất = 230
        img = np.clip(raw + rng.normal(0, 2, raw.shape), 0, 255).astype(np.uint8)  # nhiễu σ = 2
        anh.append(img)
        f = img.astype(np.float64)
        mb, sb = f[nen].mean(), f[nen].std()
        dong = f"{ten:26s} {mb:4.0f}±{sb:<4.1f} |"
        for vung in VUNG.values():
            delta = np.abs(f[vung] - mb).mean()       # |chênh lệch| trung bình so với nền
            dong += f" {delta:6.0f} {delta / sb:5.1f} |"
        print(dong)
    return np.vstack(anh)


a1 = thi_nghiem("Thép mài bóng (kd=0.15, ks=0.85)", 0.15, 0.85, 200)
a2 = thi_nghiem("Nhựa mờ (kd=0.80, ks=0.05)", 0.80, 0.05, 10)
cv2.imwrite("chieu_sang_thep.png", a1)
cv2.imwrite("chieu_sang_nhua.png", a2)
np.savez_compressed("chieu_sang.npz", thep=a1, nhua=a2, nen=nen, **VUNG)
print("Đã lưu chieu_sang_thep.png, chieu_sang_nhua.png (4 ảnh xếp dọc theo thứ tự bảng)")
== Thép mài bóng (kd=0.15, ks=0.85)
Chiếu sáng                   nền μ±σ | xước Δ   CNR | móp Δ   CNR | chữ Δ   CNR
Đồng trục (bright field)    217±12.0 |    139  11.6 |    115   9.6 |    202  16.8 |
Vòng góc thấp (dark field)   43±2.0  |     98  48.4 |      2   0.8 |     29  14.3 |
Thanh góc thấp 1 phía        10±2.1  |     72  33.8 |      3   1.5 |      7   3.3 |
Vòm (dome)                  230±2.0  |     40  19.6 |      2   0.8 |    214 105.9 |
== Nhựa mờ (kd=0.80, ks=0.05)
Chiếu sáng                   nền μ±σ | xước Δ   CNR | móp Δ   CNR | chữ Δ   CNR
Đồng trục (bright field)    229±2.0  |     72  35.8 |      3   1.3 |    211 104.3 |
Vòng góc thấp (dark field)  141±2.0  |     49  24.2 |      2   0.8 |    132  64.9 |
Thanh góc thấp 1 phía        73±5.5  |     93  16.9 |     20   3.6 |     68  12.4 |
Vòm (dome)                  229±2.0  |     28  13.9 |      2   0.9 |    211 104.5 |
Đã lưu chieu_sang_thep.png, chieu_sang_nhua.png (4 ảnh xếp dọc theo thứ tự bảng)

Đọc bảng thép bóng, từng cột một:

  • Vết xước: dark field góc thấp thắng rõ (CNR 48): nền thép tối, thành xước hắt ánh sáng lên camera. Đồng trục cũng thấy (xước tối trên nền sáng, CNR 11,6) nhưng thua vì chính nền đồng trục "nhiễu" hơn: σ = 12 do vân mài nghiêng 1–2° đã làm tia lệch khỏi thùy phản xạ hẹp. Đồng trục làm lộ mọi bất thường nhỏ của mặt bóng, kể cả những thứ không phải lỗi.
  • Vết móp nông: chỉ đồng trục thấy (CNR 9,6). Mặt móp nghiêng tới 8° làm phản xạ lệch tới 16°, ra khỏi ống kính, nên tối. Dark field góc thấp cần mặt nghiêng khoảng 40° mới hắt sáng (mục 2), nên vết móp 8° vô hình (CNR 0,8). Vòm xóa địa hình nên cũng vô hình.
  • Chữ in: vòm thắng tuyệt đối (CNR 106) với nền đều nhất (σ = 2,0, chỉ còn nhiễu cảm biến). Vòm nhìn thấy đúng thứ đã thay đổi: hệ số phản xạ.
  • Thanh một phía trên thép bóng tương tự dark field cho xước nhưng nền rất tối (10) và chỉ thấy thành xước quay về phía đèn.

Bảng nhựa mờ cho bài học ngược lại: trên bề mặt khuếch tán, đồng trục không còn lợi thế (nền sáng đều như mọi đèn chiếu gần trục); vết móp chỉ hiện dưới thanh góc thấp một phía nhờ bóng đổ Lambert (một sườn quay về đèn sáng hơn, sườn kia tối hơn), dù CNR chỉ 3,6 vì chính vân bề mặt cũng đổ bóng (σ nền tăng lên 5,5). Đèn vòng góc thấp chiếu từ mọi phía nên hai sườn bù trừ nhau, vết móp lại biến mất. Mở hai file PNG để nhìn 4 ảnh xếp dọc theo thứ tự bảng.

Mô phỏng chỉ để rèn trực giácMô hình Lambert + Blinn-Phong bỏ qua tán xạ nhiều lần, bóng đổ, kích thước thật của đèn và phối cảnh của ống kính. Con số tuyệt đối không dùng được cho thiết kế; xu hướng (đèn nào thắng cho lỗi nào, vì sao) thì đúng và khớp kinh nghiệm thực tế. Quyết định cuối cùng luôn đến từ ảnh chụp mẫu thật (mục 6).

5. Bảng tra: loại lỗi × bề mặt → đèn thử trước

Cần kiểm traBề mặtThử trướcPhương án 2Lỗi hiện ra
Kích thước, biên dạng, lỗ xuyênBất kỳBacklight (chiếu song song nếu dung sai chặt)Đồng trục với lỗ mù trên mặt bóngVật đen, lỗ sáng
Vết xướcKim loại, kính phẳng bóngDark field góc thấpĐồng trụcSáng trên nền tối / tối trên nền sáng
Móp, lồi nôngPhẳng bóngĐồng trụcLệch phản xạ (deflectometry, màn sọc)Tối trên nền sáng
Móp, gợnMờThanh góc thấp một phía (chụp 2–4 hướng)Ánh sáng có cấu trúcSáng/tối hai sườn
In ấn, nhãn, vết bẩnMờ, phẳngĐèn vòng / thanh có tán xạVòmTheo màu (chọn màu đèn, bài sau)
In ấn, ký tự, mãCong, bóng, nhănVòmĐèn thanh đặt tránh góc phản xạMực tối trên nền đều
Chữ dập nổi, dập chìmKim loại, nhựaDark field góc thấpThanh một phíaMép chữ sáng
Bụi, xước trên kính, màn hìnhTrong suốt bóngDark field góc thấpBacklight (vết nứt)Hạt sáng trên nền tối
Chiều cao keo, phẳng, thể tíchMờ tốt nhấtVạch laserCamera 3D sọc chiếuProfile chiều cao

6. Thử nghiệm chiếu sáng có phương pháp

Cách làm sai phổ biến: lắp đèn đầu tiên có sẵn, chỉnh phơi sáng cho "nhìn được", rồi đẩy phần khó sang thuật toán. Cách làm đúng là một thí nghiệm có kiểm soát, giống như bạn vừa làm với mô phỏng:

  1. Bộ mẫu: ít nhất 5–10 mẫu OK (gồm cả mẫu OK "xấu nhất" còn được chấp nhận: vết dầu, vân mài đậm, màu lệch lô) và mẫu NG cho từng loại lỗi, ưu tiên lỗi nhỏ nhất phải bắt. Đánh số mẫu, chụp mọi cấu hình trên cùng bộ mẫu.
  2. Cố định những thứ không thử: camera, ống kính, khoảng làm việc, khẩu độ, gain = 0. Với mỗi cấu hình đèn, chỉnh phơi sáng (hoặc dòng đèn) để vùng sáng nhất cần quan tâm khoảng 200–230, không bão hòa.
  3. Ma trận thử: kiểu đèn × góc/độ cao × màu (bài sau). Ví dụ 4 kiểu × 2 độ cao × 2 màu = 16 cấu hình. Ghi lại tên đèn, khoảng cách, góc, dòng, phơi sáng cho từng ảnh (tên file chứa mã cấu hình).
  4. Đo bằng số trên ROI cố định: CNR cho từng loại lỗi, độ đều nền (σ/μ hoặc min/max trên vùng nền), tỉ lệ pixel bão hòa. Không chấm "ảnh nhìn đẹp".
  5. Luật loại rồi mới xếp hạng: loại cấu hình có lỗi bất kỳ CNR < 5 (quy tắc kinh nghiệm: CNR 3–5 là ngưỡng phát hiện được, sản xuất cần dư địa), bão hòa > 0,5%, nền không đều quá mức thuật toán chịu được. Trong số còn lại, chọn cấu hình có CNR nhỏ nhất (lỗi khó nhất) lớn nhất.
  6. Thử độ bền cho 1–2 cấu hình tốt nhất: vật lệch cao ±1–2 mm, xoay, nghiêng 1–2°, đèn yếu đi 20%, bật/tắt đèn xưởng. Cấu hình mà CNR sụp khi vật nghiêng 1° (đồng trục hay bị) là cấu hình rủi ro.
  7. Ghi biên bản: ảnh, bảng số, lựa chọn và lý do. Đây là tài liệu bạn sẽ cần khi khách hỏi "tại sao không dùng đèn rẻ hơn".

Áp dụng bước 4–5 lên 4 ảnh thép bóng đã lưu ở mục 4, cho ba trạm có yêu cầu khác nhau:

import numpy as np

d = np.load("chieu_sang.npz")
TEN = ["Đồng trục", "Dark field vòng", "Thanh 1 phía", "Vòm"]
anh = np.split(d["thep"].astype(np.float64), 4)     # 4 ảnh thép bóng, cùng thứ tự với bảng
nen = d["nen"]
CNR_MIN, BAO_HOA_MAX = 5.0, 0.5                     # luật: CNR ≥ 5, pixel bão hòa ≤ 0,5 %


def danh_gia(img, can_thay):
    mb, sb = img[nen].mean(), img[nen].std()
    cnr = {k: np.abs(img[d[k]] - mb).mean() / sb for k in can_thay}
    bao_hoa = 100 * (img >= 250).mean()
    cv = 100 * sb / max(mb, 1)                       # độ không đều của nền (%)
    dat = min(cnr.values()) >= CNR_MIN and bao_hoa <= BAO_HOA_MAX
    return min(cnr.values()), min(cnr, key=cnr.get), bao_hoa, cv, dat


for tram, can_thay in (("Trạm 1: tìm xước + móp", ["xước", "móp"]),
                       ("Trạm 2: đọc chữ in", ["chữ"]),
                       ("Trạm 3: xước + chữ", ["xước", "chữ"])):
    print(f"== {tram}")
    kq = []
    for ten, img in zip(TEN, anh):
        cmin, yeu, bh, cv, dat = danh_gia(img, can_thay)
        kq.append((dat, cmin, ten))
        print(f"   {ten:16s} CNR nhỏ nhất {cmin:5.1f} ({yeu:4s}) | bão hòa {bh:4.1f}% | "
              f"nền không đều {cv:4.1f}% | {'ĐẠT' if dat else 'loại'}")
    dat_list = [k for k in kq if k[0]]
    print("   → chọn:", max(dat_list)[2] if dat_list else "không cấu hình nào đạt, cần phối hợp 2 lần chụp")
== Trạm 1: tìm xước + móp
   Đồng trục        CNR nhỏ nhất   9.6 (móp ) | bão hòa  0.0% | nền không đều  5.5% | ĐẠT
   Dark field vòng  CNR nhỏ nhất   0.8 (móp ) | bão hòa  0.0% | nền không đều  4.7% | loại
   Thanh 1 phía     CNR nhỏ nhất   1.5 (móp ) | bão hòa  0.0% | nền không đều 21.0% | loại
   Vòm              CNR nhỏ nhất   0.8 (móp ) | bão hòa  0.0% | nền không đều  0.9% | loại
   → chọn: Đồng trục
== Trạm 2: đọc chữ in
   Đồng trục        CNR nhỏ nhất  16.8 (chữ ) | bão hòa  0.0% | nền không đều  5.5% | ĐẠT
   Dark field vòng  CNR nhỏ nhất  14.3 (chữ ) | bão hòa  0.0% | nền không đều  4.7% | ĐẠT
   Thanh 1 phía     CNR nhỏ nhất   3.3 (chữ ) | bão hòa  0.0% | nền không đều 21.0% | loại
   Vòm              CNR nhỏ nhất 105.9 (chữ ) | bão hòa  0.0% | nền không đều  0.9% | ĐẠT
   → chọn: Vòm
== Trạm 3: xước + chữ
   Đồng trục        CNR nhỏ nhất  11.6 (xước) | bão hòa  0.0% | nền không đều  5.5% | ĐẠT
   Dark field vòng  CNR nhỏ nhất  14.3 (chữ ) | bão hòa  0.0% | nền không đều  4.7% | ĐẠT
   Thanh 1 phía     CNR nhỏ nhất   3.3 (chữ ) | bão hòa  0.0% | nền không đều 21.0% | loại
   Vòm              CNR nhỏ nhất  19.6 (xước) | bão hòa  0.0% | nền không đều  0.9% | ĐẠT
   → chọn: Vòm

Kết luận rút ra không phải "đèn nào tốt nhất" mà là "đèn nào tốt nhất cho yêu cầu này". Trạm 1 phải bắt vết móp nên chỉ đồng trục đạt, dù nó không phải đèn tốt nhất cho xước. Trạm 2 chọn vòm. Trạm 3 chọn vòm vì vết xước mô phỏng có đáy bị cày xới, đổi hệ số phản xạ; bài tập 3 sẽ cho bạn thấy kết luận này đổi thế nào khi vết xước "sạch". Khi không cấu hình đơn nào đạt mọi yêu cầu, phương án là chụp 2 lần với 2 đèn chớp lần lượt (ví dụ đồng trục rồi dark field) hoặc tách 2 trạm, như trong bài tập lớn cuối chặng.

7. Sai lầm thường gặp

  • Chọn đèn theo tên lỗi mà quên bề mặt: "xước thì dùng dark field" đúng trên kim loại bóng, nhưng trên nhựa mờ thành xước tán xạ gần như nền, dark field cho tương phản kém hơn hẳn.
  • Đèn vòng cho mọi thứ: trên vật bóng, vòng chói nằm đúng giữa vùng cần kiểm tra. Tính bán kính vòng chói trước khi mua.
  • Chỉ thử với mẫu OK đẹp và một mẫu NG rõ: đèn nào cũng thấy lỗi to. Thứ quyết định là lỗi nhỏ nhất so với biến động của mẫu OK xấu nhất.
  • Bù đèn kém bằng gain: gain khuếch đại cả nhiễu, CNR không tăng. Chỉnh dòng đèn, phơi sáng, khẩu độ.
  • Dùng vòm cho lỗi hình học: vòm được thiết kế để xóa địa hình. Vết móp, xước sạch sẽ biến mất.
  • Quên dung sai lắp đặt: dark field góc thấp và đồng trục rất nhạy với độ cao, độ nghiêng của vật. Ghi lại vị trí đèn bằng số, làm giá gá có chốt định vị để thay đèn không phải chỉnh lại.
  • Không tính đến lão hóa và bụi: đèn LED yếu dần, vòm bám bụi. Chọn cấu hình còn dư CNR, và giám sát độ sáng trong sản xuất (bài Kiểm soát ánh sáng môi trường).

8. Bài tập

Bài 1. Với 3 bài toán sau, chọn kiểu chiếu sáng và giải thích: (a) đo đường kính lỗ trên tấm thép dập, dung sai ±0,05 mm; (b) kiểm tra vết xước trên nắp kim loại phẳng mài bóng; (c) đọc chữ khắc laser (số lô) trên thân trục thép.

Xem đáp án
  • (a) Lỗ xuyên: đèn nền. Lỗi cần đo là biên dạng (ánh sáng bị chặn hay lọt qua), không phụ thuộc màu, vết dầu trên mặt thép. Dung sai ±0,05 mm (dải 0,1 mm) là chặt: dùng đèn nền chiếu song song + ống kính telecentric để tránh phản xạ trên thành lỗ và sai số thấy thành bên (bài Ống kính telecentric: khi nào cần?). Nếu là lỗ mù (không xuyên), không dùng được đèn nền: dùng đồng trục (mặt thép sáng, miệng lỗ tối) hoặc góc thấp (mép lỗ sáng).
  • (b) Xước trên kim loại phẳng bóng: dark field góc thấp, dự phòng đồng trục. Thép bóng là bề mặt phản xạ gương, mặt phẳng hắt ánh sáng góc thấp ra ngoài nên tối, thành xước dốc hắt về camera nên sáng (mô phỏng: CNR 48 so với 11,6 của đồng trục). Đồng trục dùng khi cần bắt cả vết móp nông, nhưng nhạy với vân mài và độ nghiêng của nắp.
  • (c) Chữ khắc laser trên trục: vòm (hoặc thanh đặt dọc trục, tránh góc phản xạ gương). Vết khắc laser trên thép thường làm bề mặt nhám và sẫm màu (oxi hóa), tức là thay đổi hệ số phản xạ, còn thân trục cong làm đèn có hướng tạo vệt chói chạy dọc trục. Vòm xóa chói trên mặt cong, giữ lại khác biệt nhám/sẫm: chữ tối trên nền đều. Nếu chữ khắc trên mặt phẳng bóng, đồng trục cho chữ tối trên nền sáng rất rõ; nếu chữ khắc sâu hay dập (không đổi màu), dark field góc thấp làm mép chữ sáng.

Bài 2. Camera (đồng tử vào) cách mặt vật bóng 300 mm, FOV 80 × 60 mm. Bạn có đèn vòng bán kính 35 mm. Ở độ cao nào trên vật thì vòng chói nằm ngoài FOV (bán kính tới góc FOV là 50 mm)? Kết luận gì?

Xem đáp án

Vòng chói ở x = R·Zc/(Zl + Zc). Muốn x > 50 mm cần R·Zc/(Zl + Zc) > 50, tức Zl < R·Zc/50 − Zc = 35·300/50 − 300 = −90 mm: không thể, vì vòng chói luôn có bán kính nhỏ hơn R = 35 mm. Kiểm tra bằng số:

R, Zc = 35.0, 300.0
for Zl in (10, 50, 100, 200):
    print(f"Zl = {Zl:3d} mm → vòng chói bán kính {R * Zc / (Zl + Zc):5.1f} mm")
Zl =  10 mm → vòng chói bán kính  33.9 mm
Zl =  50 mm → vòng chói bán kính  30.0 mm
Zl = 100 mm → vòng chói bán kính  26.2 mm
Zl = 200 mm → vòng chói bán kính  21.0 mm

Một đèn vòng có bán kính nhỏ hơn FOV luôn để lại vòng chói trong ảnh vật bóng. Phải dùng đèn vòng góc thấp bán kính lớn hơn đường chéo FOV (R > 50 mm và đặt sát vật), hoặc đồng trục, hoặc vòm, tùy loại lỗi.

Bài 3. Trong mô phỏng mục 4, sửa DAY_XUOC = (0.15, 0.85) (đáy rãnh có cùng vật liệu với nền: vết xước "sạch", chỉ có hình học) rồi chạy lại. Dự đoán trước: CNR của vết xước dưới vòm thay đổi thế nào? Kết luận cho trạm 3 ở mục 6 còn đúng không?

Xem đáp án

Khi chạy lại, CNR vết xước dưới vòm trên thép bóng giảm từ 19,6 xuống khoảng 1,5: vòm xóa địa hình, mà vết xước giờ chỉ còn địa hình. Dark field vẫn thấy rõ (CNR khoảng 32) vì thành rãnh dốc vẫn hắt ánh sáng góc thấp lên camera, đồng trục khoảng 12,8. Trạm 3 (xước + chữ) không còn chọn được vòm: chạy lại cham_diem, vòm bị loại, dark field góc thấp lên đầu vì chữ in vẫn có CNR khoảng 25 dưới dark field. Bài học: vòm chỉ thấy vết xước nào làm đổi hệ số phản xạ (đáy cày xới, cháy, oxi hóa); vết xước "sạch" phải dùng đèn có hướng. Đó là lý do bộ mẫu thử phải có đúng loại lỗi thật, không phải lỗi "tương tự".

Tóm tắt

  • Câu hỏi đầu tiên: lỗi làm ánh sáng đổi hướng (hình học), đổi cường độ (phản xạ, màu) hay chặn ánh sáng (biên dạng)? Câu thứ hai: bề mặt bóng hay mờ?
  • Bright field: phản xạ gương của mặt phẳng vào ống kính, nền sáng, lỗi tối. Dark field: phản xạ đi ra ngoài, nền tối, lỗi sáng. Điều kiện: |θ − 2α| ≤ β, với β thường chỉ 1–2°.
  • Backlight cho biên dạng; đồng trục cho mặt phẳng bóng (bắt cả móp nông); dark field góc thấp cho xước, chữ dập, bụi; vòm cho in ấn trên vật cong bóng (xóa địa hình); đèn vòng cho vật mờ; đèn thanh để tạo bóng có hướng; vạch laser cho chiều cao (độ dịch = h·tan θ).
  • Đèn vòng trên vật bóng tạo vòng chói bán kính R·Zc/(Zl + Zc), luôn nhỏ hơn R.
  • Quyết định bằng thí nghiệm: bộ mẫu OK xấu nhất + NG nhỏ nhất, cố định mọi thứ khác, đo CNR từng lỗi, loại theo luật (CNR ≥ 5, không bão hòa), chọn CNR nhỏ nhất lớn nhất, rồi thử độ bền.

Bài tiếp theo: Màu đèn, kính lọc và phân cực, nơi bạn chọn bước sóng làm lỗi tối nhất, chặn ánh sáng xưởng bằng kính lọc và xóa chói bằng phân cực.

Bài tập thực hành

  1. Với 3 bài toán: đo đường kính lỗ, kiểm tra vết xước trên kim loại bóng, đọc chữ khắc laser, chọn kiểu chiếu sáng và giải thích.

Làm xong bài tập mới chuyển sang bài tiếp theo: tự viết code là cách duy nhất để nhớ lâu.

Bài tiếp theo
Ban biên tập HọcFree

Chúng tôi viết những bài hướng dẫn dễ hiểu, thực tế để ai cũng có thể tự học lập trình và ngoại ngữ, hoàn toàn miễn phí.