Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. from MultiMsgSync import TwoStageHostSeqSync
  2. import blobconverter
  3. import cv2
  4. import depthai as dai
  5. import numpy as np
  6. from pathlib import Path
  7.  
  8. def frame_norm(frame, bbox):
  9. normVals = np.full(len(bbox), frame.shape[0])
  10. normVals[::2] = frame.shape[1]
  11. return (np.clip(np.array(bbox), 0, 1) * normVals).astype(int)
  12.  
  13. def create_pipeline(stereo):
  14. pipeline = dai.Pipeline()
  15.  
  16. print("Creating Color Camera...")
  17. cam = pipeline.create(dai.node.ColorCamera)
  18. cam.setPreviewSize(1072, 1072)
  19. cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
  20. cam.setInterleaved(False)
  21. cam.setBoardSocket(dai.CameraBoardSocket.RGB)
  22.  
  23. # Workaround: remove in 2.18, use `cam.setPreviewNumFramesPool(10)`
  24. # This manip uses 15*3.5 MB => 52 MB of RAM.
  25. copy_manip = pipeline.create(dai.node.ImageManip)
  26. copy_manip.setNumFramesPool(15)
  27. copy_manip.setMaxOutputFrameSize(1072 * 1072 * 3)
  28. cam.preview.link(copy_manip.inputImage)
  29.  
  30. cam_xout = pipeline.create(dai.node.XLinkOut)
  31. cam_xout.setStreamName("color")
  32. copy_manip.out.link(cam_xout.input)
  33.  
  34. # ImageManip will resize the frame before sending it to the Face detection NN node
  35. face_det_manip = pipeline.create(dai.node.ImageManip)
  36. face_det_manip.initialConfig.setResize(300, 300)
  37. face_det_manip.initialConfig.setFrameType(dai.RawImgFrame.Type.RGB888p)
  38. copy_manip.out.link(face_det_manip.inputImage)
  39.  
  40. if stereo:
  41. monoLeft = pipeline.create(dai.node.MonoCamera)
  42. monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
  43. monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
  44.  
  45. monoRight = pipeline.create(dai.node.MonoCamera)
  46. monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
  47. monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
  48.  
  49. stereo = pipeline.create(dai.node.StereoDepth)
  50. stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
  51. stereo.setDepthAlign(dai.CameraBoardSocket.RGB)
  52. monoLeft.out.link(stereo.left)
  53. monoRight.out.link(stereo.right)
  54.  
  55. # Spatial Detection network if OAK-D
  56. print("OAK-D detected, app will display spatial coordiantes")
  57. face_det_nn = pipeline.create(dai.node.MobileNetSpatialDetectionNetwork)
  58. face_det_nn.setBoundingBoxScaleFactor(0.8)
  59. face_det_nn.setDepthLowerThreshold(100)
  60. face_det_nn.setDepthUpperThreshold(5000)
  61. stereo.depth.link(face_det_nn.inputDepth)
  62. else: # Detection network if OAK-1
  63. print("OAK-1 detected, app won't display spatial coordiantes")
  64. face_det_nn = pipeline.create(dai.node.MobileNetDetectionNetwork)
  65.  
  66. face_det_nn.setConfidenceThreshold(0.5)
  67. face_det_nn.setBlobPath(blobconverter.from_zoo(name="face-detection-retail-0004", shaves=6))
  68. face_det_nn.input.setQueueSize(1)
  69. face_det_manip.out.link(face_det_nn.input)
  70.  
  71. # Send face detections to the host (for bounding boxes)
  72. face_det_xout = pipeline.create(dai.node.XLinkOut)
  73. face_det_xout.setStreamName("detection")
  74. face_det_nn.out.link(face_det_xout.input)
  75.  
  76. # Script node will take the output from the face detection NN as an input and set ImageManipConfig
  77. # to the 'recognition_manip' to crop the initial frame
  78. image_manip_script = pipeline.create(dai.node.Script)
  79. face_det_nn.out.link(image_manip_script.inputs['face_det_in'])
  80.  
  81. # Remove in 2.18 and use `imgFrame.getSequenceNum()` in Script node
  82. face_det_nn.passthrough.link(image_manip_script.inputs['passthrough'])
  83.  
  84. copy_manip.out.link(image_manip_script.inputs['preview'])
  85.  
  86. image_manip_script.setScript("""
  87. import time
  88. msgs = dict()
  89. def add_msg(msg, name, seq = None):
  90. global msgs
  91. if seq is None:
  92. seq = msg.getSequenceNum()
  93. seq = str(seq)
  94. # node.warn(f"New msg {name}, seq {seq}")
  95. # Each seq number has it's own dict of msgs
  96. if seq not in msgs:
  97. msgs[seq] = dict()
  98. msgs[seq][name] = msg
  99. # To avoid freezing (not necessary for this ObjDet model)
  100. if 15 < len(msgs):
  101. node.warn(f"Removing first element! len {len(msgs)}")
  102. msgs.popitem() # Remove first element
  103. def get_msgs():
  104. global msgs
  105. seq_remove = [] # Arr of sequence numbers to get deleted
  106. for seq, syncMsgs in msgs.items():
  107. seq_remove.append(seq) # Will get removed from dict if we find synced msgs pair
  108. # node.warn(f"Checking sync {seq}")
  109. # Check if we have both detections and color frame with this sequence number
  110. if len(syncMsgs) == 2: # 1 frame, 1 detection
  111. for rm in seq_remove:
  112. del msgs[rm]
  113. # node.warn(f"synced {seq}. Removed older sync values. len {len(msgs)}")
  114. return syncMsgs # Returned synced msgs
  115. return None
  116. def correct_bb(bb):
  117. if bb.xmin < 0: bb.xmin = 0.001
  118. if bb.ymin < 0: bb.ymin = 0.001
  119. if bb.xmax > 1: bb.xmax = 0.999
  120. if bb.ymax > 1: bb.ymax = 0.999
  121. return bb
  122. while True:
  123. time.sleep(0.001) # Avoid lazy looping
  124. preview = node.io['preview'].tryGet()
  125. if preview is not None:
  126. add_msg(preview, 'preview')
  127. face_dets = node.io['face_det_in'].tryGet()
  128. if face_dets is not None:
  129. # TODO: in 2.18.0.0 use face_dets.getSequenceNum()
  130. passthrough = node.io['passthrough'].get()
  131. seq = passthrough.getSequenceNum()
  132. add_msg(face_dets, 'dets', seq)
  133. sync_msgs = get_msgs()
  134. if sync_msgs is not None:
  135. img = sync_msgs['preview']
  136. dets = sync_msgs['dets']
  137. for i, det in enumerate(dets.detections):
  138. cfg = ImageManipConfig()
  139. correct_bb(det)
  140. cfg.setCropRect(det.xmin, det.ymin, det.xmax, det.ymax)
  141. # node.warn(f"Sending {i + 1}. det. Seq {seq}. Det {det.xmin}, {det.ymin}, {det.xmax}, {det.ymax}")
  142. cfg.setResize(200, 200)
  143. cfg.setKeepAspectRatio(False)
  144. node.io['manip_cfg'].send(cfg)
  145. node.io['manip_img'].send(img)
  146. """)
  147.  
  148. recognition_manip = pipeline.create(dai.node.ImageManip)
  149. recognition_manip.initialConfig.setResize(200, 200)
  150. recognition_manip.inputConfig.setWaitForMessage(True)
  151. image_manip_script.outputs['manip_cfg'].link(recognition_manip.inputConfig)
  152. image_manip_script.outputs['manip_img'].link(recognition_manip.inputImage)
  153.  
  154. # Second stange recognition NN
  155. print("Creating recognition Neural Network...")
  156. recognition_nn = pipeline.create(dai.node.NeuralNetwork)
  157. #recognition_nn.setBlobPath(blobconverter.from_zoo(name="age-gender-recognition-retail-0013", shaves=6))
  158. recognition_nn.setBlobPath(str(Path("model.blob").resolve().absolute()))
  159. recognition_manip.out.link(recognition_nn.input)
  160.  
  161. recognition_xout = pipeline.create(dai.node.XLinkOut)
  162. recognition_xout.setStreamName("recognition")
  163. recognition_nn.out.link(recognition_xout.input)
  164.  
  165. return pipeline
  166.  
  167. with dai.Device() as device:
  168. stereo = 1 < len(device.getConnectedCameras())
  169. device.startPipeline(create_pipeline(stereo))
  170.  
  171. sync = TwoStageHostSeqSync()
  172. queues = {}
  173. # Create output queues
  174. for name in ["color", "detection", "recognition"]:
  175. queues[name] = device.getOutputQueue(name)
  176.  
  177. while True:
  178. for name, q in queues.items():
  179. # Add all msgs (color frames, object detections and recognitions) to the Sync class.
  180. if q.has():
  181. sync.add_msg(q.get(), name)
  182.  
  183. msgs = sync.get_msgs()
  184. if msgs is not None:
  185. frame = msgs["color"].getCvFrame()
  186. detections = msgs["detection"].detections
  187. recognitions = msgs["recognition"]
  188.  
  189. for i, detection in enumerate(detections):
  190. bbox = frame_norm(frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax))
  191.  
  192. # Decoding of recognition results
  193. rec = recognitions[i]
  194. age = np.array(rec.getLayerFp16('age'))
  195. # gender = np.squeeze(np.array(rec.getLayerFp16('prob')))
  196. # gender_str = "female" if gender[0] > gender[1] else "male"
  197.  
  198. cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (10, 245, 10), 2)
  199. y = (bbox[1] + bbox[3]) // 2
  200. cv2.putText(frame, str(age), (bbox[0], y), cv2.FONT_HERSHEY_TRIPLEX, 1.5, (0, 0, 0), 8)
  201. cv2.putText(frame, str(age), (bbox[0], y), cv2.FONT_HERSHEY_TRIPLEX, 1.5, (255, 255, 255), 2)
  202. # cv2.putText(frame, gender_str, (bbox[0], y + 30), cv2.FONT_HERSHEY_TRIPLEX, 1.5, (0, 0, 0), 8)
  203. # cv2.putText(frame, gender_str, (bbox[0], y + 30), cv2.FONT_HERSHEY_TRIPLEX, 1.5, (255, 255, 255), 2)
  204. # if stereo:
  205. # # You could also get detection.spatialCoordinates.x and detection.spatialCoordinates.y coordinates
  206. # coords = "Z: {:.2f} m".format(detection.spatialCoordinates.z/1000)
  207. # cv2.putText(frame, coords, (bbox[0], y + 60), cv2.FONT_HERSHEY_TRIPLEX, 1, (0, 0, 0), 8)
  208. # cv2.putText(frame, coords, (bbox[0], y + 60), cv2.FONT_HERSHEY_TRIPLEX, 1, (255, 255, 255), 2)
  209.  
  210. cv2.imshow("Camera", frame)
  211. if cv2.waitKey(1) == ord('q'):
  212. break