|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- import sys
- import cv2
- import numpy as np
- from PyQt5.QtWidgets import (
- QApplication, QWidget, QFormLayout, QPushButton, QLabel, QHBoxLayout, QVBoxLayout, QComboBox
- )
- from PyQt5.QtGui import QImage, QPixmap
- from PyQt5.QtCore import QTimer, Qt, QThread, pyqtSignal, QElapsedTimer
-
- import ideal_filter # Ensure this is properly implemented
- import butterworth_filter # Ensure this is properly implemented
-
-
- class CameraThread(QThread):
- frame_ready = pyqtSignal(np.ndarray)
-
- def __init__(self):
- super().__init__()
- self.is_running = True
- self.cap = cv2.VideoCapture(0)
- self.fps = self.cap.get(cv2.CAP_PROP_FPS) or 30
-
- def run(self):
- while self.is_running:
- ret, frame = self.cap.read()
- if ret:
- self.frame_ready.emit(frame)
- else:
- print("Error: Could not read frame from camera.")
- self.msleep(int(1000 / self.fps))
-
- def stop(self):
- self.is_running = False
- self.cap.release()
-
-
- class FilterWorker(QThread):
- result_ready = pyqtSignal(np.ndarray, float)
-
- def __init__(self, buffer, alpha, chromAttenuation, fps, filter_type="Ideal", width=512, height=512, time_window=5):
- super().__init__()
- self.buffer = buffer
- self.alpha = alpha
- self.chromAttenuation = chromAttenuation
- self.fps = fps
- self.width = width
- self.height = height
- self.time_window = time_window
- self.is_running = True
- self.filter_type = filter_type
- self.low, self.high = (1, 2.5) if filter_type == "Ideal" else (0.1, 0.5)
-
- def run(self):
-
-
-
- if self.filter_type == "Ideal":
- final_video, bpm = ideal_filter.start(
- vidFile=self.buffer,
- alpha=self.alpha,
- low=self.low,
- high=self.high,
- chromAttenuation=self.chromAttenuation,
- fps=self.fps,
- width=self.width, height=self.height
- )
-
- elif self.filter_type == "Butterworth":
- final_video, bpm = butterworth_filter.start(
- video_frames=self.buffer,
- alpha=self.alpha,
- low=self.low,
- high=self.high,
- chromAttenuation=self.chromAttenuation,
- fps=self.fps,
- width=self.width,
- height=self.height,
- time_window=self.time_window
- )
- if self.is_running:
- self.result_ready.emit(final_video, bpm)
-
- def stop(self):
- self.is_running = False
-
- class ParameterGUI(QWidget):
- def __init__(self):
- super().__init__()
- self.setWindowTitle('Video Filtering Display')
- self.setFixedSize(1400, 800)
- self.setup_ui()
-
- modelFile = "res10_300x300_ssd_iter_140000_fp16.caffemodel"
- configFile = "deploy.prototxt"
- self.face_net = cv2.dnn.readNetFromCaffe(configFile, modelFile)
-
- self.face_buffer = []
- self.video_buffer = []
- self.buffer_length = 0
-
- self.elapsed_timer = QElapsedTimer()
- self.is_processing = False
- self.worker = None
- self.camera_thread = None
-
-
- def setup_ui(self):
- layout = QVBoxLayout()
-
- # ComboBoxes for user parameters
- self.alphaMenu = QComboBox(self)
- alpha_values = [5, 10, 15, 20, 30, 40, 50, 60]
- self.alphaMenu.addItems([str(value) for value in alpha_values])
-
- self.chromAtt = QComboBox(self)
- chrom_values = [0.0001, 0.001,0.01,0.1,0.5]
- self.chromAtt.addItems([str(value) for value in chrom_values])
-
- self.timeWindowMenu = QComboBox(self)
- self.timeWindowMenu.addItems(["5", "10", "15", "20"])
-
- self.filterMenu = QComboBox(self)
- self.filterMenu.addItems(["Ideal", "Butterworth"])
-
- # Form layout for parameters
- form_layout = QFormLayout()
- form_layout.addRow("Alpha:", self.alphaMenu)
- form_layout.addRow("ChromAttenuation:", self.chromAtt)
- form_layout.addRow("Filter:", self.filterMenu)
- form_layout.addRow("Time Window (seconds):", self.timeWindowMenu)
-
- self.submitButton = QPushButton('Start Camera')
- self.submitButton.clicked.connect(self.start_camera)
- form_layout.addRow(self.submitButton)
- layout.addLayout(form_layout)
-
- # Layout for displaying video
- video_layout = QHBoxLayout()
- self.liveVideoLabel = QLabel(self)
- self.liveVideoLabel.setFixedSize(640, 480)
- self.processedVideoLabel = QLabel(self)
- self.processedVideoLabel.setFixedSize(640, 480)
-
- video_layout.addWidget(self.liveVideoLabel, alignment=Qt.AlignCenter)
- video_layout.addWidget(self.processedVideoLabel, alignment=Qt.AlignCenter)
- layout.addLayout(video_layout)
-
- # BPM and status labels
- self.bpmLabel = QLabel('BPM: ', self)
- layout.addWidget(self.bpmLabel)
-
- self.bufferStatusLabel = QLabel('Buffer status: Waiting...', self)
- layout.addWidget(self.bufferStatusLabel)
-
- self.filterStatusLabel = QLabel('Filter status: Not running', self)
- layout.addWidget(self.filterStatusLabel)
-
- self.ParameterStatusLabel = QLabel('No parameters set', self)
- layout.addWidget(self.ParameterStatusLabel)
-
- self.setLayout(layout)
-
- def start_camera(self):
- # Stop existing camera thread if it's running
- if self.camera_thread is not None:
- self.camera_thread.stop()
- self.camera_thread.wait()
-
- # Stop existing worker thread if it's running
- if self.worker is not None:
- self.worker.stop()
- self.worker.wait()
-
- # Stop any existing timer for video display
- if not hasattr(self, 'timer'):
- self.timer = QTimer(self)
- if self.timer.isActive():
- self.timer.stop() # Stop any running timer before starting new camera session
-
- # Reset buffers and status labels
- self.face_buffer.clear()
- self.video_buffer.clear()
- self.is_processing = False
- self.bufferStatusLabel.setText('Buffer status: Waiting...')
- self.filterStatusLabel.setText('Filter status: Not running')
- self.bpmLabel.setText('BPM: ')
-
- # Fetch parameters from UI
- self.alpha = int(self.alphaMenu.currentText())
- self.chromAttenuation = float(self.chromAtt.currentText())
- self.filter = str(self.filterMenu.currentText())
- self.timeWindow = int(self.timeWindowMenu.currentText())
-
- # Update the parameter status label
- self.ParameterStatusLabel.setText(f'Alpha: {self.alpha} ChromAttenuation: {self.chromAttenuation} TimeWindow: {self.timeWindow}')
-
- # Start the camera thread
- self.camera_thread = CameraThread() # Initialize the new camera thread
- self.camera_thread.frame_ready.connect(self.update_frame)
- self.camera_thread.start()
-
- # Set FPS and buffer length based on the camera's FPS
- self.fps = self.camera_thread.fps
- self.buffer_length = int(self.camera_thread.fps * self.timeWindow)
-
- # Start the elapsed timer to measure buffering time
- self.elapsed_timer.start()
-
-
- def update_frame(self, frame):
- if not self.is_processing:
- self.bufferStatusLabel.setText('Buffer status: Filling up')
-
- if self.filter == "Butterworth":
- upper_body_region, coords = self.get_upper_body(frame)
- if upper_body_region is not None:
- upper_body_resized = cv2.resize(upper_body_region, (512, 512))
- self.video_buffer.append(upper_body_resized)
- startX, startY, endX, endY = coords
- cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
-
- if self.filter == "Ideal":
- face_region = self.get_face(frame)
- if face_region is not None:
- face_region_resized = cv2.resize(face_region, (512, 512))
-
- #Weißabgleich
- face_region_resized = cv2.GaussianBlur(face_region_resized,(25,25),0)
- face_region_resized = cv2.medianBlur(face_region_resized,25)
-
- self.face_buffer.append(face_region_resized)
-
- if self.elapsed_timer.elapsed() >= self.timeWindow * 1000:
- self.process_buffers()
- self.elapsed_timer.restart()
-
-
- # Display the live frame
- frame_display = self.resize_frame(frame, self.liveVideoLabel)
- frame_display = cv2.cvtColor(frame_display, cv2.COLOR_BGR2RGB)
- height, width, channel = frame_display.shape
- bytes_per_line = channel * width
- q_img = QImage(frame_display.data, width, height, bytes_per_line, QImage.Format_RGB888)
- self.liveVideoLabel.setPixmap(QPixmap.fromImage(q_img))
-
-
- def get_face(self, frame):
- (h, w) = frame.shape[:2]
- blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0))
- self.face_net.setInput(blob)
- detections = self.face_net.forward()
-
- for i in range(0, detections.shape[2]):
- confidence = detections[0, 0, i, 2]
- if confidence > 0.5:
- box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
- (startX, startY, endX, endY) = box.astype("int")
- face_region = frame[startY:endY, startX:endX]
- cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
- return face_region
- return None
-
-
- def get_upper_body(self, frame):
- (h, w) = frame.shape[:2]
- startY = int(h / 2)
- endY = h
- startX = int(w / 4)
- endX = int(w * 3 / 4)
-
- cropped_frame = frame[startY:endY, startX:endX]
- return cropped_frame, (startX, startY, endX, endY)
-
- def process_buffers(self):
- if self.is_processing:
- return
-
- self.is_processing = True
- self.bufferStatusLabel.setText('Buffer status: Completed')
- self.filterStatusLabel.setText('Filter status: Running')
-
- time_window = int(self.timeWindowMenu.currentText())
-
- if self.filter == "Ideal" and self.face_buffer:
- self.worker = FilterWorker(
- self.face_buffer.copy(), # Copy buffer before clearing
- self.alpha,
- self.chromAttenuation,
- self.camera_thread.fps,
- filter_type="Ideal",
- time_window=time_window
- )
- self.worker.result_ready.connect(self.display_filtered_video)
- self.worker.start()
-
- self.face_buffer.clear()
-
- elif self.filter == "Butterworth" and self.video_buffer:
- self.worker = FilterWorker(
- self.video_buffer.copy(), # Copy buffer before clearing
- self.alpha,
- self.chromAttenuation,
- self.camera_thread.fps,
- filter_type="Butterworth",
- time_window=time_window
- )
- self.worker.result_ready.connect(self.display_filtered_video)
- self.worker.start()
-
- # Clear the buffer after starting the filter worker
- self.video_buffer.clear()
-
- def display_filtered_video(self, final_video, bpm):
- self.bpmLabel.setText(f'BPM: {bpm:.2f}')
-
- self.filterStatusLabel.setText('Filter status: Displaying video')
- self.frame_index = 0
- self.final_video = final_video
-
- # Stop the existing timer (if any) and set up a new timer for frame display
- if hasattr(self, 'frame_timer'):
- self.frame_timer.stop()
-
- self.frame_timer = QTimer(self)
- self.frame_timer.timeout.connect(lambda: self.show_filtered_frame(self.final_video))
- self.frame_timer.start(int(1000 / self.fps)) # Display frames based on FPS
- print(self.fps)
-
- def show_filtered_frame(self, final_video):
- """Displays each frame from the filtered video using a QTimer."""
- if self.frame_index < len(final_video):
- frame = final_video[self.frame_index]
-
- if frame.dtype == np.float64:
- frame = cv2.normalize(frame, None, 0, 255, cv2.NORM_MINMAX)
- frame = frame.astype(np.uint8)
-
- # Resize and display the filtered frame
- frame_resized = self.resize_frame(frame, self.processedVideoLabel)
- frame_resized = cv2.cvtColor(frame_resized, cv2.COLOR_BGR2RGB)
- height, width, channel = frame_resized.shape
- bytes_per_line = channel * width
- q_img = QImage(frame_resized.data, width, height, bytes_per_line, QImage.Format_RGB888)
-
- self.processedVideoLabel.setPixmap(QPixmap.fromImage(q_img))
- QApplication.processEvents()
-
- self.frame_index += 1
-
- else:
- # Stop the filtered video display timer
- self.frame_timer.stop()
-
- # Restart the live video feed
- if hasattr(self, 'timer'):
- self.timer.start(int(1000 / self.fps)) # Restart the live feed timer
- else:
- print("Error: Timer for live video is not initialized.")
- self.filterStatusLabel.setText('Filter status: Completed')
- self.is_processing = False
- self.bufferStatusLabel.setText('Buffer status: Blocked')
-
- def resize_frame(self, frame, label):
- size = label.size()
- return cv2.resize(frame, (size.width(), size.height()))
-
- def closeEvent(self, event):
- if self.camera_thread:
- self.camera_thread.stop()
- if self.worker:
- self.worker.stop()
- if self.frame_timer:
- self.frame_timer.stop()
- event.accept()
-
-
- if __name__ == '__main__':
- app = QApplication(sys.argv)
- window = ParameterGUI()
- window.show()
- sys.exit(app.exec_())
-
-
- for i in range(frame_count):
- ret, frame = cap.read()
- if not ret:
- print(f"Frame {i+1} konnte nicht gelesen werden.")
- break
- frames[i] = frame
-
- # Optional: Vorschau anzeigen
- cv2.imshow("Aufnahme", frame)
- if cv2.waitKey(1) & 0xFF == ord('q'): # Beenden durch Drücken von 'q'
- break
-
- # Kamera und Fenster freigeben
- cap.release()
- cv2.destroyAllWindows()
|