Welcome to DOFBOT-Ultra repository
6. Face effects
Face Effects
Please ensure that the web control program backend process is not running in the background. To close it, refer to the [Get Started Quickly - 2. Access the Terminal] section in [Disable the Auto-Start Web Control Backend Process]. After closing, please restart DofbotUltra!!!
Use dlib to detect 68 facial keypoints and apply beautifying effects on the face: black eye shadow (eye area fill), pink lip gloss (lip area fill), and white eyebrow highlights (eyebrow area fill).
1、Startup
1.1、Startup
Enter the following command to start the program
xxxxxxxxxxros2 run dofbot_mediapipe 06_FaceLandmarks.py

Press the q key in the image window or Ctrl+C in the terminal to exit the program.
On first run, if the
shape_predictor_68_face_landmarks.datmodel file is missing locally, the program will automatically download it (approx. 65MB).
1.2、Source Code
Raspberry Pi source path:
xxxxxxxxxx~/dofbot_ultra_ws/src/dofbot_mediapipe/scripts/06_FaceLandmarks.pyRDK X5 source path:
xxxxxxxxxx~/dofbot_ultra_ws/src/2d/dofbot_mediapipe/scripts/06_FaceLandmarks.pyx#!/usr/bin/env python3# encoding: utf-8import osimport cv2 as cvimport numpy as npimport dlibfrom dofbot_utils.camera import create_camerafrom dofbot_utils.fps import FPS
class FaceLandmarks: def __init__(self, dat_file): self.hog_face_detector = dlib.get_frontal_face_detector() self.dlib_facelandmark = dlib.shape_predictor(dat_file) self.faces = [] self.face_landmarks = None
def get_face(self, frame, draw=True): gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) self.faces = self.hog_face_detector(gray) for face in self.faces: self.face_landmarks = self.dlib_facelandmark(gray, face) if draw: for n in range(68): x = self.face_landmarks.part(n).x y = self.face_landmarks.part(n).y cv.circle(frame, (x, y), 2, (0, 255, 255), 2) cv.putText(frame, str(n), (x, y), cv.FONT_HERSHEY_SIMPLEX, 0.3, (0, 255, 255), 1) return frame
def _get_lmList(self, frame, p1, p2, draw=True): lmList = [] if len(self.faces) == 0 or self.face_landmarks is None: return lmList for n in range(p1, p2): x = self.face_landmarks.part(n).x y = self.face_landmarks.part(n).y lmList.append([x, y]) if draw: next_point = n + 1 if n < p2 - 1 else p1 x2 = self.face_landmarks.part(next_point).x y2 = self.face_landmarks.part(next_point).y cv.line(frame, (x, y), (x2, y2), (0, 255, 0), 1) return lmList
def _get_lipList(self, frame, lipIndexList, draw=True): lmList = [] if len(self.faces) == 0 or self.face_landmarks is None: return lmList for n in range(len(lipIndexList)): x = self.face_landmarks.part(lipIndexList[n]).x y = self.face_landmarks.part(lipIndexList[n]).y lmList.append([x, y]) if draw: next_idx = (n + 1) % len(lipIndexList) x2 = self.face_landmarks.part(lipIndexList[next_idx]).x y2 = self.face_landmarks.part(lipIndexList[next_idx]).y cv.line(frame, (x, y), (x2, y2), (0, 255, 0), 1) return lmList
def prettify_face(self, frame, eye=True, lips=True, eyebrow=True, draw=True): if eye: leftEye = self._get_lmList(frame, 36, 42) rightEye = self._get_lmList(frame, 42, 48) if draw: if leftEye: cv.fillConvexPoly(frame, np.array(leftEye, dtype=np.int32), (0, 0, 0)) if rightEye: cv.fillConvexPoly(frame, np.array(rightEye, dtype=np.int32), (0, 0, 0)) if lips: lipsUpA = self._get_lipList(frame, [51, 52, 53, 54, 64, 63, 62]) lipsUpB = self._get_lipList(frame, [48, 49, 50, 51, 62, 61, 60]) lipsDownA = self._get_lipList(frame, [57, 58, 59, 48, 67, 66]) lipsDownB = self._get_lipList(frame, [54, 55, 56, 57, 66, 65, 64]) if draw: color = (249, 0, 226) for pts in [lipsUpA, lipsUpB, lipsDownA, lipsDownB]: if pts: cv.fillConvexPoly(frame, np.array(pts, dtype=np.int32), color) if eyebrow: leftBrow = self._get_lmList(frame, 17, 22) rightBrow = self._get_lmList(frame, 22, 27) if draw: for pts in [leftBrow, rightBrow]: if pts: cv.fillConvexPoly(frame, np.array(pts, dtype=np.int32), (255, 255, 255)) return frame
DAT_FILENAME = 'shape_predictor_68_face_landmarks.dat'DAT_URL = 'http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2'
def _download_dat(dest_path): import urllib.request import bz2 bz2_path = dest_path + '.bz2' print(f"Downloading {DAT_FILENAME} (~65MB compressed)...") urllib.request.urlretrieve(DAT_URL, bz2_path) print("Decompressing...") with bz2.open(bz2_path, 'rb') as f_in, open(dest_path, 'wb') as f_out: f_out.write(f_in.read()) os.remove(bz2_path) print(f"Saved to {dest_path}")
def find_dat_file(): search_paths = [ os.path.expanduser(f'~/.dlib/{DAT_FILENAME}'), os.path.join(os.path.dirname(__file__), 'file', DAT_FILENAME), os.path.expanduser( f'~/dofbot_ultra_ws/src/dofbot_mediapipe/scripts/file/{DAT_FILENAME}'), os.path.expanduser(f'~/dofbot_ultra/2d/dofbot_mediapipe/scripts/file/{DAT_FILENAME}'), f'/usr/share/dlib/{DAT_FILENAME}', ] for p in search_paths: if os.path.exists(p): return p
default_dir = os.path.expanduser('~/.dlib') os.makedirs(default_dir, exist_ok=True) dest = os.path.join(default_dir, DAT_FILENAME) _download_dat(dest) return dest
def main(): dat_file = find_dat_file() detector = FaceLandmarks(dat_file) fps = FPS()
cap = create_camera() if not cap.isOpened(): raise RuntimeError("Failed to open camera")
try: while cap.isOpened(): ret, frame = cap.read() if not ret: continue
frame = detector.get_face(frame, draw=False) frame = detector.prettify_face(frame, eye=True, lips=True, eyebrow=True, draw=True) fps.update_fps() fps.show_fps(frame) cv.imshow('FaceLandmarks', frame)
if cv.waitKey(1) & 0xFF == ord('q'): break finally: cap.release() cv.destroyAllWindows()
if __name__ == '__main__': main()