สร้างโมเดลจดจำใบหน้าน้องลิซ่าแบบง่ายด้วย Face-recognition library

Sasiwut Chaiyadecha
3 min readMay 19, 2020

--

สวัสดีครับ วันนี้เรามาทำโมเดลจดจำใบหน้า แบบที่ง่ายกว่าโมเดลของคิมจองอิล จาก 2 ตอนที่ผ่านมากันดีกว่า เพราะตอนที่ทำโมเดลอันนั้นรู้สึกว่าเขียนเหนื่อยจัง ทั้ง ๆ Code ก็ไม่ได้เยอะอะไร

วันนี้ลองหาวิธีสร้างโมเดลจดจำใบหน้าแบบง่าย ๆ ด้วย Library face-recognition (ใช่ครับ ชื่อนี้เลย) ซึ่งการทำงานของ Library ตัวนี้ต้องเรียกใช้งานตัว dlib ที่ติดตั้งแบบ pip install เท่านั้น นะครับ ดังนั้นใครยังไม่ได้ติดตั้ง หรือติดตั้งยังไม่ได้ แนะนำให้กลับไปอ่านตอนที่สอนติดตั้งกันก่อนนะครับ มีทั้งภาษาไทยและภาษาอังกฤษ

ลิซ่า blackpink lisa

Install

วันนี้พระเอกของเราคือ Library face-recognition ครับ ซึ่งตัวนี้ยังไม่มีใคร Complie ผ่าน conda forge ดังนั้นจึงไม่สามารถใช้ conda install ได้ครับ ต้องติดตั้งผ่าน pip install เท่านั้น

pip install face-recognition

เมื่อติดตั้งทุกอย่างพร้อมแล้ว ก็ไปเตรียม Dataset สำหรับการ Training model กันต่อได้เลย

Dataset

วันนี้เรามาใช้รูปใบหน้าของน้อง Lisa Blackpink ในการสอนโมเดลกันดีกว่า เราก็ไปหารูปของน้องมานิดหน่อย เพราะที่ต้องการบอกโมเดลว่า “คนนี้คือ Lisa นะ”

ลิซ่า blackpink lisa
รูปน่ารัก ๆ ของ lisa เอาไว้สอนโมเดล

จากนั้นเราก็อาจจะหารูปคนอื่นอีกนิดหน่อย เพื่อเอาไว้ทดสอบโมเดลของเราว่า มันแยกแยะออกไหมว่าคนนี้คือ Lisa คนนี้ไม่ใช่ Lisa ซึ่งวันนี้ผมขอเอาดาราที่หน้าตาคล้าย ๆ Lisa หน่อยละกัน คล้ายในที่นี้คือ ทรงผมและหน้าตา นะครับ ดังนั้นวันนี้ของเลือกเป็นรูปของคุณพี่ ใหม่ ดาวิกา ตอนที่ตัดผมหน้าม้า และน้อง พลอยไพลิน ที่เคยมีข่าวว่าหน้าคล้าย Lisa ครับ ที่สำคัญคือต้องมีหน้าของ Lisa เพื่อเอาไว้ทดสอบโมเดลด้วยว่า ถ้าเจอ Lisa จริง ๆ แล้วจะ Detect ได้ไหม

ลิซ่า blackpink lisa
ผมตั้งชื่อว่า lisa และ non_lisa เก็บเอาไว้เพื่อทดสอบ

Code

เริ่มจาก Import library ที่จำเป็นต้องใช้งานก่อนเลย ตัวหลักของโมเดลนี้คือ face_recognition ส่วน cv2 เอาไว้จัดการเกี่ยวกับรูปภาพ เช่น การแสดงผล การตีกรอบ ไม่ได้ประมวลผลใด ๆ บน cv2 ครับวันนี้ เพราะว่าอยากใช้ face_recognition ให้เยอะที่สุด ส่วน os เอาไว้จัดการ Directory path บนเครื่องเฉย ๆ

