Computer vision
UAT 315 ปัญญาประดิษฐ์ การวิเคราะห์ข้อมูล และการมองเห็นด้วยคอมพิวเตอร์สำหรับระบบอากาศยานไร้คนขับ
บทเรียน
เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ
- อธิบายคอนโวลูชันและใช้ OpenCV แยกวัตถุด้วยสี นับ และหากรอบของวัตถุ
- อธิบายโครงสร้างของโครงข่ายประสาทแบบคอนโวลูชัน (CNN) และพัฒนาการตั้งแต่ LeNet ถึง ResNet
- แยกงานจำแนกภาพ ตรวจจับวัตถุ และแบ่งส่วนภาพ และอธิบายขั้นตอนตรวจจับรวมทั้ง NMS
- ติดตามวัตถุด้วยตัวกรองคาลมานอย่างง่าย และอธิบายการหลอมรวมข้อมูลเซนเซอร์
ทำไมต้องรู้
กล้องเป็นเซนเซอร์ที่ถูกและให้ข้อมูลมากที่สุดบนโดรน การมองเห็นด้วยคอมพิวเตอร์ (computer vision) ทำให้โดรนหาผู้ประสบภัย นับต้นไม้ ตรวจรอยร้าว หรือตามวัตถุได้ งานเหล่านี้มีตั้งแต่การประมวลผลภาพแบบดั้งเดิมที่อธิบายได้ทุกขั้น ไปจนถึงการเรียนรู้เชิงลึกที่แม่นกว่าแต่ต้องใช้ข้อมูลและการประเมินอย่างระมัดระวัง ผู้ใช้งานต้องรู้ว่าแต่ละวิธีทำอะไรได้และพลาดตรงไหน
คอนโวลูชันและการประมวลผลภาพ
คอนโวลูชัน (convolution) คือการเลื่อนตัวกรองขนาดเล็ก (kernel) ไปทั่วภาพ แล้วคูณและรวมค่าในแต่ละตำแหน่ง ตัวกรองต่างกันให้ผลต่างกัน เช่น เบลอภาพ หรือหาขอบ ตัวกรอง Sobel ในแนวนอนให้ค่าสูงตรงที่ความสว่างเปลี่ยนจากซ้ายไปขวา
import numpy as np
image = np.array([[10, 10, 10, 200, 200],
[10, 10, 10, 200, 200],
[10, 10, 10, 200, 200],
[10, 10, 10, 200, 200]], dtype=float)
sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=float)
out = np.zeros((image.shape[0] - 2, image.shape[1] - 2))
for i in range(out.shape[0]):
for j in range(out.shape[1]):
out[i, j] = np.sum(sobel_x * image[i:i + 3, j:j + 3])
print(out)
[[ 0. 760. 760.]
[ 0. 760. 760.]]
ค่าเป็นศูนย์ในบริเวณที่ความสว่างคงที่ และสูงตรงรอยต่อระหว่าง 10 กับ 200 ซึ่งคือขอบของวัตถุ ใน CNN ตัวกรองแบบนี้ไม่ได้ออกแบบโดยคน แต่เรียนรู้จากข้อมูลเอง
ตัวอย่างที่ 1 หากล่องสีส้มบนพื้นหญ้าด้วย OpenCV
สร้างภาพสังเคราะห์ขนาด 120 × 160 พื้นสีเขียวมีสัญญาณรบกวน วางกล่องสีส้มสามกล่อง แล้วแยกสีส้มในปริภูมิสี HSV (สี ความอิ่มตัว ความสว่าง) ซึ่งแยกสีได้ง่ายกว่า BGR
import cv2
rng = np.random.default_rng(345)
frame = np.full((120, 160, 3), (60, 130, 70), np.uint8)
frame = np.clip(frame.astype(int) + rng.integers(-15, 16, frame.shape), 0, 255).astype(np.uint8)
truth = [(20, 30, 16, 12), (90, 70, 20, 14), (130, 20, 10, 10)]
for x, y, w, h in truth:
frame[y:y + h, x:x + w] = (20, 120, 240)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (5, 150, 150), (25, 255, 255))
count, labels, stats, centroids = cv2.connectedComponentsWithStats(mask)
found = sorted(tuple(int(v) for v in s[:4]) for s in stats[1:])
print("objects found:", count - 1)
print("boxes (x, y, w, h):", found)
objects found: 3
boxes (x, y, w, h): [(20, 30, 16, 12), (90, 70, 20, 14), (130, 20, 10, 10)]
วิธีนี้ง่ายและอธิบายได้ทุกขั้น แต่ใช้ได้เฉพาะเมื่อวัตถุมีสีเด่นและแสงคงที่ ถ้ามีเงา แสงเย็น หรือวัตถุสีคล้ายกัน ช่วงสีที่ตั้งไว้จะพลาดทันที งานจริงจึงใช้การเรียนรู้เชิงลึก
โครงข่ายประสาทแบบคอนโวลูชัน
CNN (convolutional neural network) ซ้อนชั้นคอนโวลูชันหลายชั้น ชั้นต้นเรียนจับขอบและสี ชั้นลึกเรียนจับรูปทรงและวัตถุ ชั้น pooling ย่อขนาดข้อมูล และชั้นเชื่อมเต็ม (fully connected) ตัดสินคลาส
| ปี | งาน | จุดสำคัญ |
|---|---|---|
| 1998 | LeNet (LeCun และคณะ) | CNN อ่านตัวเลขเขียนมือ |
| 2012 | AlexNet (Krizhevsky และคณะ) | CNN ลึกบน GPU ชนะการแข่งขัน ImageNet อย่างขาดลอย |
| 2016 | ResNet (He และคณะ) | การเชื่อมข้ามชั้น (residual) ทำให้ฝึกเครือข่ายลึกมากได้ |
| 2016 | YOLO (Redmon และคณะ) | ตรวจจับวัตถุทั้งภาพในการประมวลผลครั้งเดียว เร็วพอสำหรับเวลาจริง |
| 2023 | Segment Anything (Kirillov และคณะ) | แบบจำลองแบ่งส่วนภาพที่ใช้กับภาพหลากหลายโดยไม่ต้องฝึกใหม่ |
จำแนก ตรวจจับ และแบ่งส่วน
- จำแนกภาพ (image classification) ตอบว่าทั้งภาพเป็นอะไร เช่น “มีพื้นที่น้ำท่วม”
- ตรวจจับวัตถุ (object detection) ตอบว่ามีวัตถุอะไร อยู่ตรงไหน เป็นกรอบสี่เหลี่ยมพร้อมคะแนนความมั่นใจ
- แบ่งส่วนภาพ (segmentation) ระบุคลาสของทุกพิกเซล เช่น น้ำ ถนน อาคาร
ตระกูล YOLO เป็นตัวตรวจจับที่นิยมบนโดรน รุ่นล่าสุดของ Ultralytics ขณะเขียนคือ YOLO26 (มกราคม 2026) ใบอนุญาต AGPL-3.0 ถ้าใช้ในผลิตภัณฑ์ที่ไม่เปิดโค้ดต้องซื้อใบอนุญาตแบบ Enterprise ตามที่หน่วยความรู้ “Computer Vision และการต่อยอดสู่ Edge AI” ของคลังความรู้โดรนเตือนไว้
ตัวตรวจจับมักให้กรอบหลายกรอบซ้อนบนวัตถุเดียว NMS (non-maximum suppression) เก็บกรอบที่คะแนนสูงสุด แล้วตัดกรอบอื่นที่ทับกับกรอบนั้นมากเกินเกณฑ์ ความทับวัดด้วย IoU คือพื้นที่ส่วนทับหารด้วยพื้นที่ส่วนรวม
def iou(a, b):
ax, ay, aw, ah = a
bx, by, bw, bh = b
inter_w = max(0, min(ax + aw, bx + bw) - max(ax, bx))
inter_h = max(0, min(ay + ah, by + bh) - max(ay, by))
inter = inter_w * inter_h
return inter / (aw * ah + bw * bh - inter)
def nms(boxes, scores, iou_threshold=0.5):
order = sorted(range(len(boxes)), key=lambda i: scores[i], reverse=True)
keep = []
for i in order:
if all(iou(boxes[i], boxes[k]) < iou_threshold for k in keep):
keep.append(i)
return keep
candidates = [(88, 69, 22, 15), (90, 70, 20, 14), (92, 72, 19, 13), (20, 30, 16, 12)]
scores = [0.81, 0.93, 0.66, 0.88]
print("IoU of box 0 and box 1:", round(iou(candidates[0], candidates[1]), 3))
print("kept after NMS:", [(candidates[i], scores[i]) for i in nms(candidates, scores)])
IoU of box 0 and box 1: 0.848
kept after NMS: [((90, 70, 20, 14), 0.93), ((20, 30, 16, 12), 0.88)]
สามกรอบแรกทับวัตถุเดียวกัน NMS เก็บเฉพาะกรอบคะแนน 0.93 และเก็บกรอบที่อยู่วัตถุอื่นไว้ เกณฑ์ IoU ของ NMS ต้องเลือกให้เหมาะ ถ้าต่ำเกินไป วัตถุสองชิ้นที่อยู่ติดกันจะถูกตัดเหลือชิ้นเดียว
ติดตามวัตถุและหลอมรวมข้อมูล
การตรวจจับทีละเฟรมไม่รู้ว่ากรอบในเฟรมนี้กับเฟรมก่อนเป็นวัตถุเดียวกันหรือไม่ การติดตาม (tracking) เชื่อมผลข้ามเฟรม และใช้แบบจำลองการเคลื่อนที่ช่วยลดสัญญาณรบกวน ตัวกรองคาลมาน (Kalman filter) ที่ Kalman เสนอในปี 1960 ผสานการทำนายจากแบบจำลองกับค่าที่วัดได้ โดยให้น้ำหนักตามความไม่แน่นอนของแต่ละฝั่ง หลักเดียวกันนี้ใช้ หลอมรวมข้อมูลเซนเซอร์ (sensor fusion) เช่น รวม GNSS กับ IMU ในตัวควบคุมการบิน
ตัวอย่างที่ 2 ติดตามตำแหน่งวัตถุที่เคลื่อนที่
วัตถุเคลื่อนที่ 2 m ต่อเฟรม ตำแหน่งที่วัดได้จากภาพมีความคลาดเคลื่อนส่วนเบี่ยงเบนมาตรฐาน 1.5 m ใช้ตัวกรองคาลมานแบบความเร็วคงที่ในหนึ่งมิติ
steps, speed, meas_sd = 30, 2.0, 1.5
truth_pos = speed * np.arange(steps)
measured = truth_pos + rng.normal(0, meas_sd, steps)
F = np.array([[1.0, 1.0], [0.0, 1.0]])
H = np.array([[1.0, 0.0]])
Q = np.diag([0.01, 0.01])
R = np.array([[meas_sd ** 2]])
x = np.array([measured[0], 0.0])
P = np.diag([R[0, 0], 4.0])
estimates = []
for z in measured:
x = F @ x
P = F @ P @ F.T + Q
K = P @ H.T @ np.linalg.inv(H @ P @ H.T + R)
x = x + (K @ (np.array([z]) - H @ x)).ravel()
P = (np.eye(2) - K @ H) @ P
estimates.append(x[0])
estimates = np.array(estimates)
rmse = lambda e: np.sqrt(np.mean(e ** 2))
print(f"RMSE of raw measurements (last 20 frames) {rmse(measured[10:] - truth_pos[10:]):.2f} m")
print(f"RMSE of Kalman estimates (last 20 frames) {rmse(estimates[10:] - truth_pos[10:]):.2f} m")
print(f"estimated speed {x[1]:.2f} m per frame")
RMSE of raw measurements (last 20 frames) 1.61 m
RMSE of Kalman estimates (last 20 frames) 0.68 m
estimated speed 1.97 m per frame
หลังผ่านไปไม่กี่เฟรม ตัวกรองให้ตำแหน่งที่คลาดเคลื่อนน้อยกว่าค่าวัดดิบมาก และยังประมาณความเร็วได้ด้วย ซึ่งไม่มีในข้อมูลที่วัด ค่าเริ่มต้นช่วงแรกยังไม่นิ่ง จึงเทียบทั้งสองแบบในช่วง 20 เฟรมหลังเหมือนกัน
กิจกรรมในชั้นเรียน
กิจกรรม: เลือกวิธีมองเห็นให้ตรงงาน
- สำหรับสามงาน คือ นับต้นปาล์ม ประเมินพื้นที่น้ำท่วม และหาผู้ประสบภัยกลางคืน เลือกว่าเป็นงานจำแนก ตรวจจับ หรือแบ่งส่วน และควรใช้กล้องชนิดใด
- ในโค้ดตัวอย่างที่ 1 เพิ่มเงาโดยลดความสว่างของกล่องหนึ่งลงครึ่งหนึ่ง แล้วดูว่าการแยกสีพลาดอย่างไร อภิปรายว่า CNN แก้ปัญหานี้ได้เพราะอะไร
- ลดเกณฑ์ IoU ของ NMS เป็น 0.1 กับกรอบของวัตถุสองชิ้นที่อยู่ติดกัน แล้วอธิบายผลที่ได้
- อ่านหน่วยความรู้ “AI คัดกรองภาพและความเสียหาย” แล้วสรุปว่าทำไมผลจากแบบจำลองควรเป็นรายการช่วยตรวจ ไม่ใช่คำตัดสิน
ข้อผิดพลาดที่พบบ่อย
ระวัง
- ใช้ช่วงสีคงที่ ในงานที่แสงเปลี่ยน
- ใช้การจำแนกภาพ กับงานที่ต้องรู้ตำแหน่งวัตถุหลายชิ้น
- ตั้งเกณฑ์ NMS ต่ำเกินไป จนวัตถุที่อยู่ติดกันหายไป
- ตีความคะแนนความมั่นใจเป็นความน่าจะเป็นที่ถูก โดยไม่ตรวจกับข้อมูลทดสอบ
- ไม่ตรวจใบอนุญาตของแบบจำลองและข้อมูล ก่อนนำไปใช้เชิงพาณิชย์
สรุป
- คอนโวลูชันเลื่อนตัวกรองไปทั่วภาพ การประมวลผลภาพแบบดั้งเดิมอธิบายได้แต่เปราะต่อแสง
- CNN เรียนตัวกรองจากข้อมูลเอง พัฒนาจาก LeNet ถึง ResNet และตัวตรวจจับเช่น YOLO
- จำแนก ตรวจจับ และแบ่งส่วนตอบคำถามต่างกัน ตัวตรวจจับต้องใช้จุดตัดความมั่นใจและ NMS
- ตัวกรองคาลมานผสานการทำนายกับค่าวัด ใช้ติดตามวัตถุและหลอมรวมข้อมูลเซนเซอร์
แบบฝึกตรวจความเข้าใจ
- งาน “ระบุว่าแต่ละพิกเซลเป็นน้ำหรือไม่” คืองานชนิดใด
- กรอบสองกรอบพื้นที่ 50 พิกเซล² เท่ากัน ทับกัน 25 พิกเซล² มี IoU เท่าใด
- ทำไมจึงแยกสีในปริภูมิ HSV แทน BGR
- NMS ทำหน้าที่อะไร
- ตัวกรองคาลมานให้น้ำหนักกับค่าวัดมากขึ้นเมื่อใด
เฉลย
- แบ่งส่วนภาพ (semantic segmentation)
- ส่วนรวม ได้ IoU
- HSV แยกสี (hue) ออกจากความสว่าง จึงกำหนดช่วงสีได้ง่ายกว่าและทนต่อการเปลี่ยนความสว่างมากกว่า
- ตัดกรอบที่ซ้อนกันบนวัตถุเดียว เหลือกรอบที่คะแนนสูงสุด
- เมื่อความไม่แน่นอนของค่าวัด น้อยเมื่อเทียบกับความไม่แน่นอนของการทำนาย ทำให้ค่า ใกล้ 1
สรุปสูตรสำคัญ
| คอนโวลูชันสองมิติ (แบบที่ใช้ใน CNN) | |
| Intersection over Union | |
| ตัวกรองคาลมาน ขั้นปรับปรุง |
แหล่งอ้างอิงหลัก
- Szeliski, R. (2022). Computer vision: Algorithms and applications (2nd ed.). Springer. link
- OpenCV. OpenCV documentation. link
- LeCun, Y., Bottou, L., Bengio, Y., & Haffner, P. (1998). Gradient-based learning applied to document recognition. Proceedings of the IEEE, 86(11), 2278–2324. link
- Krizhevsky, A., Sutskever, I., & Hinton, G. E. (2012). ImageNet classification with deep convolutional neural networks. Advances in Neural Information Processing Systems 25. link
- He, K., Zhang, X., Ren, S., & Sun, J. (2016). Deep residual learning for image recognition. In Proceedings of CVPR 2016 (pp. 770–778). link
- Redmon, J., Divvala, S., Girshick, R., & Farhadi, A. (2016). You only look once: Unified, real-time object detection. In Proceedings of CVPR 2016 (pp. 779–788). link
- Ultralytics. Models supported by Ultralytics (YOLO11, YOLO26). Ultralytics documentation. link
- Kirillov, A., et al. (2023). Segment anything. In Proceedings of ICCV 2023 (pp. 3992–4003). link
- Kalman, R. E. (1960). A new approach to linear filtering and prediction problems. Journal of Basic Engineering, 82(1), 35–45. link
- Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep learning. MIT Press. link
อ่านเพิ่มเติม
ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล
Computer Vision และการต่อยอดสู่ Edge AI
การเรียนรู้เชิงลึกและ CNN
GeoAI และการเผยแพร่แผนที่
AI คัดกรองภาพและความเสียหาย
ในชั้นเรียน / ภาคสนาม
บรรยาย อภิปรายกรณีศึกษา และแก้โจทย์ในชั้นเรียน
หลักฐานการเรียนรู้: ผล quiz และแบบฝึกหัดที่ส่ง