def test_read_frames_from_disk(self): # Store old FPS self.curr_settings, _ = settings.get_parameters() self.fps_backup = self.curr_settings[IDX_FPS] # Adjust to FPS of test video settings.change_settings(IDX_FPS, 25) # Store frame location in video thread file_names = ["1.jpg"] for num in range(2, 1002): file_names.append(str(num) + ".jpg") self.videoThread.store_frames_from_disk("tests/test_frames", file_names) # Activate video thread self.videoThread.eventUserPressedStart.set() # Wait until thread has finished self.videoThread.join() # Compare number of stored frames assert_equal(self.videoThread.frameCounter, 1001) # Restore old FPS settings.change_settings(IDX_FPS, self.fps_backup)
def test_gui_ToolbarROI_enable_disable_Viola_Jones(self): """Check is Viola Jones button function works""" # Get options before curr_settings = settings.get_parameters() before = curr_settings[IDX_FACE] # Simulate button click self.toolbar_roi._ToolbarROI__enable_or_disable_viola_jones_algorithm() # Get options after curr_settings = settings.get_parameters() after = curr_settings[IDX_FACE] # Restore value settings.change_settings(IDX_FACE, before) # Compare assert_not_equal(before, after)
def __init__(self, parent, tk_root, thread, cam, signal_display, roi_toolbar): # Store variables global root self.root = tk_root self.parent = parent # Add exit function to X button self.root.protocol("WM_DELETE_WINDOW", self.__quit) # Store camera object self.cameraInstance = cam # Get number of available cameras self.numberOfCameras = self.cameraInstance.get_number_of_cameras() # Store thread object self.threadInstance = thread # Store connection to signal display self.signalDisplayInstance = signal_display # Store connection to ROI toolbar self.toolbar_roi = roi_toolbar # Initialize buttons self.check_button_1 = self.check_button_2 = self.check_button_2 = self.check_button_4 = \ self.listCamerasStr = self.dropDownListCamera = self.listAlgorithmStr = self.dropDownListAlgorithm = None # Get current settings self.curr_settings, _ = settings.get_parameters() # Create GUI self.__create_gui()
def test_gui_ToolbarROI___enable_or_disable_option(self): """Check if zero padding button function works""" # Get options before curr_settings = settings.get_parameters() before = curr_settings[IDX_ZERO_PADDING] # Simulate button click self.toolbar_roi._ToolbarROI__enable_or_disable_option( IDX_ZERO_PADDING) # Get options after curr_settings = settings.get_parameters() after = curr_settings[IDX_ZERO_PADDING] # Restore value settings.change_settings(IDX_ZERO_PADDING, before) # Compare assert_not_equal(before, after)
def __init__(self): """ Initialization of class. The system is scanned for OpenCV compatible cameras and variables are set """ # Thread initialization threading.Thread.__init__(self) # Set camera to default value self.cameraIdx = 0 # Event is activated when user presses ''start'' button self.eventUserPressedStart = threading.Event() # Event is activated when frames are received from camera or hard disk self.eventVideoReady = threading.Event() # Event is activated when user closed the application. self.eventProgramEnd = threading.Event() # Create variable to adjust thread sleeping time to desired FPS self.currSettings, _ = settings.get_parameters() self.FPS = self.currSettings[IDX_FPS] # Initialize variables self.videoStream = self.startTime = None # A black frame that is displayed until the user has started the program self.currentFrame = np.zeros((480, 640, 3), np.uint8) # If the user wants to read frames from the hard disk, the directory and file names are stored here self.filesDir = None self.files = None # A counter of loaded frames, used for loading frames from hard disk self.frameCounter = 0 # During init, the cameras available are counted (idea from http://stackoverflow.com/a/30384945) # apparently there is still no clean OpenCV-based solution (https://github.com/opencv/opencv/issues/4269) self.numberOfCameras = 0 for i in range(2): cap = None try: cap = cv2.VideoCapture(i) ret, frame = cap.read() cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cap.release() cv2.destroyAllWindows() self.numberOfCameras += 1 except: if cap is not None: cap.release() cv2.destroyAllWindows() break tmp_str = "Found " + str( self.numberOfCameras) + " OpenCV-compatible cameras" logging.info(tmp_str)
def __change_algorithm_parameter(self, idx_param, value): """Action to perform when corresponding button is pressed""" # Get current parameters _, curr_parameters = settings.get_parameters() # Change parameter settings.change_parameters(idx_param, value) logging.info('User changed algorithm parameter: ' + str(value))
def __enable_or_disable_algorithm_parameter(self, idx_param): """Action to perform when corresponding button is pressed""" # Get current parameters _, curr_parameters = settings.get_parameters() # Change parameter settings.change_parameters(idx_param, 1 - curr_parameters[idx_param]) logging.info('User enabled option: ' + str(idx_param))
def __init__(self, parent, tk_root, thread, cam, roi, statusbar): # Store variables global root self.root = tk_root self.parent = parent self.first_frame = True self.faceCascade = cv2.CascadeClassifier( 'data/haarcascade_frontalface_default.xml') # Save camera object self.cameraInstance = cam # Save thread object self.threadInstance = thread # Save ROI toolbar object self.roiToolbarInstance = roi # Save statusbar instance self.statusbarInstance = statusbar # Initialize threading event for display of trigger symbol self.eventShowTrigger = threading.Event() # A counter that is used to determine how long the symbol is shown self.counterShownTriggerSymbol = 0 # Initialize variable that contains HR self.HeartRateText = ' ' # Create GUI self.__create_gui() # Get current settings self.curr_settings, _ = settings.get_parameters() # Create variable to adjust thread sleeping time to desired FPS self.sleep_time = 1000 / self.curr_settings[IDX_FPS] # Start frame display as thread self.frameCounter = 0 self.displayThread = threading.Thread(target=self.__show_image) self.displayThread.start() # Start FPS computation thread self.FPS = 0 self.frameCounterLastValue = 0 self.fpsCounterThread = threading.Thread(target=self.__compute_fps) self.fpsCounterThread.start()
def __enable_or_disable_viola_jones_algorithm(self): """Action to perform when Viola-Jones button is pressed""" # Get current parameters settings.flip_setting(IDX_FACE) curr_settings, _ = settings.get_parameters() if curr_settings[IDX_FACE]: self.textbox_x1.config(bg='lightgray') self.textbox_x2.config(bg='lightgray') self.textbox_y1.config(bg='lightgray') self.textbox_y2.config(bg='lightgray') logging.info('Viola-Jones algorithm was activated by the user') else: self.textbox_x1.config(bg='white') self.textbox_x2.config(bg='white') self.textbox_y1.config(bg='white') self.textbox_y2.config(bg='white') logging.info('Viola-Jones algorithm was disabled by the user')
def test_gui_toolbarButtons_change_algorithm(self): """Check if change algorithm button function works""" # Get current text in text box curr_text = self.toolbar_buttons.dropDownListAlgorithm.cget("text") # Call function self.toolbar_buttons._ToolbarButtons__change_algorithm() # Get options curr_settings = settings.get_parameters() if curr_settings[IDX_ALGORITHM] == 0 and curr_text == LABEL_ALGORITHM_1: assert True elif curr_settings[ IDX_ALGORITHM] == 1 and curr_text == LABEL_ALGORITHM_2: assert True elif curr_settings[ IDX_ALGORITHM] == 2 and curr_text == LABEL_ALGORITHM_3: assert True else: assert False
def test_compute_heart_rate_frequency(self): """Test if HR is computed correctly""" # Get algorithm parameters _, self.curr_parameters = settings.get_parameters() # Enable zero padding if self.curr_parameters[IDX_ZERO_PADDING] != 1.0: settings.change_parameters(IDX_ZERO_PADDING, 1) # Time vector t = np.arange(600) * 0.1 # Test signal with variable frequency and 10 Hz sampling frequency for n in range(0, 25): frequency = np.random.uniform(0.8, 1.5, 1) phase = np.random.rand(1) - 0.5 signal = np.cos(2 * np.pi * t * frequency + phase) yield self.compute_heart_rate_frequency, signal, frequency # Undo changes if self.curr_parameters[IDX_ZERO_PADDING] != 1.0: settings.change_parameters(IDX_ZERO_PADDING, 0)
def compute_heart_rate(self, input_raw_signal, estimated_fps): """This simple algorithm computes the heart rate as described in: Spicher N, Maderwald S, Ladd ME and Kukuk M. Heart rate monitoring in ultra-high-field MRI using frequency information obtained from video signals of the human skin compared to electrocardiography and pulse oximetry. Proceedings of the 49th Annual Conference of the German Society for Biomedical Engineering, Luebeck, Germany, 16.-18.09.2015. Please note that the different length of the input signal N and that a moving average filter as described in section 2.4) of the reference is not applied. """ # Get normalized signal signal = self.normalize(input_raw_signal) # Store number of elements in signal n = np.size(signal) # Store FPS of video stream fps = estimated_fps # Parameters: Minimal and maximum HR (48..180 bpm) hr_min = 0.5 hr_max = 3 # Get current settings curr_settings, curr_parameters = settings.get_parameters() # Apply zero padding if it is enabled if curr_parameters[IDX_ZERO_PADDING]: # Compute next power of 2 from N next_n = self.nextpow2(self.nextpow2(n)) # Zero padding: Fill before and after signal with zeros number_before, number_after = self.compute_zero_padding_values( next_n - n) signal = np.concatenate((np.zeros( int(number_before)), signal, np.zeros(int(number_after))), 0) # Use new N value instead n = next_n # Use Hamming window on signal values_win = signal[0:n] * np.hamming(n) # Compute FFT signal_fft = np.fft.fft(values_win) # Compute frequency axis x = np.linspace(0, n / fps, n + 1) freq_axis = np.fft.fftfreq(len(values_win), x[1] - x[0]) # Get boolean values if values are between hrMin and hrMax limits_bool = (hr_min < freq_axis) & (hr_max > freq_axis) limits_idx = np.linspace(0, n - 1, n) # Get indices of frequencies between hrMin and hrMax limits = limits_idx[limits_bool.nonzero()] limits = limits.astype(int) # Get index of maximum frequency in FFT spectrum max_val = limits[np.argmax(abs(signal_fft[limits]))] # Return HR, spectrum with frequency axis, and found maximum return (np.round(freq_axis[max_val] * 60)), abs( signal_fft[limits]), freq_axis[limits], max_val - limits[0]
from builtins import filter from fpdf import FPDF import settings from helper_functions import break_chapter_to_lines PARAMETERS = settings.get_parameters() def get_text_body_length(text_body): return len(text_body.splitlines()) class PDF(FPDF): def __init__(self, orientation='P', unit='mm', format='A4'): super().__init__(orientation, unit, format) self.footer_text = "" path_to_font = "CourierNewRegular.ttf" self.add_font('Courier New', '', path_to_font, uni=True) # Containing coordinates for link self.link_locations = [] # Page numbers where links lead. Used for rtf conversion self.link_page = [] self.writing_toc = False def table_of_contents(self, contents, orientation, create_hyperlink=True): """ Creates a table of contents page at the first page. :param create_hyperlink: Boolean indicating if we want to create hyperlinks to toc items :param orientation: Page orientation. Values "P" or "L" :param contents: Dictionary where keys are chapter names and values are page numbers where chapter starts
def __open_options_menu(self): # Get current option curr_settings, curr_param = settings.get_parameters() # Create window self.menu = Tk.Toplevel() self.menu.wm_geometry("270x210") self.menu.title("Algorithm parameters") # Add label self.label_info_text_1 = Tk.Label(self.menu, text=LABEL_ALGORITHM_1 + ":", anchor="w", font="Verdana 10 bold") self.label_info_text_1.pack(side=Tk.TOP, fill="both") # Add content button_zero_padding = Tk.Checkbutton( self.menu, text="Enable zero-padding when using FFT", anchor="w", command=lambda: self.__enable_or_disable_algorithm_parameter( IDX_ZERO_PADDING)) button_zero_padding.pack(side=Tk.TOP, fill="both") if curr_param[IDX_ZERO_PADDING]: button_zero_padding.toggle() # Add label self.label_info_text_2 = Tk.Label(self.menu, text=LABEL_ALGORITHM_2 + ":", anchor="w", font="Verdana 10 bold") self.label_info_text_2.pack(side=Tk.TOP, fill="both") self.label_param_1 = Tk.Label(self.menu, text="Used values", anchor="w") self.label_param_1.pack(side=Tk.TOP, fill="both") self.textbox_param_1 = Tk.Text(self.menu, width=6, height=1) self.textbox_param_1.pack(side=Tk.TOP, fill="both") self.textbox_param_1.insert(Tk.END, curr_param[IDX_WIN_SIZE]) self.label_param_2 = Tk.Label(self.menu, text="Running max window size", anchor="w") self.label_param_2.pack(side=Tk.TOP, fill="both") self.textbox_param_2 = Tk.Text(self.menu, width=6, height=1) self.textbox_param_2.pack(side=Tk.TOP, fill="both") self.textbox_param_2.insert(Tk.END, curr_param[IDX_RUN_MAX]) self.label_param_3 = Tk.Label(self.menu, text="Minimum trigger time", anchor="w") self.label_param_3.pack(side=Tk.TOP, fill="both") self.textbox_param_3 = Tk.Text(self.menu, width=6, height=1) self.textbox_param_3.pack(side=Tk.TOP, fill="both") self.textbox_param_3.insert(Tk.END, curr_param[IDX_MIN_TIME]) self.button_options_store = Tk.Button( self.menu, text="Save", width=6, command=lambda: self.__store_values_in_options_menu()) self.button_options_store.pack(side=Tk.TOP)
from PyQt5.QtCore import QThread from PyQt5.QtWidgets import QVBoxLayout, QLabel, QPushButton, QWidget, QFileDialog, QRadioButton, \ QButtonGroup, QTextBrowser, QCheckBox, QProgressBar, QTextEdit, QHBoxLayout from main_functions import Converter from settings import get_parameters parameters = get_parameters() ### TODO: COMMENT # noinspection PyArgumentList class MainWindow(QWidget): def __init__(self): super().__init__() self.filetype_set = False self.save_location = "" self.main_layout = QHBoxLayout(self) self.converter = Converter() self.setWindowTitle("PDF compiler") self.create_base_ui() def create_thread(self): try: self.thread.isFinished() except: self.thread = QThread() self.thread.finished.connect(self._update_finished_text) self.converter.moveToThread(self.thread) self.thread.started.connect(self.converter.convert) self.converter.finished.connect(self.thread.quit)
def __create_gui(self): """Create GUI elements and add them to root widget""" # Create frame that contains all following elements self.button_frame = Tk.Frame(root, width=500, height=100) self.button_frame.pack(side=Tk.BOTTOM) # Add Checkbutton to decide whether to use Viola-Jones algorithm or manual ROI definition curr_settings, _ = settings.get_parameters() self.check_button_1 = Tk.Checkbutton( master=self.button_frame, text="Face Detection", command=lambda: self.__enable_or_disable_viola_jones_algorithm()) self.check_button_1.pack(side=Tk.LEFT) # Add empty box # Todo: use a dynamic solution self.label_x0 = Tk.Label(self.button_frame, text=" ") self.label_x0.pack(side=Tk.LEFT) # Fill list with available cameras and add to menu self.label_color_channels = Tk.Label(self.button_frame, text="Color channel:") self.label_color_channels.pack(side=Tk.LEFT) list_color_channels = [' ', 'R', 'G', 'B'] list_color_channels.pop(0) self.list_color_channelsStr = Tk.StringVar() self.dropDownListColorChannel = Tk.OptionMenu( self.button_frame, self.list_color_channelsStr, *list_color_channels) self.list_color_channelsStr.set(list_color_channels[0]) self.dropDownListColorChannel.pack(side=Tk.LEFT) # Add empty box self.label_x0 = Tk.Label(self.button_frame, text=" ") self.label_x0.pack(side=Tk.LEFT) # Add text boxes for ROI definition self.label_x1 = Tk.Label(self.button_frame, text="X Begin:") self.label_x1.pack(side=Tk.LEFT) self.textbox_x1 = Tk.Text(self.button_frame, width=6, height=1) self.textbox_x1.pack(side=Tk.LEFT) if settings.determine_if_under_testing() is False: self.textbox_x1.insert(Tk.END, self.x_min) self.label_x2 = Tk.Label(self.button_frame, text="X End:") self.label_x2.pack(side=Tk.LEFT) self.textbox_x2 = Tk.Text(self.button_frame, width=6, height=1) self.textbox_x2.pack(side=Tk.LEFT) if settings.determine_if_under_testing() is False: self.textbox_x2.insert(Tk.END, self.x_max) self.label_y1 = Tk.Label(self.button_frame, text="Y Begin:") self.label_y1.pack(side=Tk.LEFT) self.textbox_y1 = Tk.Text(self.button_frame, width=6, height=1) self.textbox_y1.pack(side=Tk.LEFT) if settings.determine_if_under_testing() is False: self.textbox_y1.insert(Tk.END, self.y_min) self.label_y2 = Tk.Label(self.button_frame, text="Y End:") self.label_y2.pack(side=Tk.LEFT) self.textbox_y2 = Tk.Text(self.button_frame, width=6, height=1) self.textbox_y2.pack(side=Tk.LEFT) if settings.determine_if_under_testing() is False: self.textbox_y2.insert(Tk.END, self.y_max) # Add empty box self.label_x0 = Tk.Label(self.button_frame, text=" ") self.label_x0.pack(side=Tk.LEFT) # Add button for option menu self.button_options = Tk.Button(self.button_frame, text="Options", width=5, command=self.__open_options_menu) self.button_options.pack(side=Tk.LEFT) # Disable text boxes when Viola-Jones algorithm is active if curr_settings[IDX_FACE]: self.check_button_1.toggle() self.textbox_x1.config(bg='lightgray') self.textbox_x2.config(bg='lightgray') self.textbox_y1.config(bg='lightgray') self.textbox_y2.config(bg='lightgray')
def run(self): """ This block is performed until the user ends the program""" # Has a connection been established to the camera or the hard disk? connection_established = False # When using frames from hard disk: Has the last file in the folder been reached? last_file_reached = False # run() method of cameraThread waits for shutdown event while self.eventProgramEnd.is_set() is False: # Timer for dynamic FPS adjustment self.startTime = datetime.datetime.now() # Check if the user wants to read frames from hard disk or from camera if self.files is not None: # Check if connection has been established if connection_established is False: # Check if the user has pressed the start button user_pressed_start = self.eventUserPressedStart.wait(1) if user_pressed_start: logging.info( "User pressed start and wants to use frames from hard disk" ) # Create variable to adjust thread sleeping time to desired FPS self.currSettings, _ = settings.get_parameters() self.FPS = self.currSettings[IDX_FPS] # Set event for other threads self.eventVideoReady.set() # Set bool variable, so that the thread can start to capture frames connection_established = True # Continuously capture frames until user ends program if self.eventVideoReady.is_set(): try: # Construct file directory and name curr_file = self.filesDir + os.sep + self.files[ self.frameCounter] # Read frame self.currentFrame = cv2.imread(curr_file) # Increase counter self.frameCounter += 1 except IndexError: # Print info to logging only once if last_file_reached is False: logging.info("Reached last file.") last_file_reached = True # Wait and start from beginning of thread self.__wait_to_adjust_fps(self.startTime, datetime.datetime.now()) # If the user did not choose frames from hard disk, use camera instead else: # Check if connection has been established if connection_established is False: # Check if the user has pressed the start button user_pressed_start = self.eventUserPressedStart.wait(1) if user_pressed_start: logging.info( "User pressed start and wants to use the camera") # Create variable to adjust thread sleeping time to desired FPS self.currSettings, _ = settings.get_parameters() self.FPS = self.currSettings[IDX_FPS] # Open connection to camera self.__open_camera() # Set event for other threads self.eventVideoReady.set() # Set bool variable, so that the thread can start to capture frames connection_established = True # Timer for dynamic FPS adjustment self.startTime = datetime.datetime.now() # Continuously capture frames until user ends program if self.eventVideoReady.is_set(): # Read frame ret, self.currentFrame = self.videoStream.read() # Wait and start from beginning of thread self.__wait_to_adjust_fps(self.startTime, datetime.datetime.now()) # Break if last file is reached if last_file_reached: break # Shutdown reached: Close connection to camera if it was used if self.files is None: self.__close_camera()
def __show_image(self): """Get frame from camera and display it""" # Get current settings self.curr_settings, _ = settings.get_parameters() # Get current frame self.isTrueFrame, self.frame = self.cameraInstance.get_frame() # Check if first frame is received if self.isTrueFrame & self.first_frame: # Disable RGB selection button self.roiToolbarInstance.disable_color_channel_selection_and_options( ) # If first frame from camera is received store dimensions x_max = np.size(self.frame, 0) y_max = np.size(self.frame, 1) self.roiToolbarInstance.set_roi(0, x_max, 0, y_max) self.first_frame = False self.frameCounter += 1 logging.info( "First frame from webcam was received and ROI was adjusted") # If first frame from camera is received and the user wants to store frames, create folder if self.curr_settings[IDX_FRAMES]: self.directory = os.path.join( os.getcwd(), 'data', datetime.datetime.now().strftime('%Y-%m-%d_%H.%M.%S')) # for window compatibility, colon has been replaced by dot os.makedirs(self.directory) logging.info('Folder was created for storing frames') # Process all following frames elif self.isTrueFrame: # Increase frame counter self.frameCounter += 1 # Use Viola Jones Algorithm for Face Detection if self.curr_settings[IDX_FACE]: frame_bw = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) faces = self.faceCascade.detectMultiScale( frame_bw, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags=cv2.cv.CV_HAAR_SCALE_IMAGE) for (x, y, w, h) in faces: cv2.rectangle(self.frame, (x, y), (x + w, y + h), (0, 255, 0), 2) self.roiToolbarInstance.set_roi(y, y + h, x, x + w) # Otherwise: Use manual ROI input else: x_min, x_max, y_min, y_max = self.roiToolbarInstance.get_roi() cv2.rectangle(self.frame, (y_min, x_min), (y_max, x_max), (0, 255, 0), 2) # Store frame on hard disk if self.curr_settings[IDX_FRAMES]: file_name = "frame%d.jpg" % self.frameCounter cv2.imwrite(os.path.join(self.directory, file_name), cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)) # Display icon current_location = os.path.dirname(os.path.realpath(__file__)) + os.sep # Heart icon if self.curr_settings[IDX_ALGORITHM] in (0, 2): # Add heart icon heart_location = current_location + 'data/heart.png' self.frame = self.__add_figure_to_frame(self.frame, heart_location) # Add text that displays Heart Rate cv2.putText(self.frame, self.HeartRateText, (25, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) # Heartbeat icon elif self.curr_settings[IDX_ALGORITHM] == 1: # If signal processing algorithm set trigger event if self.eventShowTrigger.is_set(): # Counter used to decide how long icon is shown self.counterShownTriggerSymbol += 1 # Add heart icon heart_location = current_location + 'data/heartbeat.png' self.frame = self.__add_figure_to_frame( self.frame, heart_location) # Clear event if symbol has been shown for approx 1/3 sec if self.counterShownTriggerSymbol >= self.FPS / 3: self.counterShownTriggerSymbol = 0 self.eventShowTrigger.clear() # Display frame if settings.determine_if_under_testing() is False: self.frameConverted = Image.fromarray(self.frame) self.imgTK = ImageTk.PhotoImage(image=self.frameConverted) self.lmain.imgtk = self.imgTK self.lmain.configure(image=self.imgTK) # Update values in statusbar self.statusbarInstance.set_frame_counter(self.get_frame_counter()) self.statusbarInstance.set_fps_counter(self.FPS) # Repeat thread immediately self.video_frame.after(1, lambda: self.__show_image())
import os import re import math import textwrap from itertools import accumulate import settings settings = settings.get_parameters() def get_text_from_file(file_path): """ Returns contents of text file as a list :param file_path: Absolute path to the file :return: Contents of the file as a string """ with open(file_path, 'r') as file: text = file.read() return text def get_info_lines(text): """ Gets research name from block of text :param text: Python string, in the program defined as block :return: Program name """ text_lines = [] for row in text.splitlines(): if "____" in row: return text_lines