demo.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. import argparse
  2. import time
  3. import cv2
  4. import numpy as np
  5. def main(video, device):
  6. # init dict to track time for every stage at each iteration
  7. timers = {
  8. "full pipeline": [],
  9. "reading": [],
  10. "pre-process": [],
  11. "optical flow": [],
  12. "post-process": [],
  13. }
  14. # init video capture with video
  15. cap = cv2.VideoCapture(video)
  16. # get default video FPS
  17. fps = cap.get(cv2.CAP_PROP_FPS)
  18. # get total number of video frames
  19. num_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
  20. # read the first frame
  21. ret, previous_frame = cap.read()
  22. if device == "cpu":
  23. # proceed if frame reading was successful
  24. if ret:
  25. # resize frame
  26. frame = cv2.resize(previous_frame, (960, 540))
  27. # convert to gray
  28. previous_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  29. # create hsv output for optical flow
  30. hsv = np.zeros_like(frame, np.float32)
  31. # set saturation to 1
  32. hsv[..., 1] = 1.0
  33. while True:
  34. # start full pipeline timer
  35. start_full_time = time.time()
  36. # start reading timer
  37. start_read_time = time.time()
  38. # capture frame-by-frame
  39. ret, frame = cap.read()
  40. # end reading timer
  41. end_read_time = time.time()
  42. # add elapsed iteration time
  43. timers["reading"].append(end_read_time - start_read_time)
  44. # if frame reading was not successful, break
  45. if not ret:
  46. break
  47. # start pre-process timer
  48. start_pre_time = time.time()
  49. # resize frame
  50. frame = cv2.resize(frame, (960, 540))
  51. # convert to gray
  52. current_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  53. # end pre-process timer
  54. end_pre_time = time.time()
  55. # add elapsed iteration time
  56. timers["pre-process"].append(end_pre_time - start_pre_time)
  57. # start optical flow timer
  58. start_of = time.time()
  59. # calculate optical flow
  60. flow = cv2.calcOpticalFlowFarneback(
  61. previous_frame, current_frame, None, 0.5, 5, 15, 3, 5, 1.2, 0,
  62. )
  63. # end of timer
  64. end_of = time.time()
  65. # add elapsed iteration time
  66. timers["optical flow"].append(end_of - start_of)
  67. # start post-process timer
  68. start_post_time = time.time()
  69. # convert from cartesian to polar coordinates to get magnitude and angle
  70. magnitude, angle = cv2.cartToPolar(
  71. flow[..., 0], flow[..., 1], angleInDegrees=True,
  72. )
  73. # set hue according to the angle of optical flow
  74. hsv[..., 0] = angle * ((1 / 360.0) * (180 / 255.0))
  75. # set value according to the normalized magnitude of optical flow
  76. hsv[..., 2] = cv2.normalize(
  77. magnitude, None, 0.0, 1.0, cv2.NORM_MINMAX, -1,
  78. )
  79. # multiply each pixel value to 255
  80. hsv_8u = np.uint8(hsv * 255.0)
  81. # convert hsv to bgr
  82. bgr = cv2.cvtColor(hsv_8u, cv2.COLOR_HSV2BGR)
  83. # update previous_frame value
  84. previous_frame = current_frame
  85. # end post-process timer
  86. end_post_time = time.time()
  87. # add elapsed iteration time
  88. timers["post-process"].append(end_post_time - start_post_time)
  89. # end full pipeline timer
  90. end_full_time = time.time()
  91. # add elapsed iteration time
  92. timers["full pipeline"].append(end_full_time - start_full_time)
  93. # visualization
  94. cv2.imshow("original", frame)
  95. cv2.imshow("result", bgr)
  96. k = cv2.waitKey(1)
  97. if k == 27:
  98. break
  99. else:
  100. # proceed if frame reading was successful
  101. if ret:
  102. # resize frame
  103. frame = cv2.resize(previous_frame, (960, 540))
  104. # upload resized frame to GPU
  105. gpu_frame = cv2.cuda_GpuMat()
  106. gpu_frame.upload(frame)
  107. # convert to gray
  108. previous_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  109. # upload pre-processed frame to GPU
  110. gpu_previous = cv2.cuda_GpuMat()
  111. gpu_previous.upload(previous_frame)
  112. # create gpu_hsv output for optical flow
  113. gpu_hsv = cv2.cuda_GpuMat(gpu_frame.size(), cv2.CV_32FC3)
  114. gpu_hsv_8u = cv2.cuda_GpuMat(gpu_frame.size(), cv2.CV_8UC3)
  115. gpu_h = cv2.cuda_GpuMat(gpu_frame.size(), cv2.CV_32FC1)
  116. gpu_s = cv2.cuda_GpuMat(gpu_frame.size(), cv2.CV_32FC1)
  117. gpu_v = cv2.cuda_GpuMat(gpu_frame.size(), cv2.CV_32FC1)
  118. # set saturation to 1
  119. gpu_s.upload(np.ones_like(previous_frame, np.float32))
  120. while True:
  121. # start full pipeline timer
  122. start_full_time = time.time()
  123. # start reading timer
  124. start_read_time = time.time()
  125. # capture frame-by-frame
  126. ret, frame = cap.read()
  127. # upload frame to GPU
  128. gpu_frame.upload(frame)
  129. # end reading timer
  130. end_read_time = time.time()
  131. # add elapsed iteration time
  132. timers["reading"].append(end_read_time - start_read_time)
  133. # if frame reading was not successful, break
  134. if not ret:
  135. break
  136. # start pre-process timer
  137. start_pre_time = time.time()
  138. # resize frame
  139. gpu_frame = cv2.cuda.resize(gpu_frame, (960, 540))
  140. # convert to gray
  141. gpu_current = cv2.cuda.cvtColor(gpu_frame, cv2.COLOR_BGR2GRAY)
  142. # end pre-process timer
  143. end_pre_time = time.time()
  144. # add elapsed iteration time
  145. timers["pre-process"].append(end_pre_time - start_pre_time)
  146. # start optical flow timer
  147. start_of = time.time()
  148. # create optical flow instance
  149. gpu_flow = cv2.cuda_FarnebackOpticalFlow.create(
  150. 5, 0.5, False, 15, 3, 5, 1.2, 0,
  151. )
  152. # calculate optical flow
  153. gpu_flow = cv2.cuda_FarnebackOpticalFlow.calc(
  154. gpu_flow, gpu_previous, gpu_current, None,
  155. )
  156. # end of timer
  157. end_of = time.time()
  158. # add elapsed iteration time
  159. timers["optical flow"].append(end_of - start_of)
  160. # start post-process timer
  161. start_post_time = time.time()
  162. gpu_flow_x = cv2.cuda_GpuMat(gpu_flow.size(), cv2.CV_32FC1)
  163. gpu_flow_y = cv2.cuda_GpuMat(gpu_flow.size(), cv2.CV_32FC1)
  164. cv2.cuda.split(gpu_flow, [gpu_flow_x, gpu_flow_y])
  165. # convert from cartesian to polar coordinates to get magnitude and angle
  166. gpu_magnitude, gpu_angle = cv2.cuda.cartToPolar(
  167. gpu_flow_x, gpu_flow_y, angleInDegrees=True,
  168. )
  169. # set value to normalized magnitude from 0 to 1
  170. gpu_v = cv2.cuda.normalize(gpu_magnitude, 0.0, 1.0, cv2.NORM_MINMAX, -1)
  171. # get angle of optical flow
  172. angle = gpu_angle.download()
  173. angle *= (1 / 360.0) * (180 / 255.0)
  174. # set hue according to the angle of optical flow
  175. gpu_h.upload(angle)
  176. # merge h,s,v channels
  177. cv2.cuda.merge([gpu_h, gpu_s, gpu_v], gpu_hsv)
  178. # multiply each pixel value to 255
  179. gpu_hsv.convertTo(cv2.CV_8U, 255.0, gpu_hsv_8u, 0.0)
  180. # convert hsv to bgr
  181. gpu_bgr = cv2.cuda.cvtColor(gpu_hsv_8u, cv2.COLOR_HSV2BGR)
  182. # send original frame from GPU back to CPU
  183. frame = gpu_frame.download()
  184. # send result from GPU back to CPU
  185. bgr = gpu_bgr.download()
  186. # update previous_frame value
  187. gpu_previous = gpu_current
  188. # end post-process timer
  189. end_post_time = time.time()
  190. # add elapsed iteration time
  191. timers["post-process"].append(end_post_time - start_post_time)
  192. # end full pipeline timer
  193. end_full_time = time.time()
  194. # add elapsed iteration time
  195. timers["full pipeline"].append(end_full_time - start_full_time)
  196. # visualization
  197. cv2.imshow("original", frame)
  198. cv2.imshow("result", bgr)
  199. k = cv2.waitKey(1)
  200. if k == 27:
  201. break
  202. # release the capture
  203. cap.release()
  204. # destroy all windows
  205. cv2.destroyAllWindows()
  206. # print results
  207. print("Number of frames : ", num_frames)
  208. # elapsed time at each stage
  209. print("Elapsed time")
  210. for stage, seconds in timers.items():
  211. print("-", stage, ": {:0.3f} seconds".format(sum(seconds)))
  212. # calculate frames per second
  213. print("Default video FPS : {:0.3f}".format(fps))
  214. of_fps = (num_frames - 1) / sum(timers["optical flow"])
  215. print("Optical flow FPS : {:0.3f}".format(of_fps))
  216. full_fps = (num_frames - 1) / sum(timers["full pipeline"])
  217. print("Full pipeline FPS : {:0.3f}".format(full_fps))
  218. if __name__ == "__main__":
  219. # init argument parser
  220. parser = argparse.ArgumentParser(description="OpenCV CPU/GPU Comparison")
  221. parser.add_argument(
  222. "--video", help="path to .mp4 video file", required=True, type=str,
  223. )
  224. parser.add_argument(
  225. "--device",
  226. default="cpu",
  227. choices=["cpu", "gpu"],
  228. help="device to inference on",
  229. )
  230. # parsing script arguments
  231. args = parser.parse_args()
  232. video = args.video
  233. device = args.device
  234. # output passed arguments
  235. print("Configuration")
  236. print("- device : ", device)
  237. print("- video file : ", video)
  238. # run pipeline
  239. main(video, device)