Innerhlab dieses Repositorys ist ein showcase ausgearbeitet, welcher live die Funktion des EVM Algorithmus darstellt.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main_showcase.py 14KB

3 weeks ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. import sys
  2. import cv2
  3. import numpy as np
  4. from PyQt5.QtWidgets import (
  5. QApplication, QWidget, QFormLayout, QPushButton, QLabel, QHBoxLayout, QVBoxLayout, QComboBox
  6. )
  7. from PyQt5.QtGui import QImage, QPixmap
  8. from PyQt5.QtCore import QTimer, Qt, QThread, pyqtSignal, QElapsedTimer
  9. import ideal_filter # Ensure this is properly implemented
  10. import butterworth_filter # Ensure this is properly implemented
  11. class CameraThread(QThread):
  12. frame_ready = pyqtSignal(np.ndarray)
  13. def __init__(self):
  14. super().__init__()
  15. self.is_running = True
  16. self.cap = cv2.VideoCapture(0)
  17. self.fps = self.cap.get(cv2.CAP_PROP_FPS) or 30
  18. def run(self):
  19. while self.is_running:
  20. ret, frame = self.cap.read()
  21. if ret:
  22. self.frame_ready.emit(frame)
  23. else:
  24. print("Error: Could not read frame from camera.")
  25. self.msleep(int(1000 / self.fps))
  26. def stop(self):
  27. self.is_running = False
  28. self.cap.release()
  29. class FilterWorker(QThread):
  30. result_ready = pyqtSignal(np.ndarray, float)
  31. def __init__(self, buffer, alpha, chromAttenuation, fps, filter_type="Ideal", width=512, height=512, time_window=5):
  32. super().__init__()
  33. self.buffer = buffer
  34. self.alpha = alpha
  35. self.chromAttenuation = chromAttenuation
  36. self.fps = fps
  37. self.width = width
  38. self.height = height
  39. self.time_window = time_window
  40. self.is_running = True
  41. self.filter_type = filter_type
  42. self.low, self.high = (1, 2.5) if filter_type == "Ideal" else (0.1, 0.5)
  43. def run(self):
  44. if self.filter_type == "Ideal":
  45. final_video, bpm = ideal_filter.start(
  46. vidFile=self.buffer,
  47. alpha=self.alpha,
  48. low=self.low,
  49. high=self.high,
  50. chromAttenuation=self.chromAttenuation,
  51. fps=self.fps,
  52. width=self.width, height=self.height
  53. )
  54. elif self.filter_type == "Butterworth":
  55. final_video, bpm = butterworth_filter.start(
  56. video_frames=self.buffer,
  57. alpha=self.alpha,
  58. low=self.low,
  59. high=self.high,
  60. chromAttenuation=self.chromAttenuation,
  61. fps=self.fps,
  62. width=self.width,
  63. height=self.height,
  64. time_window=self.time_window
  65. )
  66. if self.is_running:
  67. self.result_ready.emit(final_video, bpm)
  68. def stop(self):
  69. self.is_running = False
  70. class ParameterGUI(QWidget):
  71. def __init__(self):
  72. super().__init__()
  73. self.setWindowTitle('Video Filtering Display')
  74. self.setFixedSize(1400, 800)
  75. self.setup_ui()
  76. modelFile = "res10_300x300_ssd_iter_140000_fp16.caffemodel"
  77. configFile = "deploy.prototxt"
  78. self.face_net = cv2.dnn.readNetFromCaffe(configFile, modelFile)
  79. self.face_buffer = []
  80. self.video_buffer = []
  81. self.buffer_length = 0
  82. self.elapsed_timer = QElapsedTimer()
  83. self.is_processing = False
  84. self.worker = None
  85. self.camera_thread = None
  86. def setup_ui(self):
  87. layout = QVBoxLayout()
  88. # ComboBoxes for user parameters
  89. self.alphaMenu = QComboBox(self)
  90. alpha_values = [5, 10, 15, 20, 30, 40, 50, 60]
  91. self.alphaMenu.addItems([str(value) for value in alpha_values])
  92. self.chromAtt = QComboBox(self)
  93. chrom_values = [0.0001, 0.001,0.01,0.1,0.5]
  94. self.chromAtt.addItems([str(value) for value in chrom_values])
  95. self.timeWindowMenu = QComboBox(self)
  96. self.timeWindowMenu.addItems(["5", "10", "15", "20"])
  97. self.filterMenu = QComboBox(self)
  98. self.filterMenu.addItems(["Ideal", "Butterworth"])
  99. # Form layout for parameters
  100. form_layout = QFormLayout()
  101. form_layout.addRow("Alpha:", self.alphaMenu)
  102. form_layout.addRow("ChromAttenuation:", self.chromAtt)
  103. form_layout.addRow("Filter:", self.filterMenu)
  104. form_layout.addRow("Time Window (seconds):", self.timeWindowMenu)
  105. self.submitButton = QPushButton('Start Camera')
  106. self.submitButton.clicked.connect(self.start_camera)
  107. form_layout.addRow(self.submitButton)
  108. layout.addLayout(form_layout)
  109. # Layout for displaying video
  110. video_layout = QHBoxLayout()
  111. self.liveVideoLabel = QLabel(self)
  112. self.liveVideoLabel.setFixedSize(640, 480)
  113. self.processedVideoLabel = QLabel(self)
  114. self.processedVideoLabel.setFixedSize(640, 480)
  115. video_layout.addWidget(self.liveVideoLabel, alignment=Qt.AlignCenter)
  116. video_layout.addWidget(self.processedVideoLabel, alignment=Qt.AlignCenter)
  117. layout.addLayout(video_layout)
  118. # BPM and status labels
  119. self.bpmLabel = QLabel('BPM: ', self)
  120. layout.addWidget(self.bpmLabel)
  121. self.bufferStatusLabel = QLabel('Buffer status: Waiting...', self)
  122. layout.addWidget(self.bufferStatusLabel)
  123. self.filterStatusLabel = QLabel('Filter status: Not running', self)
  124. layout.addWidget(self.filterStatusLabel)
  125. self.ParameterStatusLabel = QLabel('No parameters set', self)
  126. layout.addWidget(self.ParameterStatusLabel)
  127. self.setLayout(layout)
  128. def start_camera(self):
  129. # Stop existing camera thread if it's running
  130. if self.camera_thread is not None:
  131. self.camera_thread.stop()
  132. self.camera_thread.wait()
  133. # Stop existing worker thread if it's running
  134. if self.worker is not None:
  135. self.worker.stop()
  136. self.worker.wait()
  137. # Stop any existing timer for video display
  138. if not hasattr(self, 'timer'):
  139. self.timer = QTimer(self)
  140. if self.timer.isActive():
  141. self.timer.stop() # Stop any running timer before starting new camera session
  142. # Reset buffers and status labels
  143. self.face_buffer.clear()
  144. self.video_buffer.clear()
  145. self.is_processing = False
  146. self.bufferStatusLabel.setText('Buffer status: Waiting...')
  147. self.filterStatusLabel.setText('Filter status: Not running')
  148. self.bpmLabel.setText('BPM: ')
  149. # Fetch parameters from UI
  150. self.alpha = int(self.alphaMenu.currentText())
  151. self.chromAttenuation = float(self.chromAtt.currentText())
  152. self.filter = str(self.filterMenu.currentText())
  153. self.timeWindow = int(self.timeWindowMenu.currentText())
  154. # Update the parameter status label
  155. self.ParameterStatusLabel.setText(f'Alpha: {self.alpha} ChromAttenuation: {self.chromAttenuation} TimeWindow: {self.timeWindow}')
  156. # Start the camera thread
  157. self.camera_thread = CameraThread() # Initialize the new camera thread
  158. self.camera_thread.frame_ready.connect(self.update_frame)
  159. self.camera_thread.start()
  160. # Set FPS and buffer length based on the camera's FPS
  161. self.fps = self.camera_thread.fps
  162. self.buffer_length = int(self.camera_thread.fps * self.timeWindow)
  163. # Start the elapsed timer to measure buffering time
  164. self.elapsed_timer.start()
  165. def update_frame(self, frame):
  166. if not self.is_processing:
  167. self.bufferStatusLabel.setText('Buffer status: Filling up')
  168. if self.filter == "Butterworth":
  169. upper_body_region, coords = self.get_upper_body(frame)
  170. if upper_body_region is not None:
  171. upper_body_resized = cv2.resize(upper_body_region, (512, 512))
  172. self.video_buffer.append(upper_body_resized)
  173. startX, startY, endX, endY = coords
  174. cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
  175. if self.filter == "Ideal":
  176. face_region = self.get_face(frame)
  177. if face_region is not None:
  178. face_region_resized = cv2.resize(face_region, (512, 512))
  179. #Weißabgleich
  180. face_region_resized = cv2.GaussianBlur(face_region_resized,(25,25),0)
  181. face_region_resized = cv2.medianBlur(face_region_resized,25)
  182. self.face_buffer.append(face_region_resized)
  183. if self.elapsed_timer.elapsed() >= self.timeWindow * 1000:
  184. self.process_buffers()
  185. self.elapsed_timer.restart()
  186. # Display the live frame
  187. frame_display = self.resize_frame(frame, self.liveVideoLabel)
  188. frame_display = cv2.cvtColor(frame_display, cv2.COLOR_BGR2RGB)
  189. height, width, channel = frame_display.shape
  190. bytes_per_line = channel * width
  191. q_img = QImage(frame_display.data, width, height, bytes_per_line, QImage.Format_RGB888)
  192. self.liveVideoLabel.setPixmap(QPixmap.fromImage(q_img))
  193. def get_face(self, frame):
  194. (h, w) = frame.shape[:2]
  195. blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0))
  196. self.face_net.setInput(blob)
  197. detections = self.face_net.forward()
  198. for i in range(0, detections.shape[2]):
  199. confidence = detections[0, 0, i, 2]
  200. if confidence > 0.5:
  201. box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
  202. (startX, startY, endX, endY) = box.astype("int")
  203. face_region = frame[startY:endY, startX:endX]
  204. cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
  205. return face_region
  206. return None
  207. def get_upper_body(self, frame):
  208. (h, w) = frame.shape[:2]
  209. startY = int(h / 2)
  210. endY = h
  211. startX = int(w / 4)
  212. endX = int(w * 3 / 4)
  213. cropped_frame = frame[startY:endY, startX:endX]
  214. return cropped_frame, (startX, startY, endX, endY)
  215. def process_buffers(self):
  216. if self.is_processing:
  217. return
  218. self.is_processing = True
  219. self.bufferStatusLabel.setText('Buffer status: Completed')
  220. self.filterStatusLabel.setText('Filter status: Running')
  221. time_window = int(self.timeWindowMenu.currentText())
  222. if self.filter == "Ideal" and self.face_buffer:
  223. self.worker = FilterWorker(
  224. self.face_buffer.copy(), # Copy buffer before clearing
  225. self.alpha,
  226. self.chromAttenuation,
  227. self.camera_thread.fps,
  228. filter_type="Ideal",
  229. time_window=time_window
  230. )
  231. self.worker.result_ready.connect(self.display_filtered_video)
  232. self.worker.start()
  233. self.face_buffer.clear()
  234. elif self.filter == "Butterworth" and self.video_buffer:
  235. self.worker = FilterWorker(
  236. self.video_buffer.copy(), # Copy buffer before clearing
  237. self.alpha,
  238. self.chromAttenuation,
  239. self.camera_thread.fps,
  240. filter_type="Butterworth",
  241. time_window=time_window
  242. )
  243. self.worker.result_ready.connect(self.display_filtered_video)
  244. self.worker.start()
  245. # Clear the buffer after starting the filter worker
  246. self.video_buffer.clear()
  247. def display_filtered_video(self, final_video, bpm):
  248. self.bpmLabel.setText(f'BPM: {bpm:.2f}')
  249. self.filterStatusLabel.setText('Filter status: Displaying video')
  250. self.frame_index = 0
  251. self.final_video = final_video
  252. # Stop the existing timer (if any) and set up a new timer for frame display
  253. if hasattr(self, 'frame_timer'):
  254. self.frame_timer.stop()
  255. self.frame_timer = QTimer(self)
  256. self.frame_timer.timeout.connect(lambda: self.show_filtered_frame(self.final_video))
  257. self.frame_timer.start(int(1000 / self.fps)) # Display frames based on FPS
  258. print(self.fps)
  259. def show_filtered_frame(self, final_video):
  260. """Displays each frame from the filtered video using a QTimer."""
  261. if self.frame_index < len(final_video):
  262. frame = final_video[self.frame_index]
  263. if frame.dtype == np.float64:
  264. frame = cv2.normalize(frame, None, 0, 255, cv2.NORM_MINMAX)
  265. frame = frame.astype(np.uint8)
  266. # Resize and display the filtered frame
  267. frame_resized = self.resize_frame(frame, self.processedVideoLabel)
  268. frame_resized = cv2.cvtColor(frame_resized, cv2.COLOR_BGR2RGB)
  269. height, width, channel = frame_resized.shape
  270. bytes_per_line = channel * width
  271. q_img = QImage(frame_resized.data, width, height, bytes_per_line, QImage.Format_RGB888)
  272. self.processedVideoLabel.setPixmap(QPixmap.fromImage(q_img))
  273. QApplication.processEvents()
  274. self.frame_index += 1
  275. else:
  276. # Stop the filtered video display timer
  277. self.frame_timer.stop()
  278. # Restart the live video feed
  279. if hasattr(self, 'timer'):
  280. self.timer.start(int(1000 / self.fps)) # Restart the live feed timer
  281. else:
  282. print("Error: Timer for live video is not initialized.")
  283. self.filterStatusLabel.setText('Filter status: Completed')
  284. self.is_processing = False
  285. self.bufferStatusLabel.setText('Buffer status: Blocked')
  286. def resize_frame(self, frame, label):
  287. size = label.size()
  288. return cv2.resize(frame, (size.width(), size.height()))
  289. def closeEvent(self, event):
  290. if self.camera_thread:
  291. self.camera_thread.stop()
  292. if self.worker:
  293. self.worker.stop()
  294. if self.frame_timer:
  295. self.frame_timer.stop()
  296. event.accept()
  297. if __name__ == '__main__':
  298. app = QApplication(sys.argv)
  299. window = ParameterGUI()
  300. window.show()
  301. sys.exit(app.exec_())
  302. for i in range(frame_count):
  303. ret, frame = cap.read()
  304. if not ret:
  305. print(f"Frame {i+1} konnte nicht gelesen werden.")
  306. break
  307. frames[i] = frame
  308. # Optional: Vorschau anzeigen
  309. cv2.imshow("Aufnahme", frame)
  310. if cv2.waitKey(1) & 0xFF == ord('q'): # Beenden durch Drücken von 'q'
  311. break
  312. # Kamera und Fenster freigeben
  313. cap.release()
  314. cv2.destroyAllWindows()