video_analyzer.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import logging
  2. import os.path
  3. import pickle
  4. from typing import Callable
  5. import cv2
  6. from config import UPLOAD_DIR, FILE_URL
  7. from service.ai.util.torch_openpose import torch_openpose
  8. from service.ai.util.util import draw_bodypose
  9. from service.ai.video.classify.balancebeam import classify_balancebeam
  10. from service.ai.video.classify.gaotaitui import classify_gaotaitui
  11. from service.ai.video.classify.juanfu import classify_juanfu
  12. from service.ai.video.classify.jump import classify_jump
  13. from service.ai.video.classify.jumpwithboth import classify_jumpwithboth
  14. from service.ai.video.classify.pingban import classify_pingban
  15. from service.ai.video.classify.shendun import classify_shendun
  16. from service.ai.video.classify.sitforward import classify_sitforward
  17. from service.ai.video.classify.standing import classify_standing
  18. from service.ai.video.classify.tennisthrow import classify_tennisthrow
  19. from service.ai.video.classify.turnaround import classify_turnaround
  20. from service.ai.video.inner_analyze import analyse_npy_side_jump, analyse_npy_side_juanfu, analyse_npy_side_shendun, \
  21. analyse_npy_side_gaotaitui
  22. from service.ai.video.video_score.balancebeam import cal_balancebeam
  23. from service.ai.video.video_score.gaotaitui import ignore_data_gaotaitui
  24. from service.ai.video.video_score.juanfu import ignore_data_juanfu
  25. from service.ai.video.video_score.jump import cal_jump
  26. from service.ai.video.video_score.jumpwithboth import cal_jumpwithboth
  27. from service.ai.video.video_score.pingban import cal_pingban
  28. from service.ai.video.video_score.shendun import ignore_data_shendun
  29. from service.ai.video.video_score.sitforward import cal_sitforward
  30. from service.ai.video.video_score.standing import cal_standing
  31. from service.ai.video.video_score.tennisthrow import cal_tennisthrow
  32. from service.ai.video.video_score.turnaround import cal_turnaround
  33. def run_openpose_for_npy_and_video(video_uuid, callback: Callable):
  34. video_path = UPLOAD_DIR + video_uuid + ".mp4"
  35. cap = cv2.VideoCapture(video_path)
  36. FPS = cap.get(cv2.CAP_PROP_FPS)
  37. total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
  38. out = None
  39. logging.debug("Splitting video %s, FPS: %s" % (video_path, FPS))
  40. c = 1
  41. sampling_fps = 1
  42. tp = torch_openpose('body_25') # AI Model
  43. results = {}
  44. while True:
  45. ret, frame = cap.read()
  46. if ret:
  47. if c % sampling_fps == 0:
  48. logging.debug("Running openpose for %s %s" % (video_uuid, c))
  49. poses = tp(frame)
  50. results[str(c)] = poses # this is evil, but the AI code expect it to be so.
  51. canvas = draw_bodypose(frame, poses, 'body_25')
  52. cv2.imwrite(UPLOAD_DIR + "result/" + video_uuid + "." + str(c) + ".jpg", canvas)
  53. if out is None:
  54. out = cv2.VideoWriter(UPLOAD_DIR + "result/" + video_uuid + ".result.mp4",
  55. cv2.VideoWriter_fourcc(*"vp90"), FPS,
  56. (canvas.shape[1], canvas.shape[0])) # So fucking stupid
  57. out.write(canvas)
  58. c += 1
  59. callback("RUNNING", progress=min(99, int(100 * c / (total_frames / sampling_fps))))
  60. else:
  61. break
  62. cap.release()
  63. out.release()
  64. return results
  65. class BaseVideoAnalyzer:
  66. def __init__(self, data: dict):
  67. self.video_uuid = data['video_uuid']
  68. self.results = None
  69. self.points = None
  70. def _do_analyze(self):
  71. assert False, "Internal error: You should override this with a subclass!"
  72. def analyze(self, callback: Callable):
  73. try:
  74. callback("RUNNING", progress=0)
  75. PICKLE_DUMP_PATH = UPLOAD_DIR + self.video_uuid + ".dump"
  76. if not os.path.exists(PICKLE_DUMP_PATH): # analyze
  77. self.results = run_openpose_for_npy_and_video(self.video_uuid, callback)
  78. self.points = self.results
  79. pickle.dump(self.results, open(PICKLE_DUMP_PATH, "wb"))
  80. else: # read cache
  81. self.results = pickle.load(open(PICKLE_DUMP_PATH, "rb"))
  82. result = {**self._do_analyze(), "file": FILE_URL + self.video_uuid + ".result.mp4"}
  83. # inject file url here
  84. try:
  85. for i in result['data']:
  86. result['data'][i]['file'] = FILE_URL + self.video_uuid + "." + result['data'][i]['index'] + ".jpg"
  87. result['data']['points']=self.points
  88. except Exception as e:
  89. logging.warning("file index in data not found, %s" % e)
  90. callback("FINISHED", result=result)
  91. except Exception as e:
  92. callback("ERROR", error=e)
  93. raise e
  94. class JumpVideoAnalyzer(BaseVideoAnalyzer):
  95. def _do_analyze(self):
  96. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  97. self.results = {k: v for k, v in self.results.items() if v != {}}
  98. raw = cal_jump(self.results)[1]
  99. return classify_jump(raw)
  100. class PingbanVideoAnalyzer(BaseVideoAnalyzer):
  101. def _do_analyze(self):
  102. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  103. self.results = {k: v for k, v in self.results.items() if v != {}}
  104. raw = cal_pingban(self.results)[1]
  105. return classify_pingban(raw)
  106. class JuanfuVideoAnalyzer(BaseVideoAnalyzer):
  107. def _do_analyze(self):
  108. self.results = {k: analyse_npy_side_juanfu(v) for k, v in self.results.items()}
  109. raw = ignore_data_juanfu(self.results)[1]
  110. return classify_juanfu(raw)
  111. class ShendunVideoAnalyzer(BaseVideoAnalyzer):
  112. def _do_analyze(self):
  113. self.results = {k: analyse_npy_side_shendun(v) for k, v in self.results.items()}
  114. raw = ignore_data_shendun(self.results)[1]
  115. return classify_shendun(raw)
  116. class GaotaituiVideoAnalyzer(BaseVideoAnalyzer):
  117. def _do_analyze(self):
  118. self.results = {k: analyse_npy_side_gaotaitui(v) for k, v in self.results.items()}
  119. raw = ignore_data_gaotaitui(self.results)[1]
  120. return classify_gaotaitui(raw)
  121. class TurnaroundVideoAnalyzer(BaseVideoAnalyzer):
  122. def _do_analyze(self):
  123. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  124. raw = cal_turnaround(self.results)[1]
  125. return classify_turnaround(raw)
  126. class TennisthrowVideoAnalyzer(BaseVideoAnalyzer):
  127. def _do_analyze(self):
  128. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  129. raw = cal_tennisthrow(self.results)[1]
  130. return classify_tennisthrow(raw)
  131. class JumpwithbothVideoAnalyzer(BaseVideoAnalyzer):
  132. def _do_analyze(self):
  133. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  134. raw = cal_jumpwithboth(self.results)[1]
  135. return classify_jumpwithboth(raw)
  136. class SitforwardVideoAnalyzer(BaseVideoAnalyzer):
  137. def _do_analyze(self):
  138. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  139. raw = cal_sitforward(self.results)[1]
  140. return classify_sitforward(raw)
  141. class BalancebeamVideoAnalyzer(BaseVideoAnalyzer):
  142. def _do_analyze(self):
  143. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  144. raw = cal_balancebeam(self.results)[1]
  145. return classify_balancebeam(raw)
  146. class StandingVideoAnalyzer(BaseVideoAnalyzer):
  147. def _do_analyze(self):
  148. self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
  149. raw = cal_standing(self.results)[1]
  150. return classify_standing(raw)