From db476fbce2067a8675e61cafa274ee8532d997aa Mon Sep 17 00:00:00 2001 From: Jonathan Frei Date: Thu, 11 Jan 2024 12:52:43 +0000 Subject: [PATCH] =?UTF-8?q?Testauswertung=20zusammengef=C3=BChrt=20und=20i?= =?UTF-8?q?n=20den=20Testablauf=20integriert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In excel_processing habe ich nur den Funktionsaufruf der Evaluation hinzugefügt, die evaluation enthält die Funktionalitäten aus dem Testauswertung-Ordner --- code/excel_evaluation.py | 151 ++++++++++++++++++++++ code/excel_processing.py | 271 ++++++++++++++++++++------------------- 2 files changed, 290 insertions(+), 132 deletions(-) create mode 100644 code/excel_evaluation.py diff --git a/code/excel_evaluation.py b/code/excel_evaluation.py new file mode 100644 index 0000000..c0004e9 --- /dev/null +++ b/code/excel_evaluation.py @@ -0,0 +1,151 @@ +import openpyxl + +def excel_row_to_string(file_path): + # Öffne die Excel-Datei + workbook = openpyxl.load_workbook(file_path) + + # Wähle das Arbeitsblatt aus + sheet = workbook['Sheet1'] + + # Erhalte die angegebene Zeile als Liste von Zellen + row_values = [cell.value for cell in sheet[2]] + + # Ergebnisse werden ab Spalte 5 eingetragen + selected_columns = list(range(4, len(row_values))) + + # Wähle nur die gewünschten Spalten aus + selected_values = [row_values[col] for col in selected_columns] + + # Schließe die Excel-Datei + workbook.close() + + # Konvertiere die Liste von Zellen in einen String + row_string = ', '.join(str(value) for value in selected_values) + + return row_string + +def write_subdivided_string_to_excel(file_path, input_string): + # Öffne die Excel-Datei + workbook = openpyxl.load_workbook(file_path) + + # Wähle das Arbeitsblatt aus + sheet = workbook['Sheet1'] + + # Teile den String nach jedem Komma auf + parts = input_string.split(',') + + # Trage jeden Teil des Strings in eine neue Zeile ein + for i, part in enumerate(parts, 1): + + #Spalte 17 kann sich je nach Tabellenstruktur ändern! + sheet.cell(row=2 + i - 1, column=17, value=part.strip()) # strip entfernt mögliche Leerzeichen + + # Speichere die Änderungen + workbook.save(file_path) + + # Schließe die Excel-Datei + workbook.close() + +def read_columns(file_path): + # Öffne die Excel-Datei + workbook = openpyxl.load_workbook(file_path) + + # Wähle das Arbeitsblatt aus + sheet = workbook['Sheet1'] + + # Lese die Werte der beiden Spalten aus + values_column1 = [cell.value for cell in sheet['O']][1:] + values_column2 = [cell.value for cell in sheet['Q']][1:] + + # Schließe die Excel-Datei + workbook.close() + + return values_column1, values_column2 + +def calculate_deviation(liste1, liste2): + # Überprüfe, ob die Listen die gleiche Länge haben + if len(liste1) != len(liste2): + raise ValueError("Die Listen müssen die gleiche Länge haben") + + # Berechne die prozentuale Abweichung zwischen den Werten + deviations = [((abs(float(b) - float(a)) / float(a)) * 100) if float(a) != 0 else None for a, b in zip(liste1, liste2)] + + return deviations + +def write_string_to_excel(file_path, input_string, column): + # Öffne die Excel-Datei + workbook = openpyxl.load_workbook(file_path) + + # Wähle das Arbeitsblatt aus + sheet = workbook['Sheet1'] + + # Trage jeden Buchstaben des Strings in eine eigene Zeile ein + for i, char in enumerate(input_string, 1): + sheet.cell(row=2 + i - 1, column=column, value=char) + + # Speichere die Änderungen + workbook.save(file_path) + + # Schließe die Excel-Datei + workbook.close() + +def copy_header(input_sheet, output_sheet): + # Kopiere den Header manuell in das Ausgabe-Arbeitsblatt + for row in input_sheet.iter_rows(min_row=1, max_row=1, values_only=True): + output_sheet.append(row) + +def sort_excel(input_file_path, output_file_path, ): + # Öffne die Eingabe-Excel-Datei + input_workbook = openpyxl.load_workbook(input_file_path) + input_sheet = input_workbook['Sheet1'] + + # Erstelle eine neue Excel-Tabelle für die sortierten Zeilen + output_workbook = openpyxl.Workbook() + output_sheet = output_workbook.active + + # Kopiere den Header ins Ausgabe-Arbeitsblatt + copy_header(input_sheet, output_sheet) + + # Lese die Daten-Zeilen aus der Tabelle + data_rows = list(input_sheet.iter_rows(min_row=2, values_only=True)) + + # Sortiere die Daten-Zeilen nach dem Wert der angegebenen Spalte + sorted_data_rows = sorted(data_rows, key=lambda x: x[18 - 1]) # -1, da Listenindizes bei 0 beginnen + + # Schreibe die sortierten Daten-Zeilen in die neue Tabelle + for row in sorted_data_rows: + output_sheet.append(row) + + # Speichere die Änderungen in der neuen Excel-Datei + output_workbook.save(output_file_path) + + # Schließe die Excel-Dateien + input_workbook.close() + output_workbook.close() + + +#Sollten mehrere Testruns ausgewertet werden wollen, müssen die enthaltenen Funktionen umstrukturiert werden +#Aktuell wird nur der Testrun in Zeile 1 ausgewertet +#Eine Weitere Funktion, die zwei Tabellenzeilen tauscht, wäre der einfachste workaround +def evaluation(testcases, testruns): + + #liest die Ergebnisse des Testruns aus + #bei mehreren Testruns muss diese Funktion angepasst werden! + input_string = excel_row_to_string(testruns) + + #schreibt die Berechneten Ergebnisse in die Testcases-Tabelle + write_subdivided_string_to_excel(testcases, input_string) + + #liest die gemessenen und die errechneten Werte aus den Testcases + values_col1, values_col2 = read_columns(testcases) + + #berechnet aus diesen Werten die prozentuale Abweichung + deviations = calculate_deviation(values_col1, values_col2) + + #Trägt die prozentualen Abweichungen in die Testcases-Tabelle + #je nach Tabellenstruktur kann sich die 18 ändern! + write_string_to_excel(testcases, deviations, 18) + + #Gibt die eine Kopie der Testcases-Tabelle sortiert nach Genauigkeit aus + sort_excel(testcases, 'Testcases_nach_Genauigkeit.xlsx') + diff --git a/code/excel_processing.py b/code/excel_processing.py index 4f0b167..128c4a6 100644 --- a/code/excel_processing.py +++ b/code/excel_processing.py @@ -1,132 +1,139 @@ -""" -Abhängigkeiten: -- pyramids (für den Aufbau der Bildpyramiden) -- heartrate (zur Berechnung der Herzfrequenz) -- preprocessing (für die Video-Vorverarbeitung) -- eulerian (für die Euler'sche Video-Magnifikation) -- tkinter und constants (für die GUI und Konstantenverwaltung) - -Autor: Roberto Gelsinger -Datum: 07.12.2023 -Version: Modulversion -""" - -import pyramids -import heartrate -import facedetection -import eulerian -from constants import freq_max, freq_min -import pandas as pd -from excel_update import color_cells_based_on_deviation - - -def process_video_for_excel(selected_video_name): - """ - Verarbeitet ein ausgewähltes Video, um die Herzfrequenz der abgebildeten Person zu ermitteln. - - Dieser Prozess umfasst die Vorverarbeitung des Videos, den Aufbau einer Laplace-Pyramide, - die Anwendung von FFT-Filterung und Euler'scher Magnifikation, und schließlich die Berechnung - der Herzfrequenz aus den Video-Daten. - - Args: - selected_video_name (str): Der Name des zu verarbeitenden Videos. - - Returns: - None: Die Funktion gibt direkt die berechnete Herzfrequenz auf der Konsole aus. - """ - - - - print("Reading + preprocessing video...") - video_frames, frame_ct, fps = facedetection.read_video("videos/"+selected_video_name) - - - print("Building Laplacian video pyramid...") - lap_video = pyramids.build_video_pyramid(video_frames) - - - - for i, video in enumerate(lap_video): - if i == 0 or i == len(lap_video)-1: - continue - - print("Running FFT and Eulerian magnification...") - result, fft, frequencies = eulerian.fft_filter(video, freq_min, freq_max, fps) - lap_video[i] += result - - - print("Calculating heart rate...") - heart_rate = heartrate.find_heart_rate(fft, frequencies, freq_min, freq_max) - - - - - - print("Heart rate: ", heart_rate*0.7, "bpm") - return heart_rate *0.7 - - - -def process_all_videos_and_save_results(testcase_excel_file_path, testruns_excel_file_path, code_version, kommentar): - - try: - df_testruns = pd.read_excel(testruns_excel_file_path) - except FileNotFoundError: - df_testruns = pd.DataFrame() - - - df_testcases = pd.read_excel(testcase_excel_file_path) - - existing_testcases = [col for col in df_testruns.columns if col.startswith('Testcase_')] - - new_testcases = [f'Testcase_{tc}' for tc in df_testcases['Testcase'] if f'Testcase_{tc}' not in existing_testcases] - - - if df_testruns.empty: - df_testruns = pd.DataFrame(columns=['Testnummer', 'Codeversion', 'Kommentar', 'Abweichung']) - - - for col in new_testcases: - df_testruns[col] = None - - - df_testruns.to_excel(testruns_excel_file_path, index=False) - - if new_testcases: - print(f"Folgende neue Testcases wurden hinzugefügt: {new_testcases}") - else: - print("Keine neuen Testcases zum Hinzufügen gefunden.") - - next_testcase_index = len(df_testruns) + 1 - - - new_run = { - 'Testnummer': next_testcase_index, - 'Codeversion': code_version, - 'Kommentar': kommentar, - 'Abweichung': 'Wert_für_Abweichung' - } - - - for index, row in df_testcases.iterrows(): - video_name = row['VideoName'] - heart_rate = process_video_for_excel(video_name) - - - testcase_column_name = f'Testcase_{row["Testcase"]}' - new_run[testcase_column_name] = heart_rate - - try: - - df_testruns = df_testruns._append(new_run, ignore_index=True) - except TypeError: - pass - - - df_testruns.to_excel(testruns_excel_file_path, index=False) - - print("Testrun wurde verarbeitet und das Ergebnis in der Testruns-Excel-Datei gespeichert.") - - color_cells_based_on_deviation(testruns_excel_file_path, testcase_excel_file_path) - - print("Zellen gefärbt") \ No newline at end of file +""" +Abhängigkeiten: +- pyramids (für den Aufbau der Bildpyramiden) +- heartrate (zur Berechnung der Herzfrequenz) +- preprocessing (für die Video-Vorverarbeitung) +- eulerian (für die Euler'sche Video-Magnifikation) +- tkinter und constants (für die GUI und Konstantenverwaltung) + +Autor: Roberto Gelsinger +Datum: 07.12.2023 +Version: Modulversion +""" + +import pyramids +import heartrate +import facedetection +import eulerian +from constants import freq_max, freq_min +import pandas as pd +from excel_update import color_cells_based_on_deviation +from excel_evaluation import evaluation + + +def process_video_for_excel(selected_video_name): + """ + Verarbeitet ein ausgewähltes Video, um die Herzfrequenz der abgebildeten Person zu ermitteln. + + Dieser Prozess umfasst die Vorverarbeitung des Videos, den Aufbau einer Laplace-Pyramide, + die Anwendung von FFT-Filterung und Euler'scher Magnifikation, und schließlich die Berechnung + der Herzfrequenz aus den Video-Daten. + + Args: + selected_video_name (str): Der Name des zu verarbeitenden Videos. + + Returns: + None: Die Funktion gibt direkt die berechnete Herzfrequenz auf der Konsole aus. + """ + + + + print("Reading + preprocessing video...") + video_frames, frame_ct, fps = facedetection.read_video("videos/"+selected_video_name) + + print(len(video_frames)) + + print("Building Laplacian video pyramid...") + lap_video = pyramids.build_video_pyramid(video_frames) + + print(len(lap_video)) + + for i, video in enumerate(lap_video): + print("test") + if i == 0 or i == len(lap_video)-1: + continue + + print("Running FFT and Eulerian magnification...") + result, fft, frequencies = eulerian.fft_filter(video, freq_min, freq_max, fps) + lap_video[i] += result + + + print("Calculating heart rate...") + heart_rate = heartrate.find_heart_rate(fft, frequencies, freq_min, freq_max) + + + + + + print("Heart rate: ", heart_rate*0.7, "bpm") + return heart_rate *0.7 + + + +def process_all_videos_and_save_results(testcase_excel_file_path, testruns_excel_file_path, code_version, kommentar): + + try: + df_testruns = pd.read_excel(testruns_excel_file_path) + except FileNotFoundError: + df_testruns = pd.DataFrame() + + + df_testcases = pd.read_excel(testcase_excel_file_path) + + existing_testcases = [col for col in df_testruns.columns if col.startswith('Testcase_')] + + new_testcases = [f'Testcase_{tc}' for tc in df_testcases['Testcase'] if f'Testcase_{tc}' not in existing_testcases] + + + if df_testruns.empty: + df_testruns = pd.DataFrame(columns=['Testnummer', 'Codeversion', 'Kommentar', 'Abweichung']) + + + for col in new_testcases: + df_testruns[col] = None + + + df_testruns.to_excel(testruns_excel_file_path, index=False) + + if new_testcases: + print(f"Folgende neue Testcases wurden hinzugefügt: {new_testcases}") + else: + print("Keine neuen Testcases zum Hinzufügen gefunden.") + + next_testcase_index = len(df_testruns) + 1 + + + new_run = { + 'Testnummer': next_testcase_index, + 'Codeversion': code_version, + 'Kommentar': kommentar, + 'Abweichung': 'Wert_für_Abweichung' + } + + + for index, row in df_testcases.iterrows(): + video_name = row['VideoName'] + heart_rate = process_video_for_excel(video_name) + + + testcase_column_name = f'Testcase_{row["Testcase"]}' + new_run[testcase_column_name] = heart_rate + + try: + + df_testruns = df_testruns._append(new_run, ignore_index=True) + except TypeError: + pass + + + df_testruns.to_excel(testruns_excel_file_path, index=False) + + print("Testrun wurde verarbeitet und das Ergebnis in der Testruns-Excel-Datei gespeichert.") + + color_cells_based_on_deviation(testruns_excel_file_path, testcase_excel_file_path) + + print("Zellen gefärbt") + + evaluation(testcase_excel_file_path, testruns_excel_file_path) + + print("Testcases sortiert") \ No newline at end of file