ผู้เขียนบทความ : นายทัศน์เทพ เหมทานนท์ COE#12
1.ความเป็นมา
หนึ่งในวิวัฒนาการด้านเทคนิคพิเศษของภาพยนตร์,เกม,ภาพยนตร์แอนิเมชั่น หรืองานต่างๆที่มีลักษณะใกล้เคียงกัน ที่รุดหน้าไปมากในช่วงทศวรรษที่ผ่านมาคืองาน “โมชั่นแคปเจอร์” หรือเรียกสั้น ๆ ว่า “โมแคป” คือการให้ตัวละครที่สร้างมาจากภาพ CGI ไม่ว่าจะเป็นสัตว์ประหลาด มนุษย์ต่างดาว ได้เคลื่อนไหวอย่างเป็นธรรมชาติกว่าที่ผ่านมา ด้วยการให้ตัวละคร CGI เชื่อมต่อกับนักแสดงที่สวมชุดพิเศษและมีเซนเซอร์ติดอยู่ตามข้อต่อบนร่างกาย ละบันทึกข้อมูลการเคลื่อนไหวไปเชื่อมต่อเข้ากับตัวละคร CGI โดยนับตั้งแต่ช่วงปีค.ศ. 1970 เป็นต้นมาถึงปัจจุบันมีการนำคอมพิวเตอร์กราฟิกส์ คณิตศาสตร์ และวิทยาศาสตร์เข้ามาช่วยในการสร้างภาพเคลื่อนไหว เป็นวิธีที่สามารถสร้างภาพที่สมจริงขึ้น มีการใช้คอมพิวเตอร์กราฟิกส์ช่วยสร้างภาพที่อยู่ในจินตการของคนเรานั้น ออกมาให้เห็นได้อย่างสวยงามและสมจริง
2.วัตถุประสงค์
- เพื่อพัฒนาระบบให้สามารถควบคุมการเคลื่อนไหวของตัว CGI ให้มีประสิทธิภาพมากขึ้น
- เพื่อเป็นการต่อยอดให้ตัวระบบมีการนำไปพัฒนาในการทำงานในอนาคต
3.ขอบเขต
- ระบบสามารถรองรับใบหน้าได้อย่างไม่มีข้อผิดพลาด
- ตัวระบบสามารถแสดงการเคลื่อนไหวที่ถูกต้องและแม่นยำ
- สามารถที่จะนำตัวระบบไปใช่ในการสื่อสารกับผู้อื่นได้
4.ประโยชน์ที่สามารถได้รับ
- สามารถเป็นการสื่อสารรูปแบบใหม่ที่จะเพึ่มสีสันในการสนทนาได้
- เพื่อนำไปต่อยอดในการทำงานในด้านภาพยนตร์,เกม,ภาพยนตร์แอนิเมชั่น หรืองานต่างๆที่มีลักษณะใกล้เคียงกัน
- ทำให้มีความรู้ในการทำโมชั่นแคปเจอร์ และ Face Landmarks
5.ความรู้ที่เกี่ยวข้อง
- ความรู้ในเขียนภาษา Python
ภาษาโปรแกรม Python คือภาษาโปรแกรมคอมพิวเตอร์ระดับสูง โดยถูกออกแบบมาให้เป็นภาษาสคริปต์ที่อ่านง่าย โดยตัดความซับซ้อนของโครงสร้างและไวยกรณ์ของภาษาออกไป ในส่วนของการแปลงชุดคำสั่งที่เราเขียนให้เป็นภาษาเครื่องPython มีการทำงานแบบ Interpreter คือเป็นการแปลชุดคำสั่งทีละบรรทัด เพื่อป้อนเข้าสู่หน่วยประมวลผลให้คอมพิวเตอร์ทำงานตามที่เราต้องการ
- ความรู้ในการออกแบบโมเดว CGI ด้วยโปรแกรม Blender
Blender คือ ซอฟต์แวร์โอเพนซอร์ส สำหรับสร้างโมเดล 3 มิติ,เรนเดอร์และทำแอนิเมชัน เป็นโปรแกรมที่มีขนาดไฟล์ที่เล็ก สามารถทำงานได้บนระบบปฏิบัติการหลายรูปแบบ มีความสามารถในการทำคาแรคเตอร์และโมเดล ได้เทียบเท่ากับโปรแกรม 3 มิติระดับสูง
- การทํา Face Landmarks ด้วย OpenCV
OpenCV (Open source Computer Vision) เป็นไลบรารีฟังก์ชันการเขียนโปรแกรม (Library of Programming Functions) โดยส่วนใหญ่จะมุ่งเป้าไปที่การแสดงผลด้วยคอมพิวเตอร์แบบเรียลไทม์ (Real-Time Computer Vision) เดิมทีแล้วถูกพัฒนาโดย Intel แต่ภายหลังได้รับการสนับสนุนโดย Willow Garage ตามมาด้วย Itseez (ซึ่งต่อมาถูกเข้าซื้อโดย Intel) OpenCV เป็นไลบรารีแบบข้ามแพลตฟอร์ม (Cross-Platform) และใช้งานได้ฟรีภายใต้ลิขสิทธิ์ของ BSD แบบโอเพ่นซอร์ส (Open-Source BSD License) - การทำโมชั่นแคปเจอร์
โมชั่น แคปเจอร์ เป็นอีกหนึ่งเทคนิคในการสร้างสรรงานเกม , ภาพยนตร์แอนิเมชั่น หรืองานต่างๆที่มีลักษณะใกล้เคียงกัน โดยใช้คนหรือสิ่งมีชีวิตเข้ามามีส่วนร่วมในการสร้างเกม เพื่อให้การเคลื่อนไหวของตัวละครที่เกิดขึ้นในเกมหรือแอนิเมชั่นมีความสมจริงมากที่สุด
6.ผลการดำเนินงาน
-ระยะแรก
ได้ทำการศึกษาเกี่ยวกับโปรแกรมที่ไว้สำหรับทำ โมชั่นแคปเจอร์ เพื่อไว้สำหรับในการทำ Face Recognition ซึ่งโปรแกรมที่ได้ศึกษาคือ โปรแกรม Blender ที่เป็นโปรแกรมฟรีที่สามารถโหลดได้ผ่านซอฟแวร์ steam
จากนั้นก็ได้ทำการศึกษาตัว Face Landmarks ที่จะทำงานโดยใช่ opencv ที่เป็น module บน python ในการที่จะสามารถรับค่าใบหน้าจากตัวกล้องเพื่อที่จะมาแสดงผลผ่านตัวโมเดวที่ได้ทำไว้
-ระยะที่สอง
ได้เรึ่มศึกษาการทำงานของตัวโค้ดของโปรแกรม โดยจะมีอยู่ด้วยกันทั้งหมดสองตัวคือ ส่วนของการสร้าง button เพื่อไว้สำหรับเปิดการทำงานของตัวกล้องในโปรแกรม Blender โดยมีรายระเอียดดังนี้
class OBJECT_MT_OpenCVPanel(bpy.types.WorkSpaceTool):
"""Creates a Panel in the Object properties window"""
bl_label = "OpenCV Animation"
bl_space_type = 'VIEW_3D'
bl_context_mode='OBJECT'
bl_idname = "ui_plus.opencv"
bl_options = {'REGISTER'}
bl_icon = "ops.generic.select_circle"
โค้ตส่วนนี้จะแสดงการตั้งค่าการแสดงของตัวเครื่องมือ button บนโปรแกรม Blender ที่จะเชื่อมไปยังตัวกล้องของเรา
def draw_settings(context, layout, tool):
row = layout.row()
op = row.operator("wm.opencv_operator", text="Capture", icon="OUTLINER_OB_CAMERA")
ในโค้ดนี้ จะเป็นการสร้างตัวปุ่มและกำหนดค่าให้เชื่อมการทำงานไปยังโค้ด opencv_operator
ส่วนที่สองคือ การทำงานของกล้องกับโมเดวที่กำหนดไว้ ซึ่งจะต้องมีการกำหนดจุดมาตร์ตามใบหน้า การเก็บค่าจากตัวกล้องเพื่อส่งค่าไปให้ตัวโมเดว และหลักการทำงานของกล้อง โดยมีรายละเอียดดังนี้
class OpenCVAnimOperator(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "wm.opencv_operator"
bl_label = "OpenCV Animation Operator"
# Set paths to trained models downloaded above เช็ดไฟต์โมดูลจับการเคลื่อนไหวที่โหลดไว้
face_detect_path = cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
#landmark_model_path = "./data/lbfmodel.yaml" #Linux
#landmark_model_path = "./data/lbfmodel.yaml" #Mac
landmark_model_path = "C:\\Users\\acer\\OneDrive\\Documents\\GSOC2017-master\\data\\lbfmodel.yaml" #Windows
# Load models ใช่งานโมดูล
fm = cv2.face.createFacemarkLBF()
fm.loadModel(landmark_model_path)
cas = cv2.CascadeClassifier(face_detect_path)
โค้ตนี้จะอธิบายถึงการกำหนดตัวโมดูนที่เราจะใช่ และการเชื่อมกับโค้ดปุ่มตัวแรก โดยบรรทัดแรกจะเป็นการเชื่อมกันกับโค้ดปุ่มตัวแรกที่ได้กล่าวไว้ ส่วนบรรทัดที่สองจะเป็นเรียกใช่โมดูลในการตรวจจับใบหน้าขึ้นมาใช่งาน
# 3D model points. จุดบนโมเดว 3d
model_points = numpy.array([
(0.0, 0.0, 0.0), # Nose tip
(0.0, -330.0, -65.0), # Chin
(-225.0, 170.0, -135.0), # Left eye left corner
(225.0, 170.0, -135.0), # Right eye right corne
(-150.0, -150.0, -125.0), # Left Mouth corner
(150.0, -150.0, -125.0) # Right mouth corner
], dtype = numpy.float32)
ส่วนนี้จะเป็นการกำหนดจุดต่างๆที่กำหนดไว้บนตัวโมเดวมากำหนดไว้ในโค้ด เพื่อที่จะไปเชื่อมกับตัวกล้องในการจับใบหน้า
# Keeps a moving average of given length เก็บค่าเฉลี่ยการเคลื่อนไหว
def smooth_value(self, name, length, value):
if not hasattr(self, 'smooth'):
self.smooth = {}
if not name in self.smooth:
self.smooth[name] = numpy.array([value])
else:
self.smooth[name] = numpy.insert(arr=self.smooth[name], obj=0, values=value)
if self.smooth[name].size > length:
self.smooth[name] = numpy.delete(self.smooth[name], self.smooth[name].size-1, 0)
sum = 0
for val in self.smooth[name]:
sum += val
return sum / self.smooth[name].size
# Keeps min and max values, then returns the value in a range 0 - 1 เก็บค่าต่ำสุดและสูงสุดของการขยับและส่งค่าไป
def get_range(self, name, value):
if not hasattr(self, 'range'):
self.range = {}
if not name in self.range:
self.range[name] = numpy.array([value, value])
else:
self.range[name] = numpy.array([min(value, self.range[name][0]), max(value, self.range[name][1])] )
val_range = self.range[name][1] - self.range[name][0]
if val_range != 0:
return (value - self.range[name][0]) / val_range
else:
return 0.0
โด้ดนี้จะแสดงการป้อนค่าให้กล้องนั้นสามารถเก็บค่าของวัตถุที่ตรวจพบแล้วนำไปประมวลค่าให้กับตัวโมเดว
# head rotation จุดเคลื่อนไหวตำแหน่งหัว
bones["head_fk"].rotation_euler[0] = self.smooth_value("h_x", 5, (self.rotation_vector[0] - self.first_angle[0])) / 1 # Up/Down
bones["head_fk"].rotation_euler[2] = self.smooth_value("h_y", 5, -(self.rotation_vector[1] - self.first_angle[1])) / 1.5 # Rotate
bones["head_fk"].rotation_euler[1] = self.smooth_value("h_z", 5, (self.rotation_vector[2] - self.first_angle[2])) / 1.3 # Left/Right
bones["head_fk"].keyframe_insert(data_path="rotation_euler", index=-1)
# mouth position จุดเคลื่อนไหวตำแหน่งปาก
bones["mouth_ctrl"].location[2] = self.smooth_value("m_h", 2, -self.get_range("mouth_height", numpy.linalg.norm(shape[62] - shape[66])) * 0.06 )
bones["mouth_ctrl"].location[0] = self.smooth_value("m_w", 2, (self.get_range("mouth_width", numpy.linalg.norm(shape[54] - shape[48])) - 0.5) * -0.04)
bones["mouth_ctrl"].keyframe_insert(data_path="location", index=-1)
#eyebrows จุดเคลื่อนไหวตำแหน่งคิ้ว
bones["brow_ctrl_L"].location[2] = self.smooth_value("b_l", 3, (self.get_range("brow_left", numpy.linalg.norm(shape[19] - shape[27])) -0.5) * 0.04)
bones["brow_ctrl_R"].location[2] = self.smooth_value("b_r", 3, (self.get_range("brow_right", numpy.linalg.norm(shape[24] - shape[27])) -0.5) * 0.04)
bones["brow_ctrl_L"].keyframe_insert(data_path="location", index=2)
bones["brow_ctrl_R"].keyframe_insert(data_path="location", index=2)
# eyelids จุดเคลื่อนไหวตำแหน่งตา
l_open = self.smooth_value("e_l", 2, self.get_range("l_open", -numpy.linalg.norm(shape[48] - shape[44])) )
r_open = self.smooth_value("e_r", 2, self.get_range("r_open", -numpy.linalg.norm(shape[41] - shape[39])) )
eyes_open = (l_open + r_open) / 2.0 # looks weird if both eyes aren't the same...
bones["eyelid_up_ctrl_R"].location[2] = -eyes_open * 0.025 + 0.005
bones["eyelid_low_ctrl_R"].location[2] = eyes_open * 0.025 - 0.005
bones["eyelid_up_ctrl_L"].location[2] = -eyes_open * 0.025 + 0.005
bones["eyelid_low_ctrl_L"].location[2] = eyes_open * 0.025 - 0.005
โด้ดส่วนนี้จะเป็นโค้ดที่ทำไว้สำหรับการ กำหนดจุดเคลื่อนไหวต่างๆของตัวโมเดว ทั้งจุดหมุนที่หัว ตา ปาก คิ้ว เปลือกตา เพื่อให้การขยับของโมเดวตรงกับจุดที่กำหนดไว้กับที่กล้องจับได้
แผนผังการทำงานของระบบ
—— วิดีโอแนะนำตัวระบบ——
7.สรุปผลและข้อเสนอแนะ
จากการดำเนินงานทั้งหมดที่กล่าวมานั้น หลังจากได้ทำการทดสอบเรียนร้อยแล้วตัวโปรเจทได้มีผลลัทธ์เป็นไปอย่างที่หน้าพอใจ โดยสรุปแล้วการทำงานส่วนใหญ่ของระบบนี้จะต้องพึ่งปัจจัยหลักกับกล้องเป็นหลัก เพราะถ้ากล้องตัวรับผลนั้นไม่มีความระเอียดที่ไม่สูงพอ จะมีปัญหาในด้านการประมวณผลได้
ข้อเสนอแนะ
1. ควรหากล้องที่มีความละเอียดที่สูงในการดำเนินผลการทำงาน
2. การจะต่อยอดโปรเจทนี้ให้ดีขึ้นต้องใช่งบประมาณในการที่จะชื้ออุปกรณ์ในการทำที่มากขึ้น
8.ข้อมูลอ้างอิง
—-วิดีโอในการศึกษา—-
-ต้นแบบโปรเจก-
BY: Python With Joe Controlling a 3D character Using Python and Blender Face Rig w/ Source Code – YouTube
-การติดตั้ง library Openvc-
BY : Egkarin Watanyulertsakul Raspberry Pi EP.34 การติดตั้ง OpenCV เพื่อจดจำใบหน้า – YouTube
-การติดตั้ง Face Landmarks Model-
BY : Nicholas Renotte (232) Real Time AI Face Landmark Detection in 20 Minutes with Tensorflow.JS and React – YouTube
-ศึกษาการใช่โปรแกรม Blender-
BY : 3DPhotostockThailand (232) สอนโปรแกรม Blender EP05 เรียนรู้คำสั่งโมเดลพื้นฐาน – YouTube
—-เว็ปในการศึกษา—-
-ต้นแบบโปรเจก-
GitHub – joeVenner/control-3d-character-using-python: Controlling 3D character’s Face Movements using OpenCV and pyhton
-สอนโปรแกรม Blender-
ใครอยากใช้ Blender เป็น ไม่เสียตังเชิญทางนี้ !! (dynamicwork.net)
-การทำงานของ Openvc-
opencv-python เบื้องต้น บทที่ ๑: บทนำ :: บล็อกของ phyblas ;囧; いつか見えた空 ~ φυβλαςのブログ (hinaboshi.com)
-การทำงานของ Facial landmarks Model-
Facial landmarks with dlib, OpenCV, and Python – PyImageSearch
โปรเจทนายเจ๋งมาก
ตอบเองครับ
What
อิหยังบ่นี้555
สุดยอดเลยครับ ได้รับประโยชน์มากมาย
555