Face-detection-and-landmarks.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. # Face Detection
  2. # Import required modules
  3. import cv2
  4. import depthai as dai
  5. import time
  6. import blobconverter
  7. # Define Frame size
  8. FRAME_SIZE = (640, 400)
  9. # Define Detection NN model name and input size
  10. # If you define the blob make sure the FACE_MODEL_NAME and ZOO_TYPE are None
  11. # DET_INPUT_SIZE = (672, 384)
  12. # FACE_MODEL_NAME = None
  13. # ZOO_TYPE = None
  14. # blob_path = "models/face-detection-adas-0001.blob"
  15. DET_INPUT_SIZE = (300, 300)
  16. FACE_MODEL_NAME = "face-detection-retail-0004"
  17. ZOO_TYPE = "depthai"
  18. blob_path = None
  19. # Define Landmark NN model name and input size
  20. # If you define the blob make sure the LANDMARKS_MODEL_NAME and ZOO_TYPE are None
  21. LANDMARKS_INPUT_SIZE = (48, 48)
  22. LANDMARKS_MODEL_NAME = "landmarks-regression-retail-0009"
  23. LANDMARKS_ZOO_TYPE = "intel"
  24. landmarks_blob_path = None
  25. # Start defining a pipeline
  26. pipeline = dai.Pipeline()
  27. # Define a source - RGB camera
  28. cam = pipeline.createColorCamera()
  29. cam.setPreviewSize(FRAME_SIZE[0], FRAME_SIZE[1])
  30. cam.setInterleaved(False)
  31. cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
  32. cam.setBoardSocket(dai.CameraBoardSocket.RGB)
  33. # Convert model from OMZ to blob
  34. if FACE_MODEL_NAME is not None:
  35. blob_path = blobconverter.from_zoo(
  36. name=FACE_MODEL_NAME,
  37. shaves=6,
  38. zoo_type=ZOO_TYPE
  39. )
  40. # Define face detection NN node
  41. faceDetNn = pipeline.createMobileNetDetectionNetwork()
  42. faceDetNn.setConfidenceThreshold(0.75)
  43. faceDetNn.setBlobPath(blob_path)
  44. # Convert model from OMZ to blob
  45. if LANDMARKS_MODEL_NAME is not None:
  46. landmarks_blob_path = blobconverter.from_zoo(
  47. name=LANDMARKS_MODEL_NAME,
  48. shaves=6,
  49. zoo_type=LANDMARKS_ZOO_TYPE
  50. )
  51. # Define landmarks detection NN node
  52. landmarksDetNn = pipeline.createNeuralNetwork()
  53. landmarksDetNn.setBlobPath(landmarks_blob_path)
  54. # Define face detection input config
  55. faceDetManip = pipeline.createImageManip()
  56. faceDetManip.initialConfig.setResize(DET_INPUT_SIZE[0], DET_INPUT_SIZE[1])
  57. faceDetManip.initialConfig.setKeepAspectRatio(False)
  58. # Define landmark detection input config
  59. lndmrksDetManip = pipeline.createImageManip()
  60. # Linking
  61. cam.preview.link(faceDetManip.inputImage)
  62. faceDetManip.out.link(faceDetNn.input)
  63. # Define Script node
  64. # Script node will take the output from the face detection NN as an input and set ImageManipConfig for landmark NN
  65. script = pipeline.create(dai.node.Script)
  66. script.setProcessor(dai.ProcessorType.LEON_CSS)
  67. script.setScriptPath("script.py")
  68. # Linking to Script inputs
  69. cam.preview.link(script.inputs['frame'])
  70. faceDetNn.out.link(script.inputs['face_det_in'])
  71. # Linking Script outputs to landmark ImageManipconfig
  72. script.outputs['manip_cfg'].link(lndmrksDetManip.inputConfig)
  73. script.outputs['manip_img'].link(lndmrksDetManip.inputImage)
  74. # Linking
  75. lndmrksDetManip.out.link(landmarksDetNn.input)
  76. # Create preview output
  77. xOutPreview = pipeline.createXLinkOut()
  78. xOutPreview.setStreamName("preview")
  79. cam.preview.link(xOutPreview.input)
  80. # Create face detection output
  81. xOutDet = pipeline.createXLinkOut()
  82. xOutDet.setStreamName('det_out')
  83. faceDetNn.out.link(xOutDet.input)
  84. # Create cropped face output
  85. xOutCropped = pipeline.createXLinkOut()
  86. xOutCropped.setStreamName('face_out')
  87. lndmrksDetManip.out.link(xOutCropped.input)
  88. # Create landmarks detection output
  89. xOutLndmrks = pipeline.createXLinkOut()
  90. xOutLndmrks.setStreamName('lndmrks_out')
  91. landmarksDetNn.out.link(xOutLndmrks.input)
  92. # Display info on the frame
  93. def display_info(frame, bbox, landmarks, status, status_color, fps):
  94. # Display bounding box
  95. cv2.rectangle(frame, bbox, status_color[status], 2)
  96. # Display landmarks
  97. if landmarks is not None:
  98. for landmark in landmarks:
  99. cv2.circle(frame, landmark, 2, (0, 255, 255), -1)
  100. # Create background for showing details
  101. cv2.rectangle(frame, (5, 5, 175, 100), (50, 0, 0), -1)
  102. # Display authentication status on the frame
  103. cv2.putText(frame, status, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.5, status_color[status])
  104. # Display instructions on the frame
  105. cv2.putText(frame, f'FPS: {fps:.2f}', (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255))
  106. # Frame count
  107. frame_count = 0
  108. # Placeholder fps value
  109. fps = 0
  110. # Used to record the time when we processed last frames
  111. prev_frame_time = 0
  112. # Used to record the time at which we processed current frames
  113. new_frame_time = 0
  114. # Set status colors
  115. status_color = {
  116. 'Face Detected': (0, 255, 0),
  117. 'No Face Detected': (0, 0, 255)
  118. }
  119. # Start pipeline
  120. with dai.Device(pipeline) as device:
  121. # Output queue will be used to get the right camera frames from the outputs defined above
  122. qCam = device.getOutputQueue(name="preview", maxSize=1, blocking=False)
  123. # Output queue will be used to get nn detection data from the video frames.
  124. qDet = device.getOutputQueue(name="det_out", maxSize=1, blocking=False)
  125. # Output queue will be used to get cropped face region.
  126. qFace = device.getOutputQueue(name="face_out", maxSize=1, blocking=False)
  127. # Output queue will be used to get landmarks from the face region.
  128. qLndmrks = device.getOutputQueue(name="lndmrks_out", maxSize=1, blocking=False)
  129. while True:
  130. # Get camera frame
  131. inCam = qCam.get()
  132. frame = inCam.getCvFrame()
  133. bbox = None
  134. inDet = qDet.tryGet()
  135. if inDet is not None:
  136. detections = inDet.detections
  137. # if face detected
  138. if len(detections) is not 0:
  139. detection = detections[0]
  140. # Correct bounding box
  141. xmin = max(0, detection.xmin)
  142. ymin = max(0, detection.ymin)
  143. xmax = min(detection.xmax, 1)
  144. ymax = min(detection.ymax, 1)
  145. # Calculate coordinates
  146. x = int(xmin*FRAME_SIZE[0])
  147. y = int(ymin*FRAME_SIZE[1])
  148. w = int(xmax*FRAME_SIZE[0]-xmin*FRAME_SIZE[0])
  149. h = int(ymax*FRAME_SIZE[1]-ymin*FRAME_SIZE[1])
  150. bbox = (x, y, w, h)
  151. # Show cropped face region
  152. inFace = qFace.tryGet()
  153. if inFace is not None:
  154. face = inFace.getCvFrame()
  155. cv2.imshow("face", face)
  156. landmarks = None
  157. # Get landmarks NN output
  158. inLndmrks = qLndmrks.tryGet()
  159. if inLndmrks is not None:
  160. # Get NN layer names
  161. # print(f"Layer names: {inLndmrks.getAllLayerNames()}")
  162. # Retrieve landmarks from NN output layer
  163. landmarks = inLndmrks.getLayerFp16("95")
  164. x_landmarks = []
  165. y_landmarks = []
  166. # Landmarks in following format [x1,y1,x2,y2,..]
  167. # Extract all x coordinates [x1,x2,..]
  168. for x_point in landmarks[::2]:
  169. # Get x coordinate on original frame
  170. x_point = int((x_point * w) + x)
  171. x_landmarks.append(x_point)
  172. # Extract all y coordinates [y1,y2,..]
  173. for y_point in landmarks[1::2]:
  174. # Get y coordinate on original frame
  175. y_point = int((y_point * h) + y)
  176. y_landmarks.append(y_point)
  177. # Zip x & y coordinates to get a list of points [(x1,y1),(x2,y2),..]
  178. landmarks = list(zip(x_landmarks, y_landmarks))
  179. # Check if a face was detected in the frame
  180. if bbox:
  181. # Face detected
  182. status = 'Face Detected'
  183. else:
  184. # No face detected
  185. status = 'No Face Detected'
  186. # Display info on frame
  187. display_info(frame, bbox, landmarks, status, status_color, fps)
  188. # Calculate average fps
  189. if frame_count % 10 == 0:
  190. # Time when we finish processing last 100 frames
  191. new_frame_time = time.time()
  192. # Fps will be number of frame processed in one second
  193. fps = 1 / ((new_frame_time - prev_frame_time)/10)
  194. prev_frame_time = new_frame_time
  195. # Capture the key pressed
  196. key_pressed = cv2.waitKey(1) & 0xff
  197. # Stop the program if Esc key was pressed
  198. if key_pressed == 27:
  199. break
  200. # Display the final frame
  201. cv2.imshow("Face Cam", frame)
  202. # Increment frame count
  203. frame_count += 1
  204. # Close all output windows
  205. cv2.destroyAllWindows()