Face mask detection #2: ใช้ Face mask model กับงาน Video หรือ Real-time

Original article was published on Deep Learning on Medium


Problem

ก่อนอื่นเลย…​ ปัญหาแรกที่เจอกับงาน Video ก็คือการ Detect ใบหน้า เพราะสิ่งแรกที่เราต้องทำก็ได้ การดึงใบหน้าออกมาในแต่ละ Frame แล้วเอา Frame นั้น ๆ ไปให้โมเดล Predict ว่า Frame นั้นมี Face mask อยู่หรือไม่

พอโจทย์มันเป็นแบบนี้แล้วเนี่ย… เราต้องมาหาตัว Detector ที่ใช้งานได้ดีก่อน ตัวแรกที่ทดลองก็คือ Haarcascade frontalface default พบว่าตัวนี้สามารถทำงานได้รวดเร็วดี ใช้งานก็ง่าย แต่ความแม่นไม่ได้เลย เพราะสิ่งที่เจอก็คือ เมื่อมัน Detect face ได้แล้ว แค่เราหันหน้า หรือเอียงคอนิดหน่อย ตัว Detector ก็ทำงานไม่ได้แล้ว หรือแม้ว่าเราอยู่นิ่ง ๆ แต่พอเอามือยกขึ้นมาปิดหน้า หรือบังบริเวณปาก ตัว Detector ก็หาหน้าไม่เจอ ดังนั้นตัวนี้ขอผ่าน

ตัวต่อมาลองไปใช้งาน Face detector ของ dlib ปรากฎว่าใช้งานได้ดีกว่านิดหน่อย แต่ติดปัญหาเรื่องความเร็ว (อาจเป็นเพราะเครื่องคอมผมมันเก่าเองด้วยแหละ) เลยทำให้ไม่สามารถเอามาใช้งานได้ในครั้งนี้

ตัวสุดท้ายและเป็นตัวที่ใช้กับโมเดลวันนี้คือ faceNet ตัวนี้มีความแม่นยำมากที่สุด สามารถ Detect ใบหน้าเจอแม้ว่าลองยกมือขึ้นมาปิดไว้ หรือการเอียงคอตัวโมเดลยังก็ใช้งานได้ดี เลยเลือกตัวนี้เพื่อใช้ดึงใบหน้าของไฟล์ Video ออกมาในแต่ละ Frame สามารถโหลดได้จากลิงค์ข้างล่าง

Code

Import libraries ทั้งหมดที่ต้องใช้งานกันก่อน ซึ่งต้องใช้ Tensorflow เพื่อโหลดโมเดล เพราะว่าโมเดลเรา Train ด้วย Tensorflow ดังนั้นเครื่อง Local ต้องมีติดตั้งไว้

ต่อมาเป็น face_mask ที่สร้างเป็นตัวแปรเก็บในไว้ List ลำดับก็ตาม Dataset ที่เราทำไว้เมื่อตอนที่แล้วคือ 1.with_mask และ 2.without_mask โดยเก็บไว้ที่ตำแหน่ง 0,1 ตามลำดับ แล้วกำหนด size ให้ตรงตาม Dataset ที่เราทำไว้ที่ขนาด 224 * 224

จากนั้นเราก็โหลดโมเดลที่ใช้ในการ Prediction และโมเดลที่ใช้ในการทำ Face detection รอไว้ได้เลย

ทำการโหลด Video ด้วย OpenCV ซึ่งถ้าอยากใช้ Video จาก Webcam ที่อยู่ในเครื่องเรา สามารถใช้คำสั่ง cv2.VideoCapture(0) ได้ครับ ซึ่งเลขในวงเล็บอาจเปลี่ยนไปในกรณีที่มีกล้องต่อไว้มากกว่า 1 ตัว แต่วันนี้ขอใช้ไฟล์ Video ในการทดสอบโมเดล ดังนั้นจึงประกาศ​ไป Directory ที่เก็บไฟล์ Video ไว้แทน