เริ่มแรกเรากำหนด Path ที่เราต้องการใช้ทำงานและ Train model กันก่อน ซึ่งมันก็คือที่ที่เราเก็บ Dataset เอาไว้นั่นเอง จากนั้นก็มีคำสั่ง print() ให้รู้ว่าโปรแกรมเริ่มทำงานเฉย ๆ จะใส่หรือไม่ใส่ก็ได้ แล้วก็สร้าง list ว่าง ๆ เอาไว้ 2 อันเพื่อรอเก็บข้อมูลครับ

ต่อไปเราก็สร้าง for…loop… ขึ้นมา เพื่อที่จะใส่รูปภาพเข้าไปประมวลผล ซึ่งใช้ os.listdir() หาไฟล์ทั้งหมดใน Dataset ของเรา ใส่เข้าไปในตัวแปร n แล้วเปิดมันขึ้นมาด้วย face_recognition.load_image_file() ซึ่งเราต้องต่อ String ด้วย os.path.join()

จากนั้นก็ Encoding รูปภาพด้วย face_recognition.face_encodings() ใส่เข้าไปในตัวแปรที่มารับชื่อว่า endc สังเกตว่าผมใส่ [0] เพราะว่ารูปที่เตรียมมามีเฉพาะหน้าของน้อง Lisa อยู่แล้ว ไม่จำเป็นต้องแยกใบหน้าหลาย ๆ หน้า แล้วเราก็ .append() ตัว endc เก็บไว้ list ว่างที่เราสร้างไว้ตั้งแต่แรกได้เลย ผมใส่ชื่อ ‘lisa’ เข้าไปเลยเพราะว่า รู้อยู่แล้วว่าเป็นใคร

เท่านี้เราก็จะได้ Model ที่เก็บหน้าของ Lisa เอาไว้แล้วครับ อันนี้ขึ้นอยู่กับว่า เราอยากให้มันแม่นแค่ไหน ก็ใส่จำนวน Dataset เพิ่มหรือลดลงก็ได้ครับ เวลาในการรันมันก็แปรผันตามกัน

จากนั้นเราก็เอารูปใครที่เราต้องการทดสอบ ที่เราเตรียมไว้ที่ Test dataset มาลองเปรียบเทียบกับ Model ที่เพิ่ง Train เสร็จดูจากเมื่อกี้นะ เหมือนเดิมครับคำสั่ง print() มีไว้บอกการทำงานของโปรแกรม ไม่ต้องมีก็ได้

ขอข้ามเรื่อง for… loop… ไปเลยละกัน เพราะ Logic การทำงานเหมือนที่อธิบายไว้ข้างบน ที่อยากให้สนใจคือว่า ก่อนที่เราจะ Encoding รูปจาก Test dataset เราต้องหาตำแหน่งให้มัน เราสามารถทำได้ด้วยคำสั่ง face_recognition.face_locations() โดยวันนี้ผมใช้ model = ‘cnn’ จากนั้นก็ไหลต่อไปตาม Logic เดิมได้เลยครับ

เนื่องจากพื้นฐานของ face_recognition มันมาจาก dlib ดังนั้นค่าสีในการทำงานของมันจึงเป็น BGR ไม่ใช่ RGB แบบที่เราคุ้นเคย เราจึงต้องทำการเปลี่ยนค่าสีมันก่อนที่จะเริ่มการทดสอบครับ ซึ่งวันนี้จะลองมาเปลี่ยนด้วย cv2 กัน สามารถใช้ cv2.cvtColor() ได้เลย หรือใครอยากใช้ ตรงนี้ผมไม่แน่ใจว่า (ไม่ได้ลอง) face_recognition.load_image_file() มันรับค่าเข้ามาเป็น Numpy array หรือเปล่า ถ้ารับมาเป็น Numpy array เราสามารถกลับค่าสีด้วย [:,:,::-1] ได้ครับ

มา! for… loop… ต่อไป ตอนนี้เราต้องการตัวแปร 2 ตัว ในการคำนวณคือ ใบหน้าที่ Encoding แล้วกับ Location ของใบหน้า ดังนั้นก็ loop มันไปพร้อมกันได้เลยด้วย zip()