พอเมื่อมันเป็นไฟล์ Video จึงขอประกาศ​ตัวแปรต่าง ๆ เพื่อ Save ไฟล์ Video หลังจากที่ทดสอบโมเดลไว้เลย

  • frame_width, frame_height เป็นขนาดของไฟล์ที่เราต้องการบันทึก
  • out เป็นตัวแปรที่บอกว่าจะ Save เป็นไฟล์นามสกุลอะไร เก็บไว้ที่ไหน ซึ่งสามารถจัดการด้วยคำสั่ง cv2.VideoWriter() (ตรงนี้อยาก Save เป็น .mp4 นะ แต่มันติดปัญหาเรื่องการ Encoding ใครรู้บอกหน่อยว่าต้องทำยังไง) Format การ Encoding แบบไหน ซึ่งสามารถจัดการได้ด้วย cv2.VideoWriter_fourcc() โดยตัวย่อ 4 ตัว สามารถดู Reference ได้จากลิงค์ข้างล่าง ส่วนเลข 30 คือการกำหนด Framerate ให้กับไฟล์ที่เราต้องการบันทึก

ใช้ while loop ในการเปิดไฟล์ Video หรือการอ่านจาก Webcam โดยใช้ตัวแปรที่เราประกาศ cv2.VideoCapture() มาทำการ .read() เพื่อดึง frame ออกมาทีละ frame จากนั้นใช้ faceNet ในการดึงใบหน้าออกมาจาก frame นั้น ๆ และเพื่อความไม่ Sensitive มากจนเกินไป (มองเห็นอะไรก็เป็นใบหน้าไปหมด) เราจึงกำหนด confidence เอาไว้ที่ 50% ถ้าต่ำกว่านั้นไม่ถือว่าเป็นใบหน้าคน

พอได้ใบหน้าคนออกมาจาก frame แล้ว สิ่งที่เราต้องทำต่อไปมี 2 อย่างคือ

  1. กำหนดพื้นที่ว่านี่คือใบหน้าคนที่โมเดลหาเจอ
  2. เอาใบหน้าที่โมเดลหาเจอไปทดสอบกับอีกโมเดล ดูว่าใบหน้านั้นมีการสวมใส่หน้ากากอยู่หรือไม่

การกำหนดพื้นที่สามารถใช้ Logic เหมือนเดิมได้คือการหา x, y, w, h แล้วก็ทำการตีกรอบให้มัน ส่วนการทดสอบโมเดลหน้ากาก เราควรทำ cv2.resize(), cv2.reshape() และ Normalization ให้เท่ากับ Input ที่เราใช้ Train model จากนั้นใช้ model.predict() โดยครอบไว้ด้วย np.argmax() เพื่อให้ส่งค่ากลับมาเป็น Index

ดังนั้น result ที่ออกมาจึงมีค่าเป็น 0,1 และเมื่อเอาไปใส่ในตัวแปร face_mask ก็จะส่งค่ากลับมาเป็น String ใน List ของ [‘Masked’,’No mask’] เมื่อได้ 2 ข้อตามที่ต้องการแล้ว ก็จัดการตีกรอบพร้อมแสดงผลลัพธ์ด้วย cv2.rectangle() และ cv2.putText()

ต่อมาเป็นเรื่องของการ Display และ Export โดยเราจะทำทั้งการแสดงผลไฟล์เป็นหน้าต่าง Video พร้อม ๆ กับบันทึกไฟล์ที่แสดงผล

Result

จากทั้งหมดที่ทำมา ได้มีการทดลองโมเดลกับคลิปสั้น ๆ 4 คลิป ซึ่งผลก็ถือว่าใช้งานได้ดีทีเดียว ลองไปดูผลลัพธ์ของโมเดลกัน

เสร็จแล้ว! รู้สึกว่าอธิบายเยอะ แต่ดูไปดูมาทั้งหมดแล้ว มันก็ค่อนข้าง Simple นะ เหมาะเป็นแบบฝึกหัดที่ดี