พระเอกมันอยู่ตรงนี้ face_recognition.compare_faces() คือคำสั่งที่เราใช้ในการเปรียบเทียบ ซึ่งเรากำลังเปรียบเทียบรูปจากโมเดลที่ Train เสร็จแล้วคือ faces กับรูปหน้าที่ Encoding แล้วที่อยู่ในรูปตัวแปร f ด้วย Thresholds = 40% ผลที่ออกมาจากการเปรียบเทียบมันจะเป็น True, False ครับ

เราจึงสามารถใช้มัน Check condition ด้วย If statement ได้ครับ ก็คือถ้า True ให้มันทำคำสั่งต่อไป (เดี๋ยวอธิบาย) แต่ถ้า False เมื่อไหร่ ให้ print() บอกว่า ‘Not Lisa’ แล้วบอกชื่อไฟล์ เพื่อให้เรากลับไปดูต้นฉบับได้

มาดูที่ Condition true กันบ้าง… เราจะให้มันไปหยิบชื่อจากโมเดลเราที่ชื่อตัวแปรว่า names ที่เก็บค่าเป็น ‘lisa’ มา จากนั้นเรามาตีกรอบหน้าที่บอกว่าเป็น Lisa ด้วย cv2.rectangle() โดยที่ตำแหน่งมันอยู่ใน Face location ของเรา ในการตีกรอบสี่เหลี่ยม เราต้องการแค่ 2 elements คือ Top left และ Bottom right ดังนั้นเราสามารถระบุตำแหน่งจาก Face location ที่อยู่ในตัวแปร l ได้เลยครับ

  • Top left = (l[3], l[0])
  • Bottom right = (l[1], l[2])

ส่วนที่เหลือจะเป็นค่าสี RGB ทั่วไปที่อยากให้มันตีกรอบ ซึ่งหาจากเว็บนี้ก็ได้ครับ

ต่อมาเราก็จะใส่ชื่อเข้าไปในรูปภาพ ซึ่งตอนนี้มีชื่อเดียวคือ lisa ที่เราเก็บไว้แล้วในตัวแปร check ดังนั้นเราใช้ cv2.putText() ระบุตำแหน่ง สี ฟอนต์ ความหนา ได้เลยครับ

สุดท้ายแล้ว… cv2.imshow() เพื่อให้มันโชว์ผลลัพธ์เป็นหน้าต่างออกมา สามารถใช้ cv2.waitKey() เพื่อรอคำสั่งได้ครับ cv2.destroyWindow() หลังจากรับคำสั่งเราไป จากนั้นเราก็สั่ง cv2.imwrite() เพื่อเซพรูปเก็บไว้ครับ

Result

ใช้ Thresholds = 40%

ทายถูก 1
ทายถูก 2
ทายถูก 3
ทายถูก 4 (รูปที่ 5 นะ)
ทายผิด 1 (รูปนี้คือน้องพลอย แต่โมเดลบอกว่าเป็นลิซ่า แต่หน้าเค้าเหมือนจริง ๆ นะ)

Conclusion

ความถูกต้องของโมเดลมันขึ้นอยู่กับจำนวนรูปที่ใส่เข้าไป Train และ Thresholds ที่เราต้องเอาไว้ แต่… เห็นไหม… แบบนี้ง่ายกว่าโมเดลของรูปคิมจองอิลตั้งเยอะ ไม่ต้องโหลด Model ที่ Trained เสร็จแล้วมาใช้ด้วย แต่ว่าความแม่นยำและการปรับแต่งก็อาจทำได้น้อยกว่า Model ที่ทำแบบละเอียดนะครับ ยังไงลองหัดสร้างแบบง่าย ๆ ขึ้นมาดูก่อนก็ได้ครับ

อัพเดต

Colab notebook ของเนื้อหา Blog ตอนนี้สามารถดูได้จาก Link ด้านบน

--

--

Sasiwut Chaiyadecha
Sasiwut Chaiyadecha

No responses yet