diff --git a/.gitignore b/.gitignore index 592b2fb..317f5c0 100644 --- a/.gitignore +++ b/.gitignore @@ -72,7 +72,8 @@ temp/ venv* *.dmg *.spec -!examples/ear_score.csv +!examples/*.csv +!examples/*.mp4 paper/paper.jats paper/paper.pdf diff --git a/examples/ear_score.csv b/examples/ear_score_240.csv similarity index 100% rename from examples/ear_score.csv rename to examples/ear_score_240.csv diff --git a/examples/ear_score_30.csv b/examples/ear_score_30.csv new file mode 100644 index 0000000..e975fde --- /dev/null +++ b/examples/ear_score_30.csv @@ -0,0 +1,251 @@ +frame,EAR2D6_l,EAR2D6_r,EAR2D6_valid,BS_Valid +0, 0.30839515, 0.31717056,True,True +1, 0.30697849, 0.31643425,True,True +2, 0.31780323, 0.32533049,True,True +3, 0.31657635, 0.31336477,True,True +4, 0.31764210, 0.31694362,True,True +5, 0.31386926, 0.31409277,True,True +6, 0.31484655, 0.31612779,True,True +7, 0.30915708, 0.31312242,True,True +8, 0.30693714, 0.31124881,True,True +9, 0.30799023, 0.31312242,True,True +10, 0.30571419, 0.30799125,True,True +11, 0.30042486, 0.30502849,True,True +12, 0.28607607, 0.30721214,True,True +13, 0.30121833, 0.30183604,True,True +14, 0.29187137, 0.30210629,True,True +15, 0.29767902, 0.29821654,True,True +16, 0.29061937, 0.30378166,True,True +17, 0.29875644, 0.29564100,True,True +18, 0.29875644, 0.30551011,True,True +19, 0.30571419, 0.29564100,True,True +20, 0.29262141, 0.29620622,True,True +21, 0.29262141, 0.29330723,True,True +22, 0.27219442, 0.27695657,True,True +23, 0.01769842, 0.01282979,True,True +24, 0.01231288, 0.02070684,True,True +25, 0.02101940, 0.01370297,True,True +26, 0.04426898, 0.02246624,True,True +27, 0.03302003, 0.00803064,True,True +28, 0.07497124, 0.02872804,True,True +29, 0.19807905, 0.19991081,True,True +30, 0.23124061, 0.24272208,True,True +31, 0.25739383, 0.26800041,True,True +32, 0.26600419, 0.27675620,True,True +33, 0.26620216, 0.28076742,True,True +34, 0.27219442, 0.28631641,True,True +35, 0.27817795, 0.28247069,True,True +36, 0.27817795, 0.28490235,True,True +37, 0.27819434, 0.28490235,True,True +38, 0.28417787, 0.29053216,True,True +39, 0.28076650, 0.29130211,True,True +40, 0.29126256, 0.29442629,True,True +41, 0.29036380, 0.29442629,True,True +42, 0.28054342, 0.28490235,True,True +43, 0.28688787, 0.29672592,True,True +44, 0.28076650, 0.29109611,True,True +45, 0.28670108, 0.28816167,True,True +46, 0.28076650, 0.28816167,True,True +47, 0.28417787, 0.29109611,True,True +48, 0.28784117, 0.29340709,True,True +49, 0.28790582, 0.29821654,True,True +50, 0.28435252, 0.29672592,True,True +51, 0.28076650, 0.29055364,True,True +52, 0.06502978, 0.03658265,True,True +53, 0.02024917, 0.02625834,True,True +54, 0.02000166, 0.01876873,True,True +55, 0.00874105, 0.02432521,True,True +56, 0.01492190, 0.02768382,True,True +57, 0.00863546, 0.02092892,True,True +58, 0.01492190, 0.03351722,True,True +59, 0.01236170, 0.01641662,True,True +60, 0.01233816, 0.01856745,True,True +61, 0.01831858, 0.00802237,True,True +62, 0.04230399, 0.00000000,True,True +63, 0.06181197, 0.02005528,True,True +64, 0.20705129, 0.22071539,True,True +65, 0.24511024, 0.24825420,True,True +66, 0.26281608, 0.27651996,True,True +67, 0.27138363, 0.28679968,True,True +68, 0.27138363, 0.29316770,True,True +69, 0.29029085, 0.30401200,True,True +70, 0.29152860, 0.30015060,True,True +71, 0.29287058, 0.30957440,True,True +72, 0.27435362, 0.29465200,True,True +73, 0.27774988, 0.29391477,True,True +74, 0.29281205, 0.29593631,True,True +75, 0.28205807, 0.30210629,True,True +76, 0.28360660, 0.29316770,True,True +77, 0.28491334, 0.30566975,True,True +78, 0.29736310, 0.29793630,True,True +79, 0.28449054, 0.30401200,True,True +80, 0.28346620, 0.30158417,True,True +81, 0.28915019, 0.29647832,True,True +82, 0.28346620, 0.28974773,True,True +83, 0.29029085, 0.29873282,True,True +84, 0.29520791, 0.29873282,True,True +85, 0.29047551, 0.30129435,True,True +86, 0.28481250, 0.29235676,True,True +87, 0.29038721, 0.30075286,True,True +88, 0.29399576, 0.29478969,True,True +89, 0.28474855, 0.29793630,True,True +90, 0.29544620, 0.29760003,True,True +91, 0.29047551, 0.29761966,True,True +92, 0.29734401, 0.30129435,True,True +93, 0.30882459, 0.30856107,True,True +94, 0.30317851, 0.30566975,True,True +95, 0.29734401, 0.30210629,True,True +96, 0.29985247, 0.30129435,True,True +97, 0.29991155, 0.30691690,True,True +98, 0.29411627, 0.30639529,True,True +99, 0.29736310, 0.30210629,True,True +100, 0.30554130, 0.32070147,True,True +101, 0.30754054, 0.31882648,True,True +102, 0.31910433, 0.32414189,True,True +103, 0.28094941, 0.27651996,True,True +104, 0.01744879, 0.02406710,True,True +105, 0.02247274, 0.03177595,True,True +106, 0.00860217, 0.03313757,True,True +107, 0.03164379, 0.01356214,True,True +108, 0.06768018, 0.01817901,True,True +109, 0.20271529, 0.22393133,True,True +110, 0.24316228, 0.25774618,True,True +111, 0.26001681, 0.28631641,True,True +112, 0.28056569, 0.28220608,True,True +113, 0.28056569, 0.29362676,True,True +114, 0.27485479, 0.29931613,True,True +115, 0.28094941, 0.29305686,True,True +116, 0.26910210, 0.28466462,True,True +117, 0.27036253, 0.28789544,True,True +118, 0.27151763, 0.27901948,True,True +119, 0.27870788, 0.29593631,True,True +120, 0.28456170, 0.29593631,True,True +121, 0.28913736, 0.29388577,True,True +122, 0.28790582, 0.30129435,True,True +123, 0.29387780, 0.30158417,True,True +124, 0.29047551, 0.30639529,True,True +125, 0.29152860, 0.30639529,True,True +126, 0.29387249, 0.30034817,True,True +127, 0.29174260, 0.30349620,True,True +128, 0.29174260, 0.30202917,True,True +129, 0.29274450, 0.30152513,True,True +130, 0.29876218, 0.30924539,True,True +131, 0.28607607, 0.30349620,True,True +132, 0.28933412, 0.30017115,True,True +133, 0.29876218, 0.31084737,True,True +134, 0.28156328, 0.30535200,True,True +135, 0.29876218, 0.31084737,True,True +136, 0.30084331, 0.30034817,True,True +137, 0.28824583, 0.30265839,True,True +138, 0.28947251, 0.29738223,True,True +139, 0.28476367, 0.29465200,True,True +140, 0.29399576, 0.30616180,True,True +141, 0.28122135, 0.29793630,True,True +142, 0.08696232, 0.07316529,True,True +143, 0.00872440, 0.02460670,True,True +144, 0.01941004, 0.02893588,True,True +145, 0.02526354, 0.03793540,True,True +146, 0.02328699, 0.04282244,True,True +147, 0.01221239, 0.01796818,True,True +148, 0.03546387, 0.00549417,True,True +149, 0.11005832, 0.05299722,True,True +150, 0.22507869, 0.22884677,True,True +151, 0.24808096, 0.25126705,True,True +152, 0.26451688, 0.28204309,True,True +153, 0.26857695, 0.28416769,True,True +154, 0.27301256, 0.28416769,True,True +155, 0.27997872, 0.28442911,True,True +156, 0.28101880, 0.28939994,True,True +157, 0.27989908, 0.28838177,True,True +158, 0.27870788, 0.29340709,True,True +159, 0.29038721, 0.29316770,True,True +160, 0.27761239, 0.28227340,True,True +161, 0.26704718, 0.28760540,True,True +162, 0.26704718, 0.28281947,True,True +163, 0.26590579, 0.28760540,True,True +164, 0.28326359, 0.28204309,True,True +165, 0.27880359, 0.27729200,True,True +166, 0.27286259, 0.28416769,True,True +167, 0.26590579, 0.28416769,True,True +168, 0.28248591, 0.28733513,True,True +169, 0.27448633, 0.27867187,True,True +170, 0.27566412, 0.28389907,True,True +171, 0.27556948, 0.28442911,True,True +172, 0.27870788, 0.28389907,True,True +173, 0.27884592, 0.28416769,True,True +174, 0.26715126, 0.28913396,True,True +175, 0.27424381, 0.29465200,True,True +176, 0.26278444, 0.28389907,True,True +177, 0.27884592, 0.28122140,True,True +178, 0.26965958, 0.28706944,True,True +179, 0.27884592, 0.29031120,True,True +180, 0.27556948, 0.28706944,True,True +181, 0.28467151, 0.28132200,True,True +182, 0.27435362, 0.28939994,True,True +183, 0.25727224, 0.26536923,True,True +184, 0.02088370, 0.01338259,True,True +185, 0.01360123, 0.01368535,True,True +186, 0.01218968, 0.02069220,True,True +187, 0.01489348, 0.02813706,True,True +188, 0.01208685, 0.01339907,True,True +189, 0.06587889, 0.02260906,True,True +190, 0.07325627, 0.03493840,True,True +191, 0.21407690, 0.22462453,True,True +192, 0.24230951, 0.24911082,True,True +193, 0.26417941, 0.27670971,True,True +194, 0.26573676, 0.27592677,True,True +195, 0.27774988, 0.29235676,True,True +196, 0.27448633, 0.28363814,True,True +197, 0.26603749, 0.28363814,True,True +198, 0.27894167, 0.28387229,True,True +199, 0.27190170, 0.28493478,True,True +200, 0.27448633, 0.28733513,True,True +201, 0.27774988, 0.28883339,True,True +202, 0.28933412, 0.29235676,True,True +203, 0.28607607, 0.28915618,True,True +204, 0.28593776, 0.29492306,True,True +205, 0.28028817, 0.28966629,True,True +206, 0.27566412, 0.28957076,True,True +207, 0.27661347, 0.29143903,True,True +208, 0.26603749, 0.28915618,True,True +209, 0.27904043, 0.28913396,True,True +210, 0.28499447, 0.29465200,True,True +211, 0.27566412, 0.29813491,True,True +212, 0.27674727, 0.29465200,True,True +213, 0.27566412, 0.28363814,True,True +214, 0.28607607, 0.29465200,True,True +215, 0.27129853, 0.29194358,True,True +216, 0.28810647, 0.29543364,True,True +217, 0.28476367, 0.28671125,True,True +218, 0.28132988, 0.29170131,True,True +219, 0.28217403, 0.29220632,True,True +220, 0.28364877, 0.30042672,True,True +221, 0.28476367, 0.30304016,True,True +222, 0.28378281, 0.29687768,True,True +223, 0.28396498, 0.30566975,True,True +224, 0.28387867, 0.30017115,True,True +225, 0.29422187, 0.30233665,True,True +226, 0.28378281, 0.30233665,True,True +227, 0.28607607, 0.30616180,True,True +228, 0.07306278, 0.04001991,True,True +229, 0.01190308, 0.02002629,True,True +230, 0.01767767, 0.01979643,True,True +231, 0.02384842, 0.01097841,True,True +232, 0.03500224, 0.01201562,True,True +233, 0.14034599, 0.10153823,True,True +234, 0.20675459, 0.22546911,True,True +235, 0.24530257, 0.25126705,True,True +236, 0.24239267, 0.26500531,True,True +237, 0.26391243, 0.27287946,True,True +238, 0.25075540, 0.28025274,True,True +239, 0.27674727, 0.28389907,True,True +240, 0.26921031, 0.29143903,True,True +241, 0.27909436, 0.29714485,True,True +242, 0.27323818, 0.28154177,True,True +243, 0.27372611, 0.28974508,True,True +244, 0.26667730, 0.28667322,True,True +245, 0.27129853, 0.28688769,True,True +246, 0.26921031, 0.28736231,True,True +247, 0.27690214, 0.28432221,True,True +248, 0.27806570, 0.28974508,True,True +249, 0.26818388, 0.28227222,True,True diff --git a/examples/test_long.mp4 b/examples/test_long.mp4 new file mode 100644 index 0000000..d44581e Binary files /dev/null and b/examples/test_long.mp4 differ diff --git a/examples/test_short.mp4 b/examples/test_short.mp4 new file mode 100644 index 0000000..15dc3a8 Binary files /dev/null and b/examples/test_short.mp4 differ diff --git a/frontend/app.py b/frontend/app.py index 16f10f8..db097c5 100644 --- a/frontend/app.py +++ b/frontend/app.py @@ -7,7 +7,7 @@ import structlog from PyQt6 import QtGui -from PyQt6.QtWidgets import QMainWindow, QTabWidget, QProgressBar, QWidget +from PyQt6.QtWidgets import QMainWindow, QTabWidget, QProgressBar, QWidget, QMessageBox from frontend import config from .ui_facial_feature_extraction import FacialFeatureExtraction @@ -18,6 +18,29 @@ def add_space_between_words(text): return re.sub(r"(\w)([A-Z])", r"\1 \2", text) +LICENCE_TEXT = """ +JeFaPaTo is licensed under the MIT License. + +MIT License + +Copyright (c) [2023] [Tim Büchner] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" + class JeFaPaTo(QMainWindow, config.Config): def __init__(self, args: argparse.Namespace) -> None: """ @@ -61,6 +84,16 @@ def __init__(self, args: argparse.Namespace) -> None: self.statusBar().addPermanentWidget(self.progress_bar) + # Create menu bar + menu_bar = self.menuBar() + # Create Help menu + help_menu = menu_bar.addMenu("Help") + + help_menu.addAction("About", self.show_about) + help_menu.addAction("Documentation", self.show_documentation) + help_menu.addAction("License", self.show_license) + help_menu.addAction("Acknowledgements", self.show_acknowledgements) + def closeEvent(self, event: QtGui.QCloseEvent) -> None: """ Event handler for the close event of the application window. @@ -81,3 +114,64 @@ def closeEvent(self, event: QtGui.QCloseEvent) -> None: self.save() logger.info("Internal Shut Down complete", widget=self) super().closeEvent(event) + + def show_about(self): + """ + Shows the About dialog. + """ + ## use a dialog to show the about information + dialog = QMessageBox() + dialog.setWindowTitle("About JeFaPaTo") + dialog.setText("JeFaPaTo - Jena Facial Palsy Tool") + dialog.setInformativeText(""" + + """) + dialog.setStandardButtons(QMessageBox.StandardButton.Ok) + dialog.exec() + + def show_documentation(self): + """ + Shows the Documentation dialog. + """ + dialog = QMessageBox() + dialog.setWindowTitle("Documentation") + dialog.setText("Documentation") + dialog.setInformativeText(""" + Documentation is available at our wiki page. + """ + ) + dialog.setStandardButtons(QMessageBox.StandardButton.Ok) + dialog.exec() + + def show_license(self): + """ + Shows the License dialog. + """ + dialog = QMessageBox() + dialog.setWindowTitle("License") + dialog.setText("License") + dialog.setInformativeText(LICENCE_TEXT) + dialog.setStandardButtons(QMessageBox.StandardButton.Ok) + dialog.exec() + + def show_acknowledgements(self): + """ + Shows the Acknowledgements dialog. + """ + + dialog = QMessageBox() + dialog.setWindowTitle("Acknowledgements") + dialog.setText("Acknowledgements") + dialog.setInformativeText(""" + JeFaPaTo is based on the MediaPipe library by Google. + We would like to thank the developers for their great work and the possibility to use their library. + Additionally, we would like to thank the OpenCV team for their great work and the possibility to use their library. + Also, we thank our medical partners for their support and feedback. + """) + dialog.setStandardButtons(QMessageBox.StandardButton.Ok) + dialog.exec() diff --git a/frontend/gui_interface.py b/frontend/gui_interface.py index 6e3df51..218479f 100644 --- a/frontend/gui_interface.py +++ b/frontend/gui_interface.py @@ -23,6 +23,9 @@ def __init__(self, parent: QtWidgets.QWidget): self.parent = parent self.stopped = False + self.update_counter = 0 + self.update_interval = 10 + def run(self): while True: if self.stopped: @@ -31,10 +34,17 @@ def run(self): def stop(self): self.stopped = True + + def set_update_interval(self, interval: int): + self.update_interval = interval @facial_features.FaceAnalyzer.hookimpl def updated_display(self, image: np.ndarray): - self.sig_updated_display.emit(image) + self.update_counter += 1 + + if self.update_counter % self.update_interval == 0: + self.update_counter = 0 + self.sig_updated_display.emit(image) @facial_features.FaceAnalyzer.hookimpl def updated_feature(self, feature_data: OrderedDict[str, Any]) -> None: diff --git a/frontend/jwidgets/graph.py b/frontend/jwidgets/graph.py index 88469ff..7cc0721 100644 --- a/frontend/jwidgets/graph.py +++ b/frontend/jwidgets/graph.py @@ -17,7 +17,7 @@ def __init__(self, background="default", x_lim_max=1000, **kargs): self.plot_item.setLimits(xMin=0, xMax=x_lim_max) self.plot_item.setXRange(0, x_lim_max) - self.plot_item.setYRange(0, 1) + self.plot_item.setYRange(-0.05, 1) self.axis_b: pg.AxisItem = self.plot_item.getAxis("bottom") self.curves: list[pg.PlotDataItem] = [] diff --git a/frontend/jwidgets/videofacepreview.py b/frontend/jwidgets/videofacepreview.py index 5f73729..31a340e 100644 --- a/frontend/jwidgets/videofacepreview.py +++ b/frontend/jwidgets/videofacepreview.py @@ -32,24 +32,24 @@ def load_file(self, file_path: Path) -> np.ndarray: return self.get_frame(0) - def in_range(self, frame_number: int) -> bool: + def in_range(self, frame_index: int) -> bool: assert self.frame_count is not None - return frame_number >= 0 and frame_number < self.frame_count + return frame_index >= 0 and frame_index < self.frame_count - def get_frame(self, frame_number: int) -> np.ndarray: + def get_frame(self, frame_index: int) -> np.ndarray: assert self.resource is not None - self.resource.set(cv2.CAP_PROP_POS_FRAMES, frame_number) + self.resource.set(cv2.CAP_PROP_POS_FRAMES, frame_index) ret, frame = self.resource.read() if not ret: - logger.error("Could not read frame", frame_number=frame_number, file_path=self.file_path) + logger.error("Could not read frame", frame_index=frame_index, file_path=self.file_path) return np.zeros((300, 300, 3), dtype=np.uint8) frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame_g = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) faces = self.face_finder.detectMultiScale(frame_g, 1.1, 5) if len(faces) == 0: - logger.warning("Could not find face", frame_number=frame_number, file_path=self.file_path) + logger.warning("Could not find face", frame_index=frame_index, file_path=self.file_path) return frame x, y, w, h = faces[0] diff --git a/frontend/ui_eye_blinking_extraction.py b/frontend/ui_eye_blinking_extraction.py index a0d5b26..277df2f 100644 --- a/frontend/ui_eye_blinking_extraction.py +++ b/frontend/ui_eye_blinking_extraction.py @@ -7,6 +7,7 @@ import pyqtgraph as pg from qtpy import QtCore, QtGui, QtWidgets +from qtpy.QtWidgets import QMessageBox, QLabel from PyQt6.QtCore import pyqtSignal from jefapato import blinking @@ -14,6 +15,36 @@ logger = structlog.get_logger() +#### Recommended Extracton Settings for Eye Blinking #### +# @30 FPS +# Minimum Distance: 10 Frames +# Minimum Prominence: 0.1 EAR Score +# Minimum Internal Width: 4 Frames +# Maximum Internal Width: 20 Frames +# Maximum Matching Distance: 15 Frames +# Partial Threshold Left: 0.18 EAR Score +# Partial Threshold Right: 0.18 EAR Score +# +# Smoothing +# - Window Size: 7 +# - Polynomial Degree: 3 +# +# --- +# +# @240 FPS +# Minimum Distance: 50 Frames +# Minimum Prominence: 0.1 EAR Score +# Minimum Internal Width: 20 Frames +# Maximum Internal Width: 100 Frames +# Maximum Matching Distance: 30 Frames +# Partial Threshold Left: 0.18 EAR Score +# Partial Threshold Right: 0.18 EAR Score +# +# Smoothing +# - Window Size: 7 +# - Polynomial Degree: 3 + + DOWNSAMPLE_FACTOR = 8 def to_float(value: str) -> float: @@ -75,6 +106,21 @@ def sec_to_min(seconds: float) -> str: seconds = int(seconds % 60) return f"{minutes:02d}:{seconds:02d}" +def create_help_button(tooltip: str, win=None) -> QtWidgets.QPushButton: + """ + Create a help button with the given tooltip. + + Args: + tooltip (str): The tooltip text to be displayed when hovering over the button. + win (QtWidgets.QWidget, optional): The parent widget for the help button. Defaults to None. + + Returns: + QtWidgets.QPushButton: The created help button. + """ + help_btn = QtWidgets.QPushButton(qta.icon("fa5s.question-circle"), "") + help_btn.setToolTip(tooltip) + help_btn.clicked.connect(lambda: QMessageBox.information(win, "Help", tooltip)) + return help_btn # TODO just make this a normal widget and not a splitter class EyeBlinkingExtraction(QtWidgets.QSplitter, config.Config): @@ -110,7 +156,7 @@ def __init__(self, parent): self.scatter_l_part = self.graph.add_scatter() self.scatter_r_part = self.graph.add_scatter() - # UI elements + # UI elements self.setOrientation(QtCore.Qt.Orientation.Horizontal) self.setAcceptDrops(True) @@ -147,7 +193,7 @@ def __init__(self, parent): # second tab is the text information self.table_summary = jwidgets.JTableSummary() - + self.graph_summary_visual = pg.GraphicsLayoutWidget() self.summary_visual = pg.ViewBox(invertY=True, lockAspect=True, enableMenu=True, enableMouse=True) self.summary_visual_image = pg.ImageItem() @@ -192,8 +238,8 @@ def __init__(self, parent): self.box_settings = QtWidgets.QGroupBox("Algorithm Settings") # dont make the groupbox changeable in height self.box_settings.setMinimumHeight(200) - self.set_algo = QtWidgets.QFormLayout() - + self.set_algo = QtWidgets.QGridLayout() + local = QtCore.QLocale(QtCore.QLocale.Language.English, QtCore.QLocale.Country.UnitedStates) doulbe_validator = QtGui.QDoubleValidator() doulbe_validator.setBottom(0) @@ -205,45 +251,74 @@ def __init__(self, parent): int_validator.setBottom(0) int_validator.setLocale(local) + extraction_help_button = QtWidgets.QPushButton("Eye Blinking Extraction Help Description") + extraction_help_button.clicked.connect(lambda: QMessageBox.information(None, "Help", blinking.HELP_DESCRIPTION)) + self.set_algo.addWidget(extraction_help_button, 0, 0, 1, 3) + le_minimum_distance = QtWidgets.QLineEdit() le_minimum_distance.setValidator(int_validator) self.add_handler("min_dist", le_minimum_distance, mapper=I2S, default=50) - self.set_algo.addRow("Minimum Distance", le_minimum_distance) + + self.set_algo.addWidget(QLabel("Minimum Distance"), 1, 0) + self.set_algo.addWidget(le_minimum_distance, 1, 1) + self.set_algo.addWidget(create_help_button("Minimum Distance: The minimum distance between two peaks in frames. Rec: 10@30FPS, 50@240FPS"), 1, 2) le_minimum_prominence = QtWidgets.QLineEdit() le_minimum_prominence.setValidator(doulbe_validator) self.add_handler("min_prominence", le_minimum_prominence, mapper=F2S, default=0.1) - self.set_algo.addRow("Minimum Prominence", le_minimum_prominence) + self.set_algo.addWidget(QLabel("Minimum Prominence"), 2, 0) + self.set_algo.addWidget(le_minimum_prominence, 2, 1) + self.set_algo.addWidget(create_help_button("Minimum Prominence: The minimum prominence of a peak in EAR score. Rec: 0.1"), 2, 2) + le_minimum_internal_width = QtWidgets.QLineEdit() le_minimum_internal_width.setValidator(int_validator) self.add_handler("min_width", le_minimum_internal_width, mapper=I2S, default=10) - self.set_algo.addRow("Mininum Internal Width", le_minimum_internal_width) + + self.set_algo.addWidget(QLabel("Minimum Internal Width"), 3, 0) + self.set_algo.addWidget(le_minimum_internal_width, 3, 1) + self.set_algo.addWidget(create_help_button("Minimum Internal Width: The minimum width of a peak in frames. Rec: 4@30FPS, 20@240FPS"), 3, 2) le_maximum_internal_width = QtWidgets.QLineEdit() le_maximum_internal_width.setValidator(int_validator) self.add_handler("max_width", le_maximum_internal_width, mapper=I2S, default=100) - self.set_algo.addRow("Maximum Internal Width", le_maximum_internal_width) + + self.set_algo.addWidget(QLabel("Maximum Internal Width"), 4, 0) + self.set_algo.addWidget(le_maximum_internal_width, 4, 1) + self.set_algo.addWidget(create_help_button("Maximum Internal Width: The maximum width of a peak in frames. Rec: 20@30FPS, 100@240FPS"), 4, 2) le_maximum_matching_dist = QtWidgets.QLineEdit() le_maximum_matching_dist.setValidator(int_validator) self.add_handler("maximum_matching_dist", le_maximum_matching_dist, mapper=I2S, default=30) - self.set_algo.addRow("Maximum Matching Distance", le_maximum_matching_dist) + + self.set_algo.addWidget(QLabel("Maximum Matching Distance"), 5, 0) + self.set_algo.addWidget(le_maximum_matching_dist, 5, 1) + self.set_algo.addWidget(create_help_button("Maximum Matching Distance: The maximum distance between two peaks to be matched in frames. Rec: 15@30FPS, 30@240FPS"), 5, 2) le_partial_threshold_left = QtWidgets.QLineEdit() self.add_handler("partial_threshold_l", le_partial_threshold_left, default="auto") - self.set_algo.addRow("Partial Threshold Left", le_partial_threshold_left) + + self.set_algo.addWidget(QLabel("Partial Threshold Left"), 6, 0) + self.set_algo.addWidget(le_partial_threshold_left, 6, 1) + self.set_algo.addWidget(create_help_button("Partial Threshold Left: The threshold for a partial blink in EAR score either 'auto' or a float number. Rec: 0.18"), 6, 2) + le_partial_threshold_right = QtWidgets.QLineEdit() self.add_handler("partial_threshold_r", le_partial_threshold_right, default="auto") - self.set_algo.addRow("Partial Threshold Right", le_partial_threshold_right) + self.set_algo.addWidget(QLabel("Partial Threshold Right"), 7, 0) + self.set_algo.addWidget(le_partial_threshold_right, 7, 1) + self.set_algo.addWidget(create_help_button("Partial Threshold Right: The threshold for a partial blink in EAR score either 'auto' or a float number. Rec: 0.18"), 7, 2) + # TODO this value is not saved in the config! self.cb_video_fps = QtWidgets.QComboBox() self.cb_video_fps.addItems(["24", "30", "60", "120", "240"]) self.cb_video_fps.setCurrentIndex(4) self.cb_video_fps.currentIndexChanged.connect(self.compute_graph_axis) - self.set_algo.addRow("Video FPS", self.cb_video_fps) + self.set_algo.addWidget(QLabel("Video FPS"), 8, 0) + self.set_algo.addWidget(self.cb_video_fps, 8, 1) + self.set_algo.addWidget(create_help_button("Video FPS: The frames per second of the video."), 8, 2) + box_smooth = QtWidgets.QGroupBox("Smoothing") box_smooth.setCheckable(True) self.add_handler("smooth", box_smooth) @@ -252,16 +327,17 @@ def __init__(self, parent): le_smooth_size = QtWidgets.QLineEdit() le_smooth_size.setValidator(int_validator) - self.add_handler("smooth_size", le_smooth_size, mapper=I2S, default=91) + self.add_handler("smooth_size", le_smooth_size, mapper=I2S, default=7) box_smooth_layout.addRow("Window Size", le_smooth_size) - + le_smooth_poly = QtWidgets.QLineEdit() le_smooth_poly.setValidator(int_validator) - self.add_handler("smooth_poly", le_smooth_poly, mapper=I2S, default=5) + self.add_handler("smooth_poly", le_smooth_poly, mapper=I2S, default=3) box_smooth_layout.addRow("Polynomial Degree", le_smooth_poly) - self.set_algo.addRow(box_smooth) - + self.set_algo.addWidget(box_smooth, 9, 0, 1, 2) + self.set_algo.addWidget(create_help_button("Smoothing: The smoothing of the EAR data. Rec: Window Size: 7, Polynomial Degree: 3"), 9, 2) + # Visual Settings # self.box_visuals = QtWidgets.QGroupBox("Graph Control") self.set_visuals = QtWidgets.QFormLayout() @@ -272,7 +348,7 @@ def __init__(self, parent): self.cb_as_time.stateChanged.connect(self.compute_graph_axis) btn_reset_graph = QtWidgets.QPushButton(qta.icon("msc.refresh"), "Reset Graph Y Range") - btn_reset_graph.clicked.connect(lambda: self.graph.setYRange(0, 1)) + btn_reset_graph.clicked.connect(lambda: self.graph.setYRange(-0.5, 1)) self.set_visuals.addRow(btn_reset_graph) btn_reset_view = QtWidgets.QPushButton(qta.icon("msc.refresh"), "View Full Graph") @@ -282,7 +358,7 @@ def __init__(self, parent): # Export Settings # self.overwrite_export = QtWidgets.QCheckBox("Overwrite Existing File") self.add_handler("overwrite_export", self.overwrite_export, default=True) - + self.format_export = QtWidgets.QComboBox() self.format_export.addItems(["CSV", "Excel"]) self.format_export.setCurrentIndex(0) @@ -300,7 +376,7 @@ def __init__(self, parent): self.layout_settings.addWidget(self.la_current_file) self.layout_settings.addWidget(self.face_preview, alignment=QtCore.Qt.AlignmentFlag.AlignCenter) self.layout_settings.addWidget(jwidgets.JHLine()) - + self.layout_settings.addWidget(QtWidgets.QLabel("Left Eye")) self.layout_settings.addWidget(self.comb_ear_l) self.layout_settings.addWidget(QtWidgets.QLabel("Right Eye")) @@ -330,7 +406,7 @@ def __init__(self, parent): self.disable_column_selection() self.disable_algorithm() self.disable_export() - + def get_selected_fps(self) -> int: """ Get the selected frames per second (fps) from the video fps combo box. @@ -411,7 +487,7 @@ def select_column_left(self, index: int) -> None: """ if self.data_frame is None or self.data_frame_columns is None: return - + self.raw_ear_l = self.data_frame[self.data_frame_columns[index]].to_numpy() self.update_plot_raw() self.disable_export() @@ -515,22 +591,19 @@ def extract_blinks(self) -> None: None """ self.progress.setRange(0, 100) - self.progress.setValue(0) + + if not self.validate_compute_parameters(): + return + self.progress.setValue(30) + if not self.compute_intervals(): return self.progress.setValue(60) if not self.plot_intervals(): return - self.progress.setValue(80) - - if self.blinking_l is None or self.blinking_r is None: - logger.error("Somehow the blinking data frames are None") - return - if self.blinking_matched is None: - logger.error("Somehow the matched blinking data frame is None") - return + self.progress.setValue(90) self.table_matched.set_data(self.blinking_matched) self.progress.setValue(100) @@ -538,88 +611,119 @@ def extract_blinks(self) -> None: self.enable_export() self.tab_widget_results.setCurrentIndex(0) - def compute_intervals(self) -> None: + def validate_compute_parameters(self) -> bool: """ - Computes the intervals for eye blinking extraction based on the provided settings. + Validate the parameters for computing the intervals for eye blinking extraction. Returns: - None - - Raises: - AssertionError: If the data frame or data frame columns are None. - AssertionError: If the raw ear right or raw ear left are None. - ValueError: If the same column is selected for both eyes. - ValueError: If the blinking data frames cannot be matched. - + bool: True if the parameters are valid, False otherwise. """ + # check if the column selection index are not the same + if self.comb_ear_l.currentIndex() == self.comb_ear_r.currentIndex(): + logger.error("The same column is selected for both eyes") + QMessageBox.critical("Blinking Extraction Error", "Both EAR columns are the same! Please select different columns and try again",) + return False + def validate_setting(setting_name: str) -> tuple[bool, int | float]: try: - value = self.get(setting_name) + _ = self.get(setting_name) except ValueError: logger.error("Error while validating the settings", setting=setting_name) - jwidgets.JDialogWarn("Blinking Extraction Error", f"The setting {setting_name} is not a valid input.", "Please change your settings and try again") - return False, None - return True, value + QMessageBox.critical(None, "Blinking Extraction", f"The setting {setting_name} is not a valid input. Please change your settings and try again") + return False + return True - # check if the column selection index are not the same - if self.comb_ear_l.currentIndex() == self.comb_ear_r.currentIndex(): - logger.error("The same column is selected for both eyes") - jwidgets.JDialogWarn("Blinking Extraction Error", "Both EAR columns are the same!", "Please select different columns and try again",) + if not validate_setting("partial_threshold_l"): return False - - succ, partial_threshold_l = validate_setting("partial_threshold_l") - if not succ: + if not validate_setting("partial_threshold_r"): return False - succ, partial_threshold_r = validate_setting("partial_threshold_r") - if not succ: + if not validate_setting("min_dist"): return False - succ, minimum_distance = validate_setting("min_dist") - if not succ: + if not validate_setting("min_prominence"): return False - succ, minimum_prominence = validate_setting("min_prominence") - if not succ: + if not validate_setting("min_width"): return False - succ, minimum_internal_width = validate_setting("min_width") - if not succ: + if not validate_setting("maximum_matching_dist"): return False - succ, maximum_matching_dist = validate_setting("maximum_matching_dist") - if not succ: + if not validate_setting("max_width"): return False - succ, maximum_internal_width = validate_setting("max_width") - if not succ: + if not validate_setting("smooth_size"): return False - succ, smooth_size = validate_setting("smooth_size") - if not succ: + if not validate_setting("smooth_poly"): return False - succ, smooth_poly = validate_setting("smooth_poly") - if not succ: + + if (self.get("partial_threshold_l") == "auto" and self.get("partial_threshold_r") != "auto") or ( + self.get("partial_threshold_l") != "auto" and self.get("partial_threshold_r") == "auto"): + QMessageBox.critical(None, "Blinking Extraction Warning", "Both partial thresholds need to be set to 'auto' or a value") return False - self.ear_l = blinking.smooth(self.raw_ear_l, smooth_size, smooth_poly) if self.get("smooth") else self.raw_ear_l - self.ear_r = blinking.smooth(self.raw_ear_r, smooth_size, smooth_poly) if self.get("smooth") else self.raw_ear_r + return True + + def compute_intervals(self) -> bool: + """ + Computes the intervals for eye blinking extraction based on the provided settings. + Returns: + bool: True if the computation is successful, False otherwise. + """ + try: + self.ear_l = blinking.smooth(self.raw_ear_l, self.get("smooth_size"), self.get("smooth_poly")) if self.get("smooth") else self.raw_ear_l + self.ear_r = blinking.smooth(self.raw_ear_r, self.get("smooth_size"), self.get("smooth_poly")) if self.get("smooth") else self.raw_ear_r + except Exception as e: + logger.error("Error while smoothing the EAR data", error=e) + QMessageBox.critical(None, "Blinking Extraction Error", f"The EAR data could not be smoothed. {e}") + return False self.progress.setValue(40) # if only one is set to auto, inform the user - if (partial_threshold_l == "auto" and partial_threshold_r != "auto") or (partial_threshold_l != "auto" and partial_threshold_r == "auto"): - jwidgets.JDialogWarn( - "Blinking Extraction Warning", - "Both partial thresholds are set to 'auto'", - "This is not recommended, please change your settings and try again" + partial_threshold_l = "auto" if self.get("partial_threshold_l") == "auto" else float(self.get("partial_threshold_l")) + partial_threshold_r = "auto" if self.get("partial_threshold_r") == "auto" else float(self.get("partial_threshold_r")) + + try: + min_dist = int(self.get("min_dist")) + min_prom = float(self.get("min_prominence")) + min_int_width = int(self.get("min_width")) + max_int_width = int(self.get("max_width")) + + self.blinking_l, self.comp_partial_threshold_l = blinking.peaks( + time_series=self.ear_l, + minimum_distance=min_dist, + minimum_prominence=min_prom, + minimum_internal_width=min_int_width, + maximum_internal_width=max_int_width, + partial_threshold=partial_threshold_l ) + self.blinking_r, self.comp_partial_threshold_r = blinking.peaks( + time_series=self.ear_r, + minimum_distance=min_dist, + minimum_prominence=min_prom, + minimum_internal_width=min_int_width, + maximum_internal_width=max_int_width, + partial_threshold=partial_threshold_r + ) + except Exception as e: + logger.error("Error while computing the intervals for eye blinking extraction", error=e) + QMessageBox.critical(None, "Error Blinking Extraction", f"Blinking Extraction Warning Error: {e}") return False + + if self.comp_partial_threshold_l is np.nan or self.comp_partial_threshold_r is np.nan: + QMessageBox.information(None, "Blinking Extraction Information", "We could not compute a automatic threshold based on the data. Continued with default `complete` label or run with sepecific thresholds. We recommend 0.18 for partial blinks.") + self.progress.setValue(50) - partial_threshold_l = "auto" if partial_threshold_l == "auto" else float(partial_threshold_l) - partial_threshold_r = "auto" if partial_threshold_r == "auto" else float(partial_threshold_r) - - self.blinking_l, self.comp_partial_threshold_l = blinking.peaks(self.ear_l, minimum_distance, minimum_prominence, minimum_internal_width, maximum_internal_width, partial_threshold_l) - self.blinking_r, self.comp_partial_threshold_r = blinking.peaks(self.ear_r, minimum_distance, minimum_prominence, minimum_internal_width, maximum_internal_width, partial_threshold_r) + # check if the blinking data frames are empty + if self.blinking_l.empty or self.blinking_r.empty: + QMessageBox.warning(None, "Blinking Extraction Warning", "No blinks found in the data. Please check the data or settings and try again.") + return False try: - self.blinking_matched = blinking.match(self.blinking_l, self.blinking_r, tolerance=maximum_matching_dist) + self.blinking_matched = blinking.match( + blinking_l=self.blinking_l, + blinking_r=self.blinking_r, + tolerance=self.get("maximum_matching_dist") + ) except ValueError as e: logger.error("Error while matching the blinking data frames", error=e) - jwidgets.JDialogWarn( "Blinking Extraction Error", "The blinking could not be matched, likely none found", "Please change your settings and try again") + QMessageBox.critical("Blinking Extraction Error", "The blinking could not be matched, likely none found") return False return True @@ -632,34 +736,39 @@ def plot_intervals(self) -> bool: """ if self.blinking_l is None or self.blinking_r is None: return False - - self.curve_l.clear() - self.curve_r.clear() - self.curve_l.setData(self.ear_l) - self.curve_r.setData(self.ear_r) - # TODO add some kind of settings for the colors - self.scatter_l_comp.clear() - self.scatter_r_comp.clear() - self.scatter_l_part.clear() - self.scatter_r_part.clear() - - # get where the complete blinks are - x = self.blinking_l[self.blinking_l["blink_type"] == "complete"]["apex_frame"].to_numpy() - y = self.blinking_l[self.blinking_l["blink_type"] == "complete"]["ear_score"].to_numpy() - self.scatter_l_comp.setData(x=x,y=y,symbol="o", pen={"color": "#00F", "width": 2}) - x = self.blinking_r[self.blinking_r["blink_type"] == "complete"]["apex_frame"].to_numpy() - y = self.blinking_r[self.blinking_r["blink_type"] == "complete"]["ear_score"].to_numpy() - self.scatter_r_comp.setData(x=x,y=y,symbol="o", pen={"color": "#F00", "width": 2}) - - # get where the partial blinks are - x = self.blinking_l[self.blinking_l["blink_type"] == "partial"]["apex_frame"].to_numpy() - y = self.blinking_l[self.blinking_l["blink_type"] == "partial"]["ear_score"].to_numpy() - self.scatter_l_part.setData(x=x,y=y, symbol="t", pen={"color": "#00F", "width": 2}) - x = self.blinking_r[self.blinking_r["blink_type"] == "partial"]["apex_frame"].to_numpy() - y = self.blinking_r[self.blinking_r["blink_type"] == "partial"]["ear_score"].to_numpy() - self.scatter_r_part.setData(x=x,y=y, symbol="t", pen={"color": "#F00", "width": 2}) - + try: + self.curve_l.clear() + self.curve_r.clear() + self.curve_l.setData(self.ear_l) + self.curve_r.setData(self.ear_r) + + # TODO add some kind of settings for the colors + self.scatter_l_comp.clear() + self.scatter_r_comp.clear() + self.scatter_l_part.clear() + self.scatter_r_part.clear() + + # get where the complete blinks are + x = self.blinking_l[self.blinking_l["blink_type"] == "complete"]["apex_frame"].to_numpy() + y = self.blinking_l[self.blinking_l["blink_type"] == "complete"]["ear_score"].to_numpy() + self.scatter_l_comp.setData(x=x,y=y,symbol="o", pen={"color": "#00F", "width": 2}) + x = self.blinking_r[self.blinking_r["blink_type"] == "complete"]["apex_frame"].to_numpy() + y = self.blinking_r[self.blinking_r["blink_type"] == "complete"]["ear_score"].to_numpy() + self.scatter_r_comp.setData(x=x,y=y,symbol="o", pen={"color": "#F00", "width": 2}) + + # get where the partial blinks are + x = self.blinking_l[self.blinking_l["blink_type"] == "partial"]["apex_frame"].to_numpy() + y = self.blinking_l[self.blinking_l["blink_type"] == "partial"]["ear_score"].to_numpy() + self.scatter_l_part.setData(x=x,y=y, symbol="t", pen={"color": "#00F", "width": 2}) + x = self.blinking_r[self.blinking_r["blink_type"] == "partial"]["apex_frame"].to_numpy() + y = self.blinking_r[self.blinking_r["blink_type"] == "partial"]["ear_score"].to_numpy() + self.scatter_r_part.setData(x=x,y=y, symbol="t", pen={"color": "#F00", "width": 2}) + except Exception as e: + logger.error("Error while plotting the blinking intervals", error=e) + QMessageBox.critical(None, "Blinking Plotting Error", f"The blinking intervals could not be plotted. {e}") + return False + return True def clear_on_new_file(self) -> None: @@ -687,7 +796,7 @@ def clear_on_new_file(self) -> None: self.scatter_r_part.clear() self.table_summary.reset() - + self.disable_column_selection() self.disable_algorithm() self.disable_export() @@ -717,6 +826,8 @@ def highlight_blink(self, index: int) -> None: frame_idx = min(frame_left, frame_right) # show 1 second before and after the blink self.graph.setXRange(frame_idx - self.get_selected_fps(), frame_idx + self.get_selected_fps()) + + logger.info("Highlighting blink", index=index, frame_idx=frame_idx) self.face_preview.set_frame(frame_idx) # summary of the results @@ -735,11 +846,11 @@ def compute_summary(self) -> None: ) self.table_summary.set_data(self.blinking_summary) logger.info("Summary computed") - + image = blinking.visualize(self.blinking_matched, fps=fps) self.summary_visual_image.setImage(image) logger.info("Visual summary computed") - + self.tab_widget_results.setCurrentIndex(1) # saving of the results @@ -785,7 +896,7 @@ def save_results(self) -> None: # TODO give user feedback that saving was successful logger.info("Saving blinking finished") - + ## general widget functions def shut_down(self) -> None: """ @@ -843,7 +954,7 @@ def dropEvent(self, event: QtGui.QDropEvent): if file.suffix.lower() == ".csv": self.load_file(file) return - + logger.info("User dropped invalid file", widget=self) ## enabling for logic flow @@ -871,4 +982,4 @@ def enable_export(self) -> None: def disable_export(self) -> None: self.btn_eprt.setEnabled(False) self.btn_summ.setEnabled(False) - self.format_export.setEnabled(False) \ No newline at end of file + self.format_export.setEnabled(False) diff --git a/frontend/ui_facial_feature_extraction.py b/frontend/ui_facial_feature_extraction.py index 1636647..8257d9f 100644 --- a/frontend/ui_facial_feature_extraction.py +++ b/frontend/ui_facial_feature_extraction.py @@ -159,7 +159,7 @@ def __init__(self, parent): self.la_current_file.setWordWrap(True) self.pb_anal = self.parent().progress_bar # type: ignore # TODO: fix this as JeFaPaTo cannot be imported from here... - self.skip_frame = QtWidgets.QSpinBox() + self.update_delay = QtWidgets.QSpinBox() self.auto_save = QtWidgets.QCheckBox("Auto-Save") self.auto_save.setToolTip("Save the extracted data automatically after the analysis is finished.") @@ -167,6 +167,22 @@ def __init__(self, parent): self.use_bbox = QtWidgets.QCheckBox("Use Bounding Box") self.use_bbox.setToolTip("Use the bounding box to extract the landmarks.") + self.rotate_group = QtWidgets.QGroupBox("Rotate") + self.rotate_group.setLayout(QtWidgets.QVBoxLayout()) + + self.rotate_none = QtWidgets.QRadioButton("None") + self.rotate_90 = QtWidgets.QRadioButton("90") + self.rotate_m90 = QtWidgets.QRadioButton("-90") + + self.rotate_none.setChecked(True) + self.rotate_group.layout().addWidget(self.rotate_none) + self.rotate_group.layout().addWidget(self.rotate_90) + self.rotate_group.layout().addWidget(self.rotate_m90) + self.current_rotation = "None" + self.rotate_none.toggled.connect(self.set_rotation) + self.rotate_90.toggled.connect(self.set_rotation) + self.rotate_m90.toggled.connect(self.set_rotation) + self.add_handler("auto_save", self.auto_save, default=True) self.add_handler("use_bbox", self.use_bbox, default=True) self.add_handler("auto_find_face", self.widget_frame.cb_auto_find, default=True) @@ -191,9 +207,11 @@ def __init__(self, parent): self.flayout_se.addRow(self.button_start) self.flayout_se.addRow(self.bt_pause_resume) self.flayout_se.addRow(self.button_stop) + self.flayout_se.addRow(self.rotate_group) + self.flayout_se.addRow(self.feature_group) self.flayout_se.addRow(self.blends_shape_group) - self.flayout_se.addRow("Graph Update Delay:", self.skip_frame) + self.flayout_se.addRow("Update Delay:", self.update_delay) self.flayout_se.addRow(self.bt_reset_graph) self.flayout_se.addRow(self.auto_save) self.flayout_se.addRow(self.use_bbox) @@ -215,8 +233,7 @@ def __init__(self, parent): self.button_stop.clicked.connect(self.stop) self.bt_pause_resume.clicked.connect(self.ea.toggle_pause) - self.skip_frame.setRange(1, 20) - self.skip_frame.setValue(1) + self.update_delay.setRange(1, 30) # disable analyse button and check box self.button_start.setDisabled(True) @@ -231,6 +248,9 @@ def __init__(self, parent): self.jefapato_signal_thread = JeFaPaToGUISignalThread(self) self.ea.register_hooks(self.jefapato_signal_thread) + self.update_delay.valueChanged.connect(self.jefapato_signal_thread.set_update_interval) + self.update_delay.setValue(5) + self.jefapato_signal_thread.sig_updated_display.connect(self.sig_updated_display) self.jefapato_signal_thread.sig_updated_feature.connect(self.sig_updated_feature) self.jefapato_signal_thread.sig_processed_percentage.connect(self.sig_processed_percentage) @@ -239,6 +259,15 @@ def __init__(self, parent): self.jefapato_signal_thread.sig_resumed.connect(self.sig_resumed) self.jefapato_signal_thread.sig_finished.connect(self.sig_finished) self.jefapato_signal_thread.start() + + def set_rotation(self): + if self.rotate_none.isChecked(): + self.current_rotation = "None" + elif self.rotate_90.isChecked(): + self.current_rotation = "90" + elif self.rotate_m90.isChecked(): + self.current_rotation = "-90" + self.set_resource(self.video_resource) def setup_graph(self) -> None: logger.info("Setup graph for all features to plot", features=len(self.used_features_classes)) @@ -285,7 +314,7 @@ def start(self) -> None: self.ea.set_features(self.used_features_classes) rect = self.widget_frame.get_roi_rect() if self.use_bbox.isChecked() else None - self.ea.clean_start(rect) + self.ea.clean_start(rect, self.current_rotation) def stop(self) -> None: self.ea.stop() @@ -362,7 +391,7 @@ def sig_updated_feature(self, feature_data: dict[str, Any]) -> None: self.plot_data[feature_name][:-1] = self.plot_data[feature_name][1:] self.plot_data[feature_name][-1] = feature_value - if self.update_count % self.skip_frame.value() == 0: + if self.update_count % self.update_delay.value() == 0: self.plot_item[feature_name].setData(self.plot_data[feature_name]) def load_video(self): @@ -371,7 +400,7 @@ def load_video(self): parent=self, caption="Select video file", directory=".", - filter="Video Files (*.mp4 *.flv *.ts *.mts *.avi *.mov)", + filter="Video Files (*.mp4 *.flv *.ts *.mts *.avi *.mov *.wmv)", ) if fileName == "": @@ -404,7 +433,7 @@ def set_resource(self, resource: Path | int) -> bool: else: self.la_current_file.setText("File: Live Webcam Feed") - success, frame = self.ea.prepare_video_resource(self.video_resource) + success, frame = self.ea.prepare_video_resource(self.video_resource, self.current_rotation) if success: logger.info("Image was set", parent=self) self.widget_frame.set_selection_image(frame) @@ -454,7 +483,7 @@ def dropEvent(self, event: QtGui.QDropEvent): file = files[0] file = Path(file) - if file.suffix.lower() not in [".mp4", ".flv", ".ts", ".mts", ".avi", ".mov"]: + if file.suffix.lower() not in [".mp4", ".flv", ".ts", ".mts", ".avi", ".mov", ".wmv"]: logger.info("User dropped invalid file", widget=self) return self.set_resource(Path(file)) \ No newline at end of file diff --git a/src/jefapato/blinking/__init__.py b/src/jefapato/blinking/__init__.py index 182839c..848fed9 100644 --- a/src/jefapato/blinking/__init__.py +++ b/src/jefapato/blinking/__init__.py @@ -1,7 +1,61 @@ -__all__ = ["peaks", "smooth", "match", "summarize", "visualize", "load_ear_score", "save_results"] +__all__ = ["peaks", "smooth", "match", "summarize", "visualize", "load_ear_score", "save_results", "HELP_DESCRIPTION"] from jefapato.blinking.peaks import peaks from jefapato.blinking.smooth import smooth from jefapato.blinking.match import match from jefapato.blinking.summary import summarize, visualize -from jefapato.blinking.io import load_ear_score, save_results \ No newline at end of file +from jefapato.blinking.io import load_ear_score, save_results + + +HELP_DESCRIPTION = """ +

Recommended Extracton Settings for Eye Blinking

+ +

+Here we give some recommended settings for the extraction of eye blinking from EAR scores. +These settings are based on the analysis of the EAR scores of a dataset of internal dataset, not yet published. +

+ +

+The dataset was recorded at 30 and 240 FPS. +The settings are divided into two groups, one for each FPS. +These should be a good starting point for the extraction of eye blinking from EAR scores depending on the FPS of the video. +

+ +

+The settings are the following: +

+
+ +

@30 FPS

+ +

Smoothing

+ +
+ +

@240 FPS

+ +

Smoothing

+ +""" \ No newline at end of file diff --git a/src/jefapato/blinking/peaks.py b/src/jefapato/blinking/peaks.py index 5cf2d74..d843b61 100644 --- a/src/jefapato/blinking/peaks.py +++ b/src/jefapato/blinking/peaks.py @@ -15,11 +15,20 @@ def otsu_thresholding(values: np.ndarray) -> float: """ # first remove all nans from the values values = values[~np.isnan(values)] + + # check that there are enough values for the calculation + if len(values) < 6: + return np.nan + th_range = np.sort(np.unique(values))[3:-3] # remove the first and last 3 values to avoid errors in the calculation res = [] for th in th_range: r = np.nansum([np.mean(cls) * np.var(values, where=cls) for cls in [values>=th, values th: df.loc[index, 'blink_type'] = "complete" else: df.loc[index, 'blink_type'] = "partial" - return df, th diff --git a/src/jefapato/blinking/smooth.py b/src/jefapato/blinking/smooth.py index 1997b23..d1469f7 100644 --- a/src/jefapato/blinking/smooth.py +++ b/src/jefapato/blinking/smooth.py @@ -5,8 +5,12 @@ def smooth(time_series: np.ndarray, smooth_size:int=91, smooth_poly:int=4) -> np.ndarray: - return signal.savgol_filter( + sig = signal.savgol_filter( time_series, window_length=smooth_size, polyorder=smooth_poly, ) + # check all values to be 0 or 1 + sig[sig < 0] = 0 + sig[sig > 1] = 1 + return sig diff --git a/src/jefapato/blinking/summary.py b/src/jefapato/blinking/summary.py index b3f2349..c52ff6b 100644 --- a/src/jefapato/blinking/summary.py +++ b/src/jefapato/blinking/summary.py @@ -132,6 +132,7 @@ def summarize( partial_times_l = pd.to_datetime(partial_l["minute"], unit='m', errors="ignore") partial_group_l = partial_l.groupby(partial_times_l.dt.minute) + i = 1 for i, row in enumerate(partial_group_l.count()["minute"], start=1): statistics[f"Partial_Blinks_min{i:02d}_left"] = row while i <= math.ceil(length_l_min): @@ -141,9 +142,11 @@ def summarize( partial_r["minute"] = partial_r["apex_frame_og"] / fps / 60 partial_times_r = pd.to_datetime(partial_r["minute"], unit='m', errors="ignore") partial_group_r = partial_r.groupby(partial_times_r.dt.minute) - + + i = 1 for i, row in enumerate(partial_group_r.count()["minute"], start=1): statistics[f"Partial_Blinks_min{i:02d}_right"] = row + while i <= math.ceil(length_r_min): statistics[f"Partial_Blinks_min{i:02d}_right"] = 0 i += 1 diff --git a/src/jefapato/facial_features/features/ear_feature.py b/src/jefapato/facial_features/features/ear_feature.py index aece25d..99d0c1c 100644 --- a/src/jefapato/facial_features/features/ear_feature.py +++ b/src/jefapato/facial_features/features/ear_feature.py @@ -12,7 +12,7 @@ logger = structlog.get_logger() -def ear_score(eye: np.ndarray) -> float: +def ear_score(eye: np.ndarray) -> tuple[float, bool]: """ Compute the EAR Score for eye landmarks @@ -35,6 +35,7 @@ def ear_score(eye: np.ndarray) -> float: Returns: float: The computed EAR score, which should be between 0 and 1 + bool: A flag indicating if the EAR score is valid """ if eye is None: raise ValueError("eye must not be None") @@ -43,22 +44,31 @@ def ear_score(eye: np.ndarray) -> float: raise TypeError(f"eye must be a numpy array, but got {type(eye)}") if eye.shape != (6, 2) and eye.shape != (6, 3): # allow for 3D landmarks - raise ValueError(f"eye must be a 6x2 array, but got {eye.shape}") + raise ValueError(f"eye must be a 6x2 or 6x3 array, but got {eye.shape}") # check that no value is negative if np.any(eye < 0): - raise ValueError(f"eye must not contain negative values, but got {eye}") - + # This can be the case if parts of the face are not inside the image + # but the predictor tries to estimate the rough location. + # Thus we just log a warning and continue + logger.warning(f"Eye landmarks must not contain negative values, but got {eye}") + # dont forget the 0-index A = distance.euclidean(eye[1], eye[5]) B = distance.euclidean(eye[2], eye[4]) C = distance.euclidean(eye[0], eye[3]) ratio = (A + B) / (2.0 * C) - if ratio > 1.002: # allow for some rounding errors - raise ValueError(f"EAR score must be between 0 and 1, but got {ratio}, check your landmarks order") - - return ratio + compute_valid = True + if ratio > 1.0: + logger.warning(f"EAR score must be between 0 and 1, but got {ratio}") + ratio = 1.0 + compute_valid = False + if ratio < 0.0: + logger.warning(f"EAR score must be between 0 and 1, but got {ratio}") + ratio = 0.0 + compute_valid = False + return ratio, compute_valid @dataclasses.dataclass @@ -158,8 +168,13 @@ def compute(self, features: np.ndarray, valid: bool) -> EAR_Data: return EAR_Data(1.0, 1.0, False, lm_l, lm_r) ear_valid = not (np.allclose(np.zeros_like(lm_l), lm_l) and np.allclose(np.zeros_like(lm_r), lm_r)) - ear_l = ear_score(lm_l) if ear_valid else 1.0 - ear_r = ear_score(lm_r) if ear_valid else 1.0 + ear_l, ear_l_c = ear_score(lm_l) + ear_r, ear_r_c = ear_score(lm_r) + + if not ear_l_c or not ear_r_c: + logger.warning(f"EAR score computation is not valid for left: {ear_l} and right: {ear_r}") + + ear_valid = ear_valid and ear_l_c and ear_r_c return EAR_Data(ear_l, ear_r, ear_valid, lm_l, lm_r) @@ -192,6 +207,11 @@ def compute(self, features: np.ndarray, valid: bool) -> EAR_Data: return EAR_Data(1.0, 1.0, False, lm_l, lm_r) ear_valid = not (np.allclose(np.zeros_like(lm_l), lm_l) and np.allclose(np.zeros_like(lm_r), lm_r)) - ear_l = ear_score(lm_l) if ear_valid else 1.0 - ear_r = ear_score(lm_r) if ear_valid else 1.0 + ear_l, ear_l_c = ear_score(lm_l) + ear_r, ear_r_c = ear_score(lm_r) + + if not ear_l_c or not ear_r_c: + logger.warning(f"EAR score computation is not valid for left: {ear_l} and right: {ear_r}") + + ear_valid = ear_valid and ear_l_c and ear_r_c return EAR_Data(ear_l, ear_r, ear_valid, lm_l, lm_r) \ No newline at end of file diff --git a/src/jefapato/facial_features/landmark_analyser.py b/src/jefapato/facial_features/landmark_analyser.py index c18882e..b044c4b 100644 --- a/src/jefapato/facial_features/landmark_analyser.py +++ b/src/jefapato/facial_features/landmark_analyser.py @@ -43,7 +43,7 @@ def __init__(self, max_ram_size: int = 4<<28): self.pm = pluggy.PluginManager("analyser") - def analysis_setup(self, bbox_slice: tuple[int, int, int, int] | None = None) -> bool: + def analysis_setup(self, bbox_slice: tuple[int, int, int, int] | None = None, rotation:str="None") -> bool: """ Sets up the analysis by initializing necessary components and calculating available resources. @@ -73,7 +73,7 @@ def analysis_setup(self, bbox_slice: tuple[int, int, int, int] | None = None) -> if bbox_slice is not None: logger.info("Bounding box slice", bbox=bbox_slice) - self.loader = VideoDataLoader(self.resource_interface.read, data_amount=self.data_amount, queue_maxsize=items_to_place) + self.loader = VideoDataLoader(self.resource_interface.read, data_amount=self.data_amount, queue_maxsize=items_to_place, rotation=rotation) self.extractor = MediapipeLandmarkExtractor(data_queue=self.loader.data_queue, data_amount=self.data_amount, bbox_slice=bbox_slice) self.extractor.register(self) return True @@ -200,7 +200,7 @@ def toggle_pause(self) -> None: self.extractor.toggle_pause() - def clean_start(self, bbox_slice: tuple[int, int, int, int] | None = None) -> None: + def clean_start(self, bbox_slice: tuple[int, int, int, int] | None = None, rotation:str = "None") -> None: """ Starts the landmark analysis process. @@ -217,7 +217,7 @@ def clean_start(self, bbox_slice: tuple[int, int, int, int] | None = None) -> No for m_name in self.feature_classes: self.feature_data[m_name].clear() - self.analysis_setup(bbox_slice=bbox_slice) + self.analysis_setup(bbox_slice=bbox_slice, rotation=rotation) self.analysis_start() def get_header(self) -> list[str]: @@ -247,7 +247,7 @@ def __next__(self): return row - def prepare_video_resource(self, value: Path) -> tuple[bool, np.ndarray]: + def prepare_video_resource(self, value: Path, rotation: str = "None") -> tuple[bool, np.ndarray]: self.video_resource = value if not isinstance(self.video_resource, Path): @@ -259,14 +259,23 @@ def prepare_video_resource(self, value: Path) -> tuple[bool, np.ndarray]: if not self.video_resource.is_file(): raise ValueError(f"File {self.video_resource} is not a file.") - if self.video_resource.suffix.lower() not in [".mp4", ".flv", ".ts", ".mts", ".avi", ".mov"]: + if self.video_resource.suffix.lower() not in [".mp4", ".flv", ".ts", ".mts", ".avi", ".mov", ".wmv"]: raise ValueError(f"File {self.video_resource} is not a video file.") self.resource_interface = cv2.VideoCapture(str(self.video_resource.absolute())) self.data_amount = self.resource_interface.get(cv2.CAP_PROP_FRAME_COUNT) success, image = self.resource_interface.read() - return success, cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + + if not success: + return success, None + + image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + if rotation == "90": + image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE) + elif rotation == "-90": + image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE) + return success, image def get_fps(self) -> float: """ diff --git a/src/jefapato/facial_features/mediapipe_landmark_extractor.py b/src/jefapato/facial_features/mediapipe_landmark_extractor.py index 736bdea..6c5c459 100644 --- a/src/jefapato/facial_features/mediapipe_landmark_extractor.py +++ b/src/jefapato/facial_features/mediapipe_landmark_extractor.py @@ -29,6 +29,7 @@ def __init__( self.stopped = False self.paused = False self.sleep_duration = sleep_duration + self.processing_per_second: int = 0 self.pm = pluggy.PluginManager("Extractor") diff --git a/src/jefapato/facial_features/video_data_loader.py b/src/jefapato/facial_features/video_data_loader.py index 54ba9b5..3bcb2e6 100644 --- a/src/jefapato/facial_features/video_data_loader.py +++ b/src/jefapato/facial_features/video_data_loader.py @@ -18,7 +18,8 @@ def __init__( self, next_item_func: Callable, data_amount: int | None = None, - queue_maxsize: int = (1 << 10) + queue_maxsize: int = (1 << 10), + rotation: str = "None", ) -> None: super().__init__(daemon=True) assert data_amount is not None, "data_amount must be set" @@ -28,9 +29,14 @@ def __init__( self.data_queue: queue.Queue[InputQueueItem] = queue.Queue(maxsize=queue_maxsize) self.stopped = False self.data_amount = data_amount - - self.processing_per_second: int = 0 + self.processing_per_second: float = 0 + if rotation == "None": + self.rotation_fc = lambda x: x + elif rotation == "90": + self.rotation_fc = lambda x: cv2.rotate(x, cv2.ROTATE_90_CLOCKWISE) + elif rotation == "-90": + self.rotation_fc = lambda x: cv2.rotate(x, cv2.ROTATE_90_COUNTERCLOCKWISE) def run(self): logger.info("Loader Thread", state="starting", object=self) @@ -66,6 +72,7 @@ def run(self): self.stopped = True break frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + frame = self.rotation_fc(frame) self.data_queue.put(InputQueueItem(frame=frame, timestamp=c_time)) processed_p_sec += 1 else: diff --git a/tests/files/blinking/blinking_30FPS.csv b/tests/files/blinking/blinking_30FPS.csv new file mode 100644 index 0000000..e975fde --- /dev/null +++ b/tests/files/blinking/blinking_30FPS.csv @@ -0,0 +1,251 @@ +frame,EAR2D6_l,EAR2D6_r,EAR2D6_valid,BS_Valid +0, 0.30839515, 0.31717056,True,True +1, 0.30697849, 0.31643425,True,True +2, 0.31780323, 0.32533049,True,True +3, 0.31657635, 0.31336477,True,True +4, 0.31764210, 0.31694362,True,True +5, 0.31386926, 0.31409277,True,True +6, 0.31484655, 0.31612779,True,True +7, 0.30915708, 0.31312242,True,True +8, 0.30693714, 0.31124881,True,True +9, 0.30799023, 0.31312242,True,True +10, 0.30571419, 0.30799125,True,True +11, 0.30042486, 0.30502849,True,True +12, 0.28607607, 0.30721214,True,True +13, 0.30121833, 0.30183604,True,True +14, 0.29187137, 0.30210629,True,True +15, 0.29767902, 0.29821654,True,True +16, 0.29061937, 0.30378166,True,True +17, 0.29875644, 0.29564100,True,True +18, 0.29875644, 0.30551011,True,True +19, 0.30571419, 0.29564100,True,True +20, 0.29262141, 0.29620622,True,True +21, 0.29262141, 0.29330723,True,True +22, 0.27219442, 0.27695657,True,True +23, 0.01769842, 0.01282979,True,True +24, 0.01231288, 0.02070684,True,True +25, 0.02101940, 0.01370297,True,True +26, 0.04426898, 0.02246624,True,True +27, 0.03302003, 0.00803064,True,True +28, 0.07497124, 0.02872804,True,True +29, 0.19807905, 0.19991081,True,True +30, 0.23124061, 0.24272208,True,True +31, 0.25739383, 0.26800041,True,True +32, 0.26600419, 0.27675620,True,True +33, 0.26620216, 0.28076742,True,True +34, 0.27219442, 0.28631641,True,True +35, 0.27817795, 0.28247069,True,True +36, 0.27817795, 0.28490235,True,True +37, 0.27819434, 0.28490235,True,True +38, 0.28417787, 0.29053216,True,True +39, 0.28076650, 0.29130211,True,True +40, 0.29126256, 0.29442629,True,True +41, 0.29036380, 0.29442629,True,True +42, 0.28054342, 0.28490235,True,True +43, 0.28688787, 0.29672592,True,True +44, 0.28076650, 0.29109611,True,True +45, 0.28670108, 0.28816167,True,True +46, 0.28076650, 0.28816167,True,True +47, 0.28417787, 0.29109611,True,True +48, 0.28784117, 0.29340709,True,True +49, 0.28790582, 0.29821654,True,True +50, 0.28435252, 0.29672592,True,True +51, 0.28076650, 0.29055364,True,True +52, 0.06502978, 0.03658265,True,True +53, 0.02024917, 0.02625834,True,True +54, 0.02000166, 0.01876873,True,True +55, 0.00874105, 0.02432521,True,True +56, 0.01492190, 0.02768382,True,True +57, 0.00863546, 0.02092892,True,True +58, 0.01492190, 0.03351722,True,True +59, 0.01236170, 0.01641662,True,True +60, 0.01233816, 0.01856745,True,True +61, 0.01831858, 0.00802237,True,True +62, 0.04230399, 0.00000000,True,True +63, 0.06181197, 0.02005528,True,True +64, 0.20705129, 0.22071539,True,True +65, 0.24511024, 0.24825420,True,True +66, 0.26281608, 0.27651996,True,True +67, 0.27138363, 0.28679968,True,True +68, 0.27138363, 0.29316770,True,True +69, 0.29029085, 0.30401200,True,True +70, 0.29152860, 0.30015060,True,True +71, 0.29287058, 0.30957440,True,True +72, 0.27435362, 0.29465200,True,True +73, 0.27774988, 0.29391477,True,True +74, 0.29281205, 0.29593631,True,True +75, 0.28205807, 0.30210629,True,True +76, 0.28360660, 0.29316770,True,True +77, 0.28491334, 0.30566975,True,True +78, 0.29736310, 0.29793630,True,True +79, 0.28449054, 0.30401200,True,True +80, 0.28346620, 0.30158417,True,True +81, 0.28915019, 0.29647832,True,True +82, 0.28346620, 0.28974773,True,True +83, 0.29029085, 0.29873282,True,True +84, 0.29520791, 0.29873282,True,True +85, 0.29047551, 0.30129435,True,True +86, 0.28481250, 0.29235676,True,True +87, 0.29038721, 0.30075286,True,True +88, 0.29399576, 0.29478969,True,True +89, 0.28474855, 0.29793630,True,True +90, 0.29544620, 0.29760003,True,True +91, 0.29047551, 0.29761966,True,True +92, 0.29734401, 0.30129435,True,True +93, 0.30882459, 0.30856107,True,True +94, 0.30317851, 0.30566975,True,True +95, 0.29734401, 0.30210629,True,True +96, 0.29985247, 0.30129435,True,True +97, 0.29991155, 0.30691690,True,True +98, 0.29411627, 0.30639529,True,True +99, 0.29736310, 0.30210629,True,True +100, 0.30554130, 0.32070147,True,True +101, 0.30754054, 0.31882648,True,True +102, 0.31910433, 0.32414189,True,True +103, 0.28094941, 0.27651996,True,True +104, 0.01744879, 0.02406710,True,True +105, 0.02247274, 0.03177595,True,True +106, 0.00860217, 0.03313757,True,True +107, 0.03164379, 0.01356214,True,True +108, 0.06768018, 0.01817901,True,True +109, 0.20271529, 0.22393133,True,True +110, 0.24316228, 0.25774618,True,True +111, 0.26001681, 0.28631641,True,True +112, 0.28056569, 0.28220608,True,True +113, 0.28056569, 0.29362676,True,True +114, 0.27485479, 0.29931613,True,True +115, 0.28094941, 0.29305686,True,True +116, 0.26910210, 0.28466462,True,True +117, 0.27036253, 0.28789544,True,True +118, 0.27151763, 0.27901948,True,True +119, 0.27870788, 0.29593631,True,True +120, 0.28456170, 0.29593631,True,True +121, 0.28913736, 0.29388577,True,True +122, 0.28790582, 0.30129435,True,True +123, 0.29387780, 0.30158417,True,True +124, 0.29047551, 0.30639529,True,True +125, 0.29152860, 0.30639529,True,True +126, 0.29387249, 0.30034817,True,True +127, 0.29174260, 0.30349620,True,True +128, 0.29174260, 0.30202917,True,True +129, 0.29274450, 0.30152513,True,True +130, 0.29876218, 0.30924539,True,True +131, 0.28607607, 0.30349620,True,True +132, 0.28933412, 0.30017115,True,True +133, 0.29876218, 0.31084737,True,True +134, 0.28156328, 0.30535200,True,True +135, 0.29876218, 0.31084737,True,True +136, 0.30084331, 0.30034817,True,True +137, 0.28824583, 0.30265839,True,True +138, 0.28947251, 0.29738223,True,True +139, 0.28476367, 0.29465200,True,True +140, 0.29399576, 0.30616180,True,True +141, 0.28122135, 0.29793630,True,True +142, 0.08696232, 0.07316529,True,True +143, 0.00872440, 0.02460670,True,True +144, 0.01941004, 0.02893588,True,True +145, 0.02526354, 0.03793540,True,True +146, 0.02328699, 0.04282244,True,True +147, 0.01221239, 0.01796818,True,True +148, 0.03546387, 0.00549417,True,True +149, 0.11005832, 0.05299722,True,True +150, 0.22507869, 0.22884677,True,True +151, 0.24808096, 0.25126705,True,True +152, 0.26451688, 0.28204309,True,True +153, 0.26857695, 0.28416769,True,True +154, 0.27301256, 0.28416769,True,True +155, 0.27997872, 0.28442911,True,True +156, 0.28101880, 0.28939994,True,True +157, 0.27989908, 0.28838177,True,True +158, 0.27870788, 0.29340709,True,True +159, 0.29038721, 0.29316770,True,True +160, 0.27761239, 0.28227340,True,True +161, 0.26704718, 0.28760540,True,True +162, 0.26704718, 0.28281947,True,True +163, 0.26590579, 0.28760540,True,True +164, 0.28326359, 0.28204309,True,True +165, 0.27880359, 0.27729200,True,True +166, 0.27286259, 0.28416769,True,True +167, 0.26590579, 0.28416769,True,True +168, 0.28248591, 0.28733513,True,True +169, 0.27448633, 0.27867187,True,True +170, 0.27566412, 0.28389907,True,True +171, 0.27556948, 0.28442911,True,True +172, 0.27870788, 0.28389907,True,True +173, 0.27884592, 0.28416769,True,True +174, 0.26715126, 0.28913396,True,True +175, 0.27424381, 0.29465200,True,True +176, 0.26278444, 0.28389907,True,True +177, 0.27884592, 0.28122140,True,True +178, 0.26965958, 0.28706944,True,True +179, 0.27884592, 0.29031120,True,True +180, 0.27556948, 0.28706944,True,True +181, 0.28467151, 0.28132200,True,True +182, 0.27435362, 0.28939994,True,True +183, 0.25727224, 0.26536923,True,True +184, 0.02088370, 0.01338259,True,True +185, 0.01360123, 0.01368535,True,True +186, 0.01218968, 0.02069220,True,True +187, 0.01489348, 0.02813706,True,True +188, 0.01208685, 0.01339907,True,True +189, 0.06587889, 0.02260906,True,True +190, 0.07325627, 0.03493840,True,True +191, 0.21407690, 0.22462453,True,True +192, 0.24230951, 0.24911082,True,True +193, 0.26417941, 0.27670971,True,True +194, 0.26573676, 0.27592677,True,True +195, 0.27774988, 0.29235676,True,True +196, 0.27448633, 0.28363814,True,True +197, 0.26603749, 0.28363814,True,True +198, 0.27894167, 0.28387229,True,True +199, 0.27190170, 0.28493478,True,True +200, 0.27448633, 0.28733513,True,True +201, 0.27774988, 0.28883339,True,True +202, 0.28933412, 0.29235676,True,True +203, 0.28607607, 0.28915618,True,True +204, 0.28593776, 0.29492306,True,True +205, 0.28028817, 0.28966629,True,True +206, 0.27566412, 0.28957076,True,True +207, 0.27661347, 0.29143903,True,True +208, 0.26603749, 0.28915618,True,True +209, 0.27904043, 0.28913396,True,True +210, 0.28499447, 0.29465200,True,True +211, 0.27566412, 0.29813491,True,True +212, 0.27674727, 0.29465200,True,True +213, 0.27566412, 0.28363814,True,True +214, 0.28607607, 0.29465200,True,True +215, 0.27129853, 0.29194358,True,True +216, 0.28810647, 0.29543364,True,True +217, 0.28476367, 0.28671125,True,True +218, 0.28132988, 0.29170131,True,True +219, 0.28217403, 0.29220632,True,True +220, 0.28364877, 0.30042672,True,True +221, 0.28476367, 0.30304016,True,True +222, 0.28378281, 0.29687768,True,True +223, 0.28396498, 0.30566975,True,True +224, 0.28387867, 0.30017115,True,True +225, 0.29422187, 0.30233665,True,True +226, 0.28378281, 0.30233665,True,True +227, 0.28607607, 0.30616180,True,True +228, 0.07306278, 0.04001991,True,True +229, 0.01190308, 0.02002629,True,True +230, 0.01767767, 0.01979643,True,True +231, 0.02384842, 0.01097841,True,True +232, 0.03500224, 0.01201562,True,True +233, 0.14034599, 0.10153823,True,True +234, 0.20675459, 0.22546911,True,True +235, 0.24530257, 0.25126705,True,True +236, 0.24239267, 0.26500531,True,True +237, 0.26391243, 0.27287946,True,True +238, 0.25075540, 0.28025274,True,True +239, 0.27674727, 0.28389907,True,True +240, 0.26921031, 0.29143903,True,True +241, 0.27909436, 0.29714485,True,True +242, 0.27323818, 0.28154177,True,True +243, 0.27372611, 0.28974508,True,True +244, 0.26667730, 0.28667322,True,True +245, 0.27129853, 0.28688769,True,True +246, 0.26921031, 0.28736231,True,True +247, 0.27690214, 0.28432221,True,True +248, 0.27806570, 0.28974508,True,True +249, 0.26818388, 0.28227222,True,True diff --git a/tests/files/test_1min.csv b/tests/files/test_1min.csv new file mode 100644 index 0000000..dca5fc2 --- /dev/null +++ b/tests/files/test_1min.csv @@ -0,0 +1,1770 @@ +frame,EAR2D6_l,EAR2D6_r,EAR2D6_valid,BS_Valid +0, 0.30799545, 0.28032574,True,True +1, 0.32456826, 0.28984380,True,True +2, 0.32122495, 0.28862193,True,True +3, 0.32450826, 0.29079934,True,True +4, 0.32450826, 0.29915607,True,True +5, 0.32450826, 0.28957659,True,True +6, 0.31844433, 0.28984380,True,True +7, 0.31380176, 0.28984380,True,True +8, 0.31305424, 0.30500184,True,True +9, 0.31761871, 0.28957659,True,True +10, 0.29833142, 0.28006730,True,True +11, 0.29833142, 0.28581396,True,True +12, 0.30799545, 0.29551837,True,True +13, 0.29827408, 0.28984380,True,True +14, 0.31173415, 0.28581396,True,True +15, 0.30799545, 0.29454412,True,True +16, 0.30950795, 0.29551837,True,True +17, 0.31575879, 0.29116053,True,True +18, 0.30956744, 0.28020945,True,True +19, 0.30805465, 0.29016782,True,True +20, 0.31510811, 0.29523517,True,True +21, 0.32251440, 0.29523517,True,True +22, 0.32251440, 0.29909700,True,True +23, 0.32137794, 0.29079934,True,True +24, 0.29845428, 0.28707951,True,True +25, 0.28708921, 0.27577628,True,True +26, 0.30805465, 0.27681827,True,True +27, 0.31510811, 0.28581396,True,True +28, 0.31179407, 0.29551837,True,True +29, 0.31155460, 0.28581396,True,True +30, 0.29630323, 0.28581396,True,True +31, 0.29635801, 0.27577628,True,True +32, 0.29988468, 0.28547138,True,True +33, 0.29652923, 0.28581396,True,True +34, 0.29988468, 0.28581396,True,True +35, 0.30228543, 0.28574522,True,True +36, 0.29839692, 0.27577628,True,True +37, 0.28873105, 0.28155289,True,True +38, 0.30805465, 0.28554006,True,True +39, 0.29833142, 0.28574522,True,True +40, 0.28873105, 0.29080448,True,True +41, 0.31767977, 0.29016782,True,True +42, 0.29827408, 0.28574522,True,True +43, 0.29833142, 0.30111890,True,True +44, 0.29630323, 0.29523517,True,True +45, 0.30799545, 0.29551837,True,True +46, 0.31913122, 0.28581396,True,True +47, 0.31504986, 0.28554006,True,True +48, 0.31173415, 0.28984380,True,True +49, 0.30799545, 0.29712804,True,True +50, 0.30574150, 0.28183707,True,True +51, 0.30950795, 0.28286004,True,True +52, 0.31995240, 0.29237810,True,True +53, 0.30799545, 0.28984380,True,True +54, 0.31971245, 0.28032574,True,True +55, 0.31510811, 0.28957659,True,True +56, 0.32944320, 0.28032574,True,True +57, 0.29839692, 0.27604081,True,True +58, 0.31028128, 0.28957659,True,True +59, 0.31761871, 0.30162897,True,True +60, 0.30050028, 0.28984380,True,True +61, 0.32245478, 0.30529441,True,True +62, 0.32128670, 0.28957659,True,True +63, 0.31299637, 0.28862193,True,True +64, 0.30805465, 0.28539579,True,True +65, 0.30799545, 0.28888826,True,True +66, 0.30799545, 0.29649261,True,True +67, 0.30799545, 0.28554006,True,True +68, 0.29630323, 0.27999994,True,True +69, 0.30781805, 0.27176321,True,True +70, 0.31915174, 0.28984380,True,True +71, 0.30361422, 0.28521419,True,True +72, 0.31767977, 0.29551837,True,True +73, 0.33093234, 0.29551837,True,True +74, 0.30799545, 0.29523517,True,True +75, 0.31778727, 0.29523517,True,True +76, 0.30956744, 0.29551837,True,True +77, 0.30799545, 0.28574522,True,True +78, 0.32122495, 0.27604081,True,True +79, 0.30799545, 0.28574522,True,True +80, 0.32128670, 0.29523517,True,True +81, 0.30579803, 0.28449807,True,True +82, 0.33193005, 0.29551837,True,True +83, 0.32105663, 0.29551837,True,True +84, 0.33093234, 0.27999994,True,True +85, 0.31179407, 0.29523517,True,True +86, 0.31504986, 0.29943212,True,True +87, 0.32122495, 0.29142256,True,True +88, 0.31761871, 0.29519218,True,True +89, 0.32122495, 0.29523517,True,True +90, 0.30574150, 0.29523517,True,True +91, 0.30574150, 0.28201377,True,True +92, 0.32122495, 0.28006730,True,True +93, 0.32122495, 0.28984380,True,True +94, 0.30799545, 0.29551837,True,True +95, 0.31761871, 0.29079934,True,True +96, 0.31913122, 0.29551837,True,True +97, 0.31995240, 0.28554006,True,True +98, 0.31761871, 0.29551837,True,True +99, 0.31299637, 0.28888826,True,True +100, 0.32122495, 0.28032574,True,True +101, 0.31504986, 0.28581396,True,True +102, 0.31299637, 0.29551837,True,True +103, 0.30574150, 0.29551837,True,True +104, 0.32251440, 0.29943212,True,True +105, 0.30355810, 0.28984380,True,True +106, 0.31299637, 0.28984380,True,True +107, 0.30574150, 0.28102196,True,True +108, 0.31504986, 0.28984380,True,True +109, 0.29630323, 0.28025831,True,True +110, 0.30557210, 0.29237810,True,True +111, 0.32944320, 0.28984380,True,True +112, 0.31977390, 0.28984380,True,True +113, 0.30574150, 0.28554006,True,True +114, 0.32450826, 0.29943212,True,True +115, 0.31299637, 0.30591493,True,True +116, 0.31761871, 0.29523517,True,True +117, 0.30805465, 0.29523517,True,True +118, 0.30799545, 0.29523517,True,True +119, 0.30361422, 0.28984380,True,True +120, 0.30950795, 0.28957659,True,True +121, 0.31767977, 0.28984380,True,True +122, 0.31761871, 0.30867649,True,True +123, 0.30799545, 0.29551837,True,True +124, 0.31504986, 0.30101088,True,True +125, 0.31504986, 0.28957659,True,True +126, 0.31767977, 0.30078653,True,True +127, 0.31761871, 0.28957659,True,True +128, 0.32122495, 0.29523517,True,True +129, 0.31305424, 0.29077900,True,True +130, 0.31971245, 0.29909700,True,True +131, 0.32122495, 0.28957659,True,True +132, 0.31299637, 0.29909700,True,True +133, 0.31504986, 0.30494162,True,True +134, 0.31504986, 0.30494162,True,True +135, 0.30805465, 0.30500184,True,True +136, 0.31356643, 0.29909700,True,True +137, 0.30805465, 0.28920373,True,True +138, 0.31844433, 0.30005166,True,True +139, 0.30055805, 0.29484005,True,True +140, 0.29259427, 0.29484005,True,True +141, 0.29827408, 0.27577628,True,True +142, 0.30579803, 0.29523517,True,True +143, 0.31305424, 0.30500184,True,True +144, 0.30574150, 0.30529441,True,True +145, 0.30574150, 0.30529441,True,True +146, 0.30574150, 0.29915607,True,True +147, 0.29254018, 0.28957659,True,True +148, 0.29271841, 0.28515792,True,True +149, 0.30579803, 0.29490929,True,True +150, 0.29635801, 0.29523517,True,True +151, 0.30566809, 0.29523517,True,True +152, 0.31157054, 0.28581396,True,True +153, 0.30211088, 0.28581396,True,True +154, 0.30216895, 0.28957659,True,True +155, 0.29827408, 0.29915607,True,True +156, 0.29613906, 0.28925696,True,True +157, 0.31504986, 0.28984380,True,True +158, 0.31305424, 0.28952388,True,True +159, 0.32456826, 0.29915607,True,True +160, 0.30799545, 0.28957659,True,True +161, 0.30211088, 0.29877737,True,True +162, 0.30213052, 0.29484005,True,True +163, 0.30574150, 0.29523517,True,True +164, 0.31022165, 0.30500184,True,True +165, 0.30574150, 0.30500184,True,True +166, 0.32128670, 0.30453351,True,True +167, 0.30795653, 0.29523517,True,True +168, 0.31510811, 0.28984380,True,True +169, 0.32450826, 0.29913216,True,True +170, 0.29630323, 0.29909700,True,True +171, 0.32450826, 0.30867649,True,True +172, 0.29635801, 0.28957659,True,True +173, 0.29635801, 0.30494162,True,True +174, 0.30574150, 0.29909700,True,True +175, 0.30574150, 0.29551837,True,True +176, 0.32450826, 0.30867649,True,True +177, 0.29635801, 0.28957659,True,True +178, 0.30579803, 0.29909700,True,True +179, 0.30425807, 0.29352982,True,True +180, 0.30355810, 0.29915607,True,True +181, 0.31504986, 0.28957659,True,True +182, 0.30574150, 0.30867649,True,True +183, 0.29630323, 0.29877737,True,True +184, 0.31761871, 0.30867649,True,True +185, 0.32450826, 0.30837680,True,True +186, 0.29630323, 0.30867649,True,True +187, 0.30050028, 0.29523517,True,True +188, 0.32450826, 0.29885638,True,True +189, 0.31519991, 0.29915607,True,True +190, 0.32450826, 0.29915607,True,True +191, 0.31971245, 0.29871189,True,True +192, 0.30574150, 0.29885638,True,True +193, 0.32122495, 0.31015773,True,True +194, 0.31821784, 0.30867649,True,True +195, 0.31710334, 0.30494162,True,True +196, 0.32122495, 0.32404311,True,True +197, 0.31504986, 0.29915607,True,True +198, 0.32450826, 0.30867649,True,True +199, 0.32450826, 0.31797622,True,True +200, 0.31504986, 0.31428712,True,True +201, 0.32711001, 0.30867649,True,True +202, 0.31504986, 0.29915607,True,True +203, 0.30211088, 0.30453351,True,True +204, 0.32944320, 0.31825831,True,True +205, 0.31299637, 0.30827904,True,True +206, 0.32450826, 0.30837680,True,True +207, 0.32122495, 0.29523517,True,True +208, 0.31504986, 0.29352982,True,True +209, 0.31504986, 0.30867649,True,True +210, 0.31487530, 0.30867649,True,True +211, 0.30557210, 0.29915607,True,True +212, 0.32450826, 0.31825831,True,True +213, 0.31356643, 0.30837680,True,True +214, 0.31487530, 0.30500184,True,True +215, 0.31487530, 0.30778090,True,True +216, 0.32432846, 0.29915607,True,True +217, 0.33086875, 0.30867649,True,True +218, 0.32450826, 0.31756680,True,True +219, 0.32450826, 0.31825831,True,True +220, 0.30910765, 0.29885638,True,True +221, 0.34039463, 0.31736272,True,True +222, 0.30557210, 0.30896132,True,True +223, 0.31155460, 0.30867649,True,True +224, 0.32450826, 0.31825831,True,True +225, 0.32103993, 0.31756680,True,True +226, 0.31155460, 0.31825831,True,True +227, 0.30193687, 0.29885638,True,True +228, 0.31487530, 0.30827904,True,True +229, 0.32432846, 0.31756680,True,True +230, 0.31173415, 0.31470830,True,True +231, 0.33086875, 0.29915607,True,True +232, 0.32450826, 0.29915607,True,True +233, 0.31155460, 0.30073338,True,True +234, 0.31155460, 0.31015773,True,True +235, 0.31339269, 0.29909700,True,True +236, 0.32122495, 0.31015773,True,True +237, 0.32103993, 0.30867649,True,True +238, 0.33067817, 0.31855199,True,True +239, 0.33036128, 0.29915607,True,True +240, 0.32073228, 0.30867649,True,True +241, 0.32103993, 0.30827904,True,True +242, 0.32122495, 0.30073338,True,True +243, 0.31952830, 0.31015773,True,True +244, 0.31777583, 0.31825831,True,True +245, 0.32716092, 0.31015773,True,True +246, 0.30748811, 0.30287118,True,True +247, 0.31155460, 0.29440856,True,True +248, 0.33366604, 0.30975837,True,True +249, 0.31487530, 0.29915607,True,True +250, 0.32103993, 0.29915607,True,True +251, 0.31155460, 0.29915607,True,True +252, 0.31155460, 0.29877088,True,True +253, 0.31952830, 0.31428712,True,True +254, 0.31777583, 0.31470830,True,True +255, 0.31519991, 0.31784852,True,True +256, 0.32137794, 0.30827904,True,True +257, 0.30557210, 0.29871189,True,True +258, 0.30557210, 0.29440856,True,True +259, 0.30557210, 0.28532398,True,True +260, 0.30557210, 0.28471380,True,True +261, 0.31155460, 0.30019122,True,True +262, 0.31487530, 0.28920373,True,True +263, 0.30557210, 0.29310804,True,True +264, 0.30164752, 0.28102196,True,True +265, 0.29862313, 0.28102196,True,True +266, 0.30193687, 0.29210855,True,True +267, 0.31155460, 0.29015716,True,True +268, 0.30193687, 0.29115389,True,True +269, 0.30193687, 0.29077900,True,True +270, 0.30544225, 0.29347186,True,True +271, 0.31125603, 0.28270844,True,True +272, 0.30193687, 0.27970669,True,True +273, 0.30516066, 0.29115389,True,True +274, 0.30557210, 0.28006730,True,True +275, 0.31253455, 0.29440856,True,True +276, 0.29613906, 0.29115389,True,True +277, 0.31125603, 0.28984380,True,True +278, 0.30557210, 0.29053124,True,True +279, 0.30544225, 0.28581396,True,True +280, 0.32103993, 0.28957659,True,True +281, 0.29586604, 0.29210855,True,True +282, 0.30311021, 0.28567814,True,True +283, 0.30974585, 0.29210855,True,True +284, 0.31004297, 0.30287118,True,True +285, 0.31458501, 0.29467010,True,True +286, 0.30529039, 0.29210855,True,True +287, 0.30903324, 0.29115389,True,True +288, 0.29586604, 0.29115389,True,True +289, 0.30516066, 0.28201377,True,True +290, 0.30489730, 0.28032574,True,True +291, 0.30932968, 0.28413049,True,True +292, 0.30380915, 0.28506720,True,True +293, 0.30516066, 0.29237810,True,True +294, 0.30903324, 0.29551837,True,True +295, 0.30529039, 0.29142256,True,True +296, 0.31864175, 0.29937300,True,True +297, 0.32073228, 0.30057824,True,True +298, 0.30529039, 0.29523517,True,True +299, 0.32073228, 0.29915607,True,True +300, 0.31458501, 0.30073338,True,True +301, 0.30539196, 0.29684329,True,True +302, 0.30539196, 0.28753504,True,True +303, 0.30164752, 0.28128127,True,True +304, 0.32073228, 0.30085560,True,True +305, 0.31155460, 0.28850929,True,True +306, 0.30903324, 0.29210855,True,True +307, 0.31519196, 0.29152120,True,True +308, 0.30903324, 0.30181114,True,True +309, 0.31155460, 0.29915607,True,True +310, 0.31458501, 0.31015773,True,True +311, 0.31745904, 0.29909700,True,True +312, 0.31125603, 0.30032854,True,True +313, 0.30752306, 0.29210855,True,True +314, 0.30781805, 0.29523517,True,True +315, 0.31112377, 0.29937300,True,True +316, 0.31777583, 0.29684329,True,True +317, 0.31155460, 0.31015773,True,True +318, 0.32282280, 0.30085560,True,True +319, 0.32073228, 0.30494162,True,True +320, 0.32073228, 0.29937300,True,True +321, 0.31155460, 0.29684329,True,True +322, 0.32103993, 0.29909700,True,True +323, 0.32103993, 0.30772001,True,True +324, 0.33694503, 0.30500184,True,True +325, 0.31125603, 0.30057824,True,True +326, 0.30557210, 0.30019122,True,True +327, 0.31155460, 0.29115389,True,True +328, 0.32745058, 0.30469630,True,True +329, 0.30557210, 0.30057824,True,True +330, 0.31745904, 0.30500184,True,True +331, 0.31777583, 0.31652181,True,True +332, 0.31777583, 0.30500184,True,True +333, 0.31777583, 0.28554006,True,True +334, 0.31487530, 0.30827904,True,True +335, 0.30557210, 0.30867649,True,True +336, 0.32073228, 0.30867649,True,True +337, 0.31745904, 0.29937300,True,True +338, 0.33694503, 0.29915607,True,True +339, 0.33036128, 0.30867649,True,True +340, 0.30003939, 0.29523517,True,True +341, 0.32073228, 0.30896132,True,True +342, 0.31922209, 0.30660997,True,True +343, 0.31864175, 0.31470830,True,True +344, 0.30932968, 0.30867649,True,True +345, 0.32073228, 0.31440275,True,True +346, 0.31864175, 0.31501017,True,True +347, 0.33036128, 0.32478861,True,True +348, 0.31550649, 0.29915607,True,True +349, 0.32103993, 0.29915607,True,True +350, 0.31623402, 0.30500184,True,True +351, 0.32893792, 0.31470830,True,True +352, 0.32684739, 0.31501017,True,True +353, 0.30932968, 0.30494162,True,True +354, 0.33036128, 0.30867649,True,True +355, 0.32193479, 0.30500184,True,True +356, 0.33002832, 0.31379521,True,True +357, 0.32827075, 0.31501017,True,True +358, 0.32377444, 0.31501017,True,True +359, 0.32827075, 0.30867649,True,True +360, 0.31591876, 0.31470830,True,True +361, 0.33549331, 0.31652181,True,True +362, 0.31004297, 0.29909700,True,True +363, 0.31777583, 0.30111890,True,True +364, 0.30796606, 0.29523517,True,True +365, 0.31396467, 0.29523517,True,True +366, 0.29942474, 0.30674576,True,True +367, 0.31591876, 0.29712804,True,True +368, 0.31591876, 0.31132915,True,True +369, 0.28850929, 0.29523517,True,True +370, 0.29942474, 0.30469630,True,True +371, 0.31024988, 0.30111890,True,True +372, 0.31591876, 0.29523517,True,True +373, 0.31396467, 0.29484005,True,True +374, 0.32160066, 0.29523517,True,True +375, 0.31024988, 0.29523517,True,True +376, 0.30992788, 0.29523517,True,True +377, 0.31396467, 0.29484005,True,True +378, 0.31415292, 0.28554006,True,True +379, 0.32267714, 0.29484005,True,True +380, 0.29687029, 0.28554006,True,True +381, 0.30436250, 0.29523517,True,True +382, 0.31304436, 0.29484005,True,True +383, 0.32036156, 0.29523517,True,True +384, 0.32193479, 0.29523517,True,True +385, 0.29444679, 0.29386804,True,True +386, 0.31550649, 0.31025393,True,True +387, 0.30418012, 0.29523517,True,True +388, 0.32036156, 0.31108021,True,True +389, 0.32193479, 0.31058583,True,True +390, 0.31550649, 0.32022208,True,True +391, 0.31550649, 0.30069972,True,True +392, 0.30799545, 0.29484005,True,True +393, 0.31550649, 0.30500184,True,True +394, 0.31550649, 0.30453351,True,True +395, 0.31550649, 0.30428852,True,True +396, 0.29561716, 0.30500184,True,True +397, 0.29810228, 0.29484005,True,True +398, 0.31192515, 0.28515792,True,True +399, 0.31550649, 0.29386804,True,True +400, 0.30796606, 0.28515792,True,True +401, 0.29971195, 0.30500184,True,True +402, 0.31396467, 0.30500184,True,True +403, 0.30632425, 0.30469630,True,True +404, 0.31256547, 0.29484005,True,True +405, 0.30569671, 0.29523517,True,True +406, 0.32193479, 0.30500184,True,True +407, 0.31004297, 0.30500184,True,True +408, 0.31256547, 0.30459366,True,True +409, 0.29971195, 0.29523517,True,True +410, 0.30781805, 0.29523517,True,True +411, 0.30781805, 0.29484005,True,True +412, 0.30569671, 0.28547138,True,True +413, 0.30569671, 0.29523517,True,True +414, 0.30569671, 0.29523517,True,True +415, 0.30932968, 0.28006730,True,True +416, 0.30632425, 0.29426185,True,True +417, 0.30569671, 0.30078653,True,True +418, 0.29591216, 0.29523517,True,True +419, 0.29591216, 0.29523517,True,True +420, 0.30539196, 0.31108021,True,True +421, 0.30590524, 0.30078653,True,True +422, 0.30815071, 0.29523517,True,True +423, 0.30569671, 0.29523517,True,True +424, 0.29608958, 0.29484005,True,True +425, 0.30678600, 0.29523517,True,True +426, 0.29444679, 0.29523517,True,True +427, 0.30781805, 0.30500184,True,True +428, 0.30650791, 0.30078653,True,True +429, 0.31642362, 0.30453351,True,True +430, 0.32287859, 0.30453351,True,True +431, 0.29971195, 0.30459366,True,True +432, 0.30974585, 0.30837680,True,True +433, 0.31777583, 0.29451462,True,True +434, 0.31022165, 0.29484005,True,True +435, 0.30211088, 0.29644603,True,True +436, 0.29810228, 0.30078653,True,True +437, 0.30032720, 0.29523517,True,True +438, 0.30077292, 0.30036782,True,True +439, 0.29669240, 0.29523517,True,True +440, 0.29810228, 0.28957659,True,True +441, 0.29810228, 0.28957659,True,True +442, 0.29687029, 0.29484005,True,True +443, 0.32122495, 0.29451462,True,True +444, 0.30678600, 0.30036782,True,True +445, 0.30050028, 0.29484005,True,True +446, 0.31745904, 0.31470830,True,True +447, 0.31623402, 0.30453351,True,True +448, 0.31569566, 0.29523517,True,True +449, 0.30832874, 0.28515792,True,True +450, 0.31022165, 0.29484005,True,True +451, 0.29988468, 0.28515792,True,True +452, 0.31415292, 0.29082516,True,True +453, 0.31777583, 0.29490929,True,True +454, 0.31913122, 0.29915607,True,True +455, 0.29608958, 0.28920373,True,True +456, 0.32764691, 0.29484005,True,True +457, 0.32764691, 0.31398198,True,True +458, 0.30590524, 0.31337525,True,True +459, 0.30678600, 0.30459366,True,True +460, 0.31569566, 0.30362165,True,True +461, 0.30569671, 0.29123058,True,True +462, 0.31569566, 0.29484005,True,True +463, 0.31173415, 0.29523517,True,True +464, 0.30832874, 0.28515792,True,True +465, 0.29851309, 0.29484005,True,True +466, 0.30588000, 0.29484005,True,True +467, 0.31796637, 0.29877088,True,True +468, 0.31155460, 0.29484005,True,True +469, 0.31155460, 0.28920373,True,True +470, 0.31155460, 0.29523517,True,True +471, 0.32122495, 0.30827904,True,True +472, 0.30781805, 0.30500184,True,True +473, 0.29942474, 0.29915607,True,True +474, 0.31796637, 0.29915607,True,True +475, 0.31022165, 0.30453351,True,True +476, 0.30650791, 0.30459366,True,True +477, 0.31022165, 0.29915607,True,True +478, 0.31777583, 0.28920373,True,True +479, 0.31796637, 0.30500184,True,True +480, 0.31777583, 0.29077900,True,True +481, 0.30932968, 0.28920373,True,True +482, 0.31173415, 0.30453351,True,True +483, 0.31173415, 0.28920373,True,True +484, 0.31155460, 0.29484005,True,True +485, 0.31155460, 0.29115389,True,True +486, 0.31155460, 0.29484005,True,True +487, 0.31155460, 0.28920373,True,True +488, 0.31155460, 0.29523517,True,True +489, 0.31155460, 0.28920373,True,True +490, 0.31777583, 0.28554006,True,True +491, 0.30796606, 0.28920373,True,True +492, 0.31777583, 0.29484005,True,True +493, 0.30193687, 0.30459366,True,True +494, 0.31777583, 0.28920373,True,True +495, 0.31777583, 0.30019122,True,True +496, 0.31777583, 0.30500184,True,True +497, 0.31155460, 0.29877088,True,True +498, 0.31155460, 0.29484005,True,True +499, 0.31764080, 0.30500184,True,True +500, 0.31777583, 0.30500184,True,True +501, 0.31777583, 0.29915607,True,True +502, 0.31155460, 0.29523517,True,True +503, 0.30193687, 0.29523517,True,True +504, 0.30164752, 0.29210855,True,True +505, 0.29971195, 0.28957659,True,True +506, 0.31155460, 0.29877088,True,True +507, 0.30815071, 0.29523517,True,True +508, 0.29249359, 0.28957659,True,True +509, 0.30796606, 0.29523517,True,True +510, 0.29249359, 0.30034616,True,True +511, 0.31155460, 0.30073338,True,True +512, 0.29833421, 0.30500184,True,True +513, 0.31550649, 0.29909700,True,True +514, 0.30193687, 0.30073338,True,True +515, 0.31125603, 0.29871189,True,True +516, 0.30557210, 0.30827904,True,True +517, 0.30193687, 0.30500184,True,True +518, 0.30569671, 0.30453351,True,True +519, 0.31764080, 0.30494162,True,True +520, 0.31550649, 0.30494162,True,True +521, 0.31777583, 0.30604168,True,True +522, 0.31777583, 0.29877088,True,True +523, 0.31173415, 0.30500184,True,True +524, 0.30950795, 0.29484005,True,True +525, 0.31777583, 0.30453351,True,True +526, 0.31796637, 0.30500184,True,True +527, 0.29833421, 0.29915607,True,True +528, 0.31796637, 0.29523517,True,True +529, 0.31155460, 0.30453351,True,True +530, 0.31155460, 0.29523517,True,True +531, 0.31364713, 0.30827904,True,True +532, 0.31173415, 0.29077900,True,True +533, 0.31022165, 0.29871189,True,True +534, 0.30193687, 0.30453351,True,True +535, 0.30932968, 0.29484005,True,True +536, 0.31155460, 0.29484005,True,True +537, 0.31155460, 0.29523517,True,True +538, 0.29827408, 0.29077900,True,True +539, 0.31777583, 0.30500184,True,True +540, 0.31796637, 0.30453351,True,True +541, 0.32764691, 0.30917347,True,True +542, 0.31155460, 0.29053124,True,True +543, 0.30950795, 0.29484005,True,True +544, 0.31155460, 0.30073338,True,True +545, 0.31777583, 0.29484005,True,True +546, 0.31777583, 0.30453351,True,True +547, 0.31155460, 0.30827904,True,True +548, 0.31173415, 0.29877088,True,True +549, 0.31777583, 0.29915607,True,True +550, 0.30796606, 0.30500184,True,True +551, 0.30796606, 0.29115389,True,True +552, 0.31173415, 0.30660997,True,True +553, 0.31777583, 0.29915607,True,True +554, 0.31777583, 0.30500184,True,True +555, 0.30588000, 0.30111890,True,True +556, 0.29971195, 0.28957659,True,True +557, 0.31623402, 0.31157716,True,True +558, 0.29266216, 0.28957659,True,True +559, 0.32764691, 0.31428712,True,True +560, 0.30632425, 0.30500184,True,True +561, 0.29971195, 0.30428852,True,True +562, 0.31504986, 0.30975837,True,True +563, 0.31796637, 0.29523517,True,True +564, 0.30590524, 0.31058583,True,True +565, 0.31796637, 0.28920373,True,True +566, 0.29266216, 0.29523517,True,True +567, 0.30211088, 0.30034616,True,True +568, 0.29851309, 0.28957659,True,True +569, 0.31796637, 0.31428712,True,True +570, 0.31155460, 0.29877088,True,True +571, 0.31173415, 0.29966531,True,True +572, 0.30193687, 0.29877088,True,True +573, 0.29266216, 0.30500184,True,True +574, 0.31173415, 0.28920373,True,True +575, 0.31173415, 0.28920373,True,True +576, 0.31796637, 0.29523517,True,True +577, 0.28703614, 0.29077900,True,True +578, 0.31173415, 0.28888451,True,True +579, 0.30193687, 0.28920373,True,True +580, 0.29613906, 0.28920373,True,True +581, 0.29266216, 0.29484005,True,True +582, 0.30574150, 0.30034616,True,True +583, 0.31173415, 0.31428712,True,True +584, 0.30574150, 0.29484005,True,True +585, 0.31796637, 0.31428712,True,True +586, 0.31022165, 0.29484005,True,True +587, 0.28679421, 0.28006730,True,True +588, 0.29851309, 0.28515792,True,True +589, 0.29687029, 0.28088066,True,True +590, 0.29591216, 0.27540720,True,True +591, 0.28872267, 0.27102027,True,True +592, 0.27222218, 0.24654977,True,True +593, 0.27470122, 0.24680592,True,True +594, 0.27205234, 0.24654977,True,True +595, 0.27050253, 0.25123401,True,True +596, 0.25747070, 0.22109358,True,True +597, 0.25747070, 0.22109358,True,True +598, 0.25265509, 0.22095636,True,True +599, 0.25747070, 0.22109358,True,True +600, 0.25747070, 0.23146749,True,True +601, 0.25752050, 0.23146749,True,True +602, 0.27574627, 0.24680592,True,True +603, 0.25747070, 0.22660419,True,True +604, 0.27222218, 0.22660419,True,True +605, 0.26037704, 0.24654977,True,True +606, 0.27205234, 0.24680592,True,True +607, 0.29016612, 0.26231333,True,True +608, 0.27205234, 0.25183791,True,True +609, 0.29639357, 0.26144334,True,True +610, 0.28038855, 0.27139808,True,True +611, 0.29442873, 0.27691633,True,True +612, 0.28615839, 0.26170423,True,True +613, 0.27461839, 0.27131747,True,True +614, 0.28679421, 0.27166890,True,True +615, 0.29282021, 0.27883842,True,True +616, 0.28696617, 0.27749571,True,True +617, 0.28679421, 0.28127221,True,True +618, 0.30273738, 0.28127221,True,True +619, 0.29608958, 0.28091616,True,True +620, 0.28696617, 0.28088066,True,True +621, 0.29833421, 0.29123058,True,True +622, 0.29669240, 0.28554006,True,True +623, 0.29608958, 0.29123058,True,True +624, 0.27896556, 0.27540720,True,True +625, 0.30423720, 0.27749571,True,True +626, 0.30588000, 0.29082516,True,True +627, 0.28867556, 0.28515792,True,True +628, 0.30588000, 0.28554006,True,True +629, 0.29444679, 0.29484005,True,True +630, 0.29266216, 0.28515792,True,True +631, 0.30588000, 0.28515792,True,True +632, 0.30569671, 0.29123058,True,True +633, 0.30632425, 0.28554006,True,True +634, 0.28867556, 0.28515792,True,True +635, 0.29827408, 0.28515792,True,True +636, 0.30588000, 0.29523517,True,True +637, 0.29028616, 0.29484005,True,True +638, 0.31777583, 0.30494162,True,True +639, 0.31777583, 0.30494162,True,True +640, 0.31761871, 0.31428712,True,True +641, 0.29827408, 0.31428712,True,True +642, 0.30799545, 0.30453351,True,True +643, 0.30588000, 0.29523517,True,True +644, 0.29827408, 0.30111890,True,True +645, 0.30569671, 0.29484005,True,True +646, 0.31022165, 0.30459366,True,True +647, 0.31155460, 0.29871189,True,True +648, 0.31796637, 0.29523517,True,True +649, 0.29971195, 0.29484005,True,True +650, 0.31777583, 0.30500184,True,True +651, 0.30588000, 0.30111890,True,True +652, 0.31971245, 0.31076858,True,True +653, 0.31173415, 0.30500184,True,True +654, 0.31796637, 0.29915607,True,True +655, 0.30799545, 0.30459366,True,True +656, 0.30799545, 0.29523517,True,True +657, 0.31796637, 0.30459366,True,True +658, 0.31155460, 0.30459366,True,True +659, 0.30211088, 0.29877088,True,True +660, 0.31173415, 0.30500184,True,True +661, 0.31022165, 0.29490929,True,True +662, 0.32122495, 0.29877088,True,True +663, 0.30796606, 0.31428712,True,True +664, 0.31173415, 0.31428712,True,True +665, 0.31504986, 0.30459366,True,True +666, 0.32122495, 0.29877088,True,True +667, 0.31022165, 0.31428712,True,True +668, 0.31155460, 0.29877088,True,True +669, 0.33086875, 0.29877088,True,True +670, 0.31173415, 0.31428712,True,True +671, 0.31364713, 0.30019122,True,True +672, 0.32103993, 0.31428712,True,True +673, 0.32103993, 0.29909700,True,True +674, 0.32745058, 0.30494162,True,True +675, 0.31913122, 0.30459366,True,True +676, 0.32122495, 0.30005166,True,True +677, 0.31364713, 0.30975837,True,True +678, 0.31142221, 0.30073338,True,True +679, 0.32103993, 0.29871189,True,True +680, 0.32122495, 0.30019122,True,True +681, 0.31155460, 0.30837680,True,True +682, 0.31142221, 0.29877737,True,True +683, 0.31142221, 0.29877737,True,True +684, 0.31155460, 0.31470830,True,True +685, 0.30557210, 0.30453351,True,True +686, 0.30529039, 0.29915607,True,True +687, 0.30557210, 0.30500184,True,True +688, 0.31777583, 0.29523517,True,True +689, 0.30193687, 0.29523517,True,True +690, 0.29827408, 0.29684329,True,True +691, 0.31155460, 0.29115389,True,True +692, 0.31155460, 0.29115389,True,True +693, 0.30557210, 0.29523517,True,True +694, 0.31155460, 0.30500184,True,True +695, 0.31155460, 0.29523517,True,True +696, 0.31155460, 0.30073338,True,True +697, 0.31155460, 0.29915607,True,True +698, 0.30557210, 0.30827904,True,True +699, 0.29630323, 0.29523517,True,True +700, 0.31155460, 0.29915607,True,True +701, 0.31155460, 0.30867649,True,True +702, 0.31155460, 0.29915607,True,True +703, 0.31777583, 0.31428712,True,True +704, 0.31436826, 0.30459366,True,True +705, 0.31155460, 0.29115389,True,True +706, 0.30557210, 0.30005166,True,True +707, 0.32387770, 0.30837680,True,True +708, 0.33067817, 0.30249571,True,True +709, 0.31155460, 0.30019122,True,True +710, 0.31155460, 0.28984380,True,True +711, 0.30557210, 0.30005166,True,True +712, 0.30557210, 0.30827904,True,True +713, 0.32103993, 0.28957659,True,True +714, 0.30950795, 0.29871189,True,True +715, 0.31436826, 0.29347186,True,True +716, 0.31155460, 0.29909700,True,True +717, 0.33067817, 0.29909700,True,True +718, 0.32103993, 0.29915607,True,True +719, 0.31777583, 0.29523517,True,True +720, 0.31155460, 0.30494162,True,True +721, 0.31155460, 0.30005166,True,True +722, 0.31173415, 0.29115389,True,True +723, 0.31155460, 0.30432456,True,True +724, 0.30574150, 0.29115389,True,True +725, 0.32122495, 0.30975837,True,True +726, 0.31004297, 0.28984380,True,True +727, 0.30799545, 0.29173243,True,True +728, 0.31155460, 0.30005166,True,True +729, 0.30557210, 0.30957207,True,True +730, 0.31642362, 0.29523517,True,True +731, 0.31777583, 0.29523517,True,True +732, 0.31173415, 0.30827904,True,True +733, 0.31504986, 0.31825831,True,True +734, 0.32450826, 0.30287118,True,True +735, 0.30799545, 0.29523517,True,True +736, 0.30557210, 0.30249571,True,True +737, 0.30799545, 0.30500184,True,True +738, 0.31155460, 0.31015773,True,True +739, 0.29827408, 0.29649261,True,True +740, 0.31299637, 0.30867649,True,True +741, 0.31299637, 0.29915607,True,True +742, 0.31913122, 0.30073338,True,True +743, 0.30557210, 0.31797622,True,True +744, 0.29810228, 0.30494162,True,True +745, 0.30799545, 0.29915607,True,True +746, 0.29988468, 0.29915607,True,True +747, 0.30574150, 0.29915607,True,True +748, 0.31155460, 0.29915607,True,True +749, 0.31510811, 0.30867649,True,True +750, 0.30338990, 0.30867649,True,True +751, 0.31305424, 0.29915607,True,True +752, 0.30574150, 0.29915607,True,True +753, 0.30557210, 0.29943212,True,True +754, 0.31504986, 0.29915607,True,True +755, 0.31510811, 0.30867649,True,True +756, 0.32122495, 0.30073338,True,True +757, 0.32122495, 0.31470830,True,True +758, 0.31504986, 0.31470830,True,True +759, 0.32450826, 0.32598754,True,True +760, 0.31504986, 0.32750583,True,True +761, 0.31525818, 0.30500184,True,True +762, 0.31022165, 0.29915607,True,True +763, 0.30574150, 0.31826964,True,True +764, 0.31299637, 0.31825831,True,True +765, 0.32450826, 0.31855199,True,True +766, 0.30211088, 0.29943212,True,True +767, 0.31525818, 0.32478861,True,True +768, 0.31510811, 0.29915607,True,True +769, 0.31504986, 0.31855199,True,True +770, 0.31510811, 0.32404311,True,True +771, 0.31510811, 0.31470830,True,True +772, 0.31385978, 0.29915607,True,True +773, 0.32128670, 0.30827904,True,True +774, 0.31356643, 0.32447736,True,True +775, 0.31305424, 0.31973955,True,True +776, 0.31305424, 0.29915607,True,True +777, 0.31519991, 0.30867649,True,True +778, 0.31504986, 0.29915607,True,True +779, 0.31504986, 0.29885638,True,True +780, 0.32450826, 0.30896132,True,True +781, 0.31299637, 0.29142256,True,True +782, 0.32251440, 0.29684329,True,True +783, 0.30799545, 0.30494162,True,True +784, 0.30799545, 0.30500184,True,True +785, 0.30338990, 0.30867649,True,True +786, 0.31519991, 0.30896132,True,True +787, 0.32456826, 0.31470830,True,True +788, 0.31510811, 0.30500184,True,True +789, 0.31305424, 0.29885638,True,True +790, 0.32456826, 0.30867649,True,True +791, 0.32456826, 0.29943212,True,True +792, 0.31510811, 0.31470830,True,True +793, 0.31510811, 0.31470830,True,True +794, 0.31510811, 0.31101879,True,True +795, 0.31767977, 0.30494162,True,True +796, 0.31977390, 0.30500184,True,True +797, 0.32316986, 0.30896132,True,True +798, 0.31977390, 0.30523413,True,True +799, 0.31299637, 0.31621848,True,True +800, 0.31510811, 0.30674576,True,True +801, 0.31305424, 0.29909700,True,True +802, 0.31510811, 0.29551837,True,True +803, 0.31510811, 0.30500184,True,True +804, 0.31510811, 0.31470830,True,True +805, 0.31510811, 0.30494162,True,True +806, 0.32456826, 0.32447736,True,True +807, 0.31504986, 0.29943212,True,True +808, 0.31305424, 0.30867649,True,True +809, 0.31504986, 0.31825831,True,True +810, 0.31504986, 0.31825831,True,True +811, 0.31510811, 0.31470830,True,True +812, 0.31510811, 0.32404311,True,True +813, 0.31362440, 0.31470830,True,True +814, 0.29833142, 0.30500184,True,True +815, 0.31504986, 0.31470830,True,True +816, 0.29477808, 0.31501017,True,True +817, 0.30361422, 0.30494162,True,True +818, 0.30361422, 0.29551837,True,True +819, 0.31362440, 0.30494162,True,True +820, 0.31767977, 0.29551837,True,True +821, 0.30361422, 0.30645180,True,True +822, 0.30361422, 0.30742512,True,True +823, 0.31504986, 0.31501017,True,True +824, 0.31510811, 0.31470830,True,True +825, 0.30425807, 0.31470830,True,True +826, 0.30361422, 0.31470830,True,True +827, 0.31504986, 0.31470830,True,True +828, 0.30579803, 0.31621848,True,True +829, 0.30579803, 0.30500184,True,True +830, 0.30579803, 0.31470830,True,True +831, 0.30579803, 0.30896132,True,True +832, 0.31362440, 0.30500184,True,True +833, 0.30425807, 0.31470830,True,True +834, 0.30579803, 0.31621848,True,True +835, 0.31510811, 0.31501017,True,True +836, 0.30805465, 0.31470830,True,True +837, 0.31510811, 0.29551837,True,True +838, 0.31504986, 0.30660997,True,True +839, 0.30574150, 0.31108021,True,True +840, 0.31510811, 0.31108021,True,True +841, 0.31510811, 0.30500184,True,True +842, 0.31510811, 0.31132915,True,True +843, 0.31510811, 0.31470830,True,True +844, 0.31510811, 0.29551837,True,True +845, 0.30579803, 0.30500184,True,True +846, 0.31504986, 0.31501017,True,True +847, 0.31510811, 0.31621848,True,True +848, 0.31305424, 0.30500184,True,True +849, 0.30431433, 0.30500184,True,True +850, 0.31977390, 0.30500184,True,True +851, 0.30425807, 0.31470830,True,True +852, 0.30361422, 0.31470830,True,True +853, 0.31022165, 0.31470830,True,True +854, 0.31971245, 0.30867649,True,True +855, 0.31510811, 0.31470830,True,True +856, 0.33245288, 0.30660997,True,True +857, 0.31356643, 0.31470830,True,True +858, 0.31362440, 0.31470830,True,True +859, 0.31510811, 0.30500184,True,True +860, 0.32450826, 0.31621848,True,True +861, 0.31701589, 0.30867649,True,True +862, 0.30916267, 0.30867649,True,True +863, 0.31362440, 0.31470830,True,True +864, 0.31510811, 0.31621848,True,True +865, 0.31510811, 0.31272039,True,True +866, 0.32456826, 0.30867649,True,True +867, 0.31510811, 0.31501017,True,True +868, 0.31977390, 0.31105331,True,True +869, 0.31510811, 0.30162897,True,True +870, 0.31510811, 0.31470830,True,True +871, 0.31305424, 0.30660997,True,True +872, 0.31504986, 0.30867649,True,True +873, 0.31510811, 0.30867649,True,True +874, 0.31510811, 0.30867649,True,True +875, 0.31305424, 0.30500184,True,True +876, 0.31510811, 0.30500184,True,True +877, 0.31510811, 0.30523413,True,True +878, 0.31510811, 0.30523413,True,True +879, 0.31362440, 0.30500184,True,True +880, 0.31362440, 0.30500184,True,True +881, 0.31977390, 0.29523517,True,True +882, 0.31510811, 0.31470830,True,True +883, 0.31510811, 0.29523517,True,True +884, 0.31510811, 0.30500184,True,True +885, 0.31305424, 0.30500184,True,True +886, 0.30579803, 0.30500184,True,True +887, 0.31510811, 0.31621848,True,True +888, 0.31504986, 0.29237810,True,True +889, 0.31362440, 0.29523517,True,True +890, 0.31510811, 0.31621848,True,True +891, 0.30361422, 0.29523517,True,True +892, 0.31305424, 0.31470830,True,True +893, 0.31305424, 0.30500184,True,True +894, 0.31305424, 0.29523517,True,True +895, 0.31028128, 0.29523517,True,True +896, 0.31385978, 0.30523413,True,True +897, 0.31305424, 0.30500184,True,True +898, 0.30574150, 0.30275907,True,True +899, 0.31022165, 0.30500184,True,True +900, 0.31161836, 0.30078653,True,True +901, 0.31022165, 0.29551837,True,True +902, 0.31510811, 0.29523517,True,True +903, 0.31525818, 0.29684329,True,True +904, 0.30579803, 0.29523517,True,True +905, 0.30361422, 0.30141938,True,True +906, 0.30355810, 0.29523517,True,True +907, 0.31307438, 0.29523517,True,True +908, 0.33093234, 0.31743577,True,True +909, 0.30799545, 0.29551837,True,True +910, 0.32950652, 0.31470830,True,True +911, 0.32245478, 0.30500184,True,True +912, 0.30574150, 0.30111890,True,True +913, 0.30574150, 0.30111890,True,True +914, 0.31519991, 0.30111890,True,True +915, 0.31305424, 0.30141938,True,True +916, 0.30213052, 0.31108021,True,True +917, 0.31525818, 0.30660997,True,True +918, 0.31173415, 0.30211161,True,True +919, 0.31767977, 0.30500184,True,True +920, 0.31510811, 0.29053124,True,True +921, 0.31510811, 0.29551837,True,True +922, 0.31510811, 0.30141938,True,True +923, 0.32456826, 0.29523517,True,True +924, 0.32456826, 0.29781661,True,True +925, 0.30579803, 0.30275907,True,True +926, 0.30574150, 0.30500184,True,True +927, 0.30574150, 0.30500184,True,True +928, 0.32128670, 0.31470830,True,True +929, 0.30579803, 0.29620848,True,True +930, 0.30579803, 0.29523517,True,True +931, 0.32456826, 0.31470830,True,True +932, 0.32456826, 0.30867649,True,True +933, 0.33086875, 0.30111890,True,True +934, 0.31519991, 0.29712804,True,True +935, 0.30574150, 0.30141938,True,True +936, 0.31977390, 0.29551837,True,True +937, 0.32450826, 0.31134034,True,True +938, 0.31701589, 0.30867649,True,True +939, 0.32950652, 0.30896132,True,True +940, 0.32456826, 0.30867649,True,True +941, 0.31356643, 0.30867649,True,True +942, 0.32316986, 0.30896132,True,True +943, 0.32316986, 0.30896132,True,True +944, 0.31299637, 0.30896132,True,True +945, 0.31179407, 0.30141938,True,True +946, 0.31151294, 0.30529441,True,True +947, 0.31305424, 0.30896132,True,True +948, 0.31299637, 0.30896132,True,True +949, 0.31299637, 0.31501017,True,True +950, 0.31305424, 0.30896132,True,True +951, 0.31362440, 0.30896132,True,True +952, 0.31510811, 0.30896132,True,True +953, 0.32311012, 0.30690408,True,True +954, 0.31305424, 0.30500184,True,True +955, 0.31305424, 0.31470830,True,True +956, 0.30574150, 0.30529441,True,True +957, 0.31510811, 0.31470830,True,True +958, 0.30805465, 0.31272039,True,True +959, 0.31519991, 0.30896132,True,True +960, 0.31301650, 0.30529441,True,True +961, 0.32105663, 0.30529441,True,True +962, 0.31179407, 0.30674576,True,True +963, 0.30799545, 0.30500184,True,True +964, 0.31179407, 0.29649261,True,True +965, 0.30211088, 0.29551837,True,True +966, 0.29994232, 0.30211161,True,True +967, 0.31028128, 0.31108021,True,True +968, 0.30805465, 0.28725949,True,True +969, 0.30799545, 0.29237810,True,True +970, 0.29833142, 0.29649261,True,True +971, 0.30799545, 0.29810228,True,True +972, 0.29833142, 0.28753504,True,True +973, 0.30795653, 0.28725949,True,True +974, 0.30805465, 0.29551837,True,True +975, 0.31767977, 0.29712804,True,True +976, 0.29833142, 0.28984380,True,True +977, 0.30799545, 0.30896132,True,True +978, 0.31767977, 0.31470830,True,True +979, 0.30956744, 0.31652181,True,True +980, 0.31767977, 0.31855199,True,True +981, 0.31977390, 0.30896132,True,True +982, 0.29833142, 0.29937300,True,True +983, 0.31022165, 0.29523517,True,True +984, 0.31179407, 0.30500184,True,True +985, 0.29833142, 0.29551837,True,True +986, 0.30361422, 0.29551837,True,True +987, 0.30566809, 0.29551837,True,True +988, 0.29833142, 0.29649261,True,True +989, 0.29833142, 0.29649261,True,True +990, 0.31305424, 0.29237810,True,True +991, 0.30821233, 0.29551837,True,True +992, 0.29994232, 0.29551837,True,True +993, 0.30650791, 0.29551837,True,True +994, 0.30594117, 0.30111890,True,True +995, 0.32143972, 0.31501017,True,True +996, 0.31510811, 0.31501017,True,True +997, 0.31307438, 0.30896132,True,True +998, 0.29833142, 0.29551837,True,True +999, 0.30425807, 0.30073338,True,True +1000, 0.29827408, 0.29142256,True,True +1001, 0.29994232, 0.29810228,True,True +1002, 0.30216895, 0.29712804,True,True +1003, 0.31022165, 0.30752306,True,True +1004, 0.30207467, 0.30500184,True,True +1005, 0.30574150, 0.30375178,True,True +1006, 0.29833142, 0.29237810,True,True +1007, 0.31173415, 0.30500184,True,True +1008, 0.30799545, 0.30500184,True,True +1009, 0.30799545, 0.31501017,True,True +1010, 0.30795653, 0.30500184,True,True +1011, 0.30431433, 0.30500184,True,True +1012, 0.31173415, 0.30211161,True,True +1013, 0.30805465, 0.29237810,True,True +1014, 0.30799545, 0.30500184,True,True +1015, 0.30574150, 0.30591493,True,True +1016, 0.30574150, 0.30073338,True,True +1017, 0.30956744, 0.29620848,True,True +1018, 0.31761871, 0.30101088,True,True +1019, 0.30799545, 0.30500184,True,True +1020, 0.30574150, 0.30162897,True,True +1021, 0.30207467, 0.30162897,True,True +1022, 0.30574150, 0.30500184,True,True +1023, 0.30799545, 0.30190730,True,True +1024, 0.30579803, 0.30101088,True,True +1025, 0.31022165, 0.30985774,True,True +1026, 0.30795653, 0.29551837,True,True +1027, 0.31504986, 0.29943212,True,True +1028, 0.29833142, 0.29237810,True,True +1029, 0.30355810, 0.29237810,True,True +1030, 0.30361422, 0.29237810,True,True +1031, 0.30355810, 0.28984380,True,True +1032, 0.30574150, 0.30181114,True,True +1033, 0.30805465, 0.29237810,True,True +1034, 0.30799545, 0.29079934,True,True +1035, 0.30361422, 0.31134034,True,True +1036, 0.30566809, 0.29810228,True,True +1037, 0.30361422, 0.29079934,True,True +1038, 0.31305424, 0.28984380,True,True +1039, 0.30203429, 0.28984380,True,True +1040, 0.30799545, 0.30190730,True,True +1041, 0.30355810, 0.28532043,True,True +1042, 0.30203429, 0.28032574,True,True +1043, 0.30361422, 0.29237810,True,True +1044, 0.30805465, 0.29810228,True,True +1045, 0.30799545, 0.29551837,True,True +1046, 0.30361422, 0.29810228,True,True +1047, 0.31173415, 0.28984380,True,True +1048, 0.29833142, 0.29551837,True,True +1049, 0.29450567, 0.29576036,True,True +1050, 0.30950795, 0.29649261,True,True +1051, 0.30203429, 0.28984380,True,True +1052, 0.28873105, 0.29551837,True,True +1053, 0.31179407, 0.29666349,True,True +1054, 0.30423720, 0.29158412,True,True +1055, 0.30355810, 0.29551837,True,True +1056, 0.30361422, 0.28984380,True,True +1057, 0.28916477, 0.30032854,True,True +1058, 0.29259427, 0.28984380,True,True +1059, 0.29994232, 0.29712804,True,True +1060, 0.29259427, 0.28984380,True,True +1061, 0.30799545, 0.29237810,True,True +1062, 0.30799545, 0.29237810,True,True +1063, 0.30650791, 0.29551837,True,True +1064, 0.30211088, 0.29649261,True,True +1065, 0.30213052, 0.28984380,True,True +1066, 0.29833142, 0.28984380,True,True +1067, 0.29259427, 0.28984380,True,True +1068, 0.30594117, 0.29827408,True,True +1069, 0.30594117, 0.28770075,True,True +1070, 0.30429804, 0.29142256,True,True +1071, 0.30805465, 0.29649261,True,True +1072, 0.30429804, 0.29810228,True,True +1073, 0.29450567, 0.29810228,True,True +1074, 0.31575879, 0.29827408,True,True +1075, 0.31575879, 0.29827408,True,True +1076, 0.30429804, 0.29810228,True,True +1077, 0.30805465, 0.29079934,True,True +1078, 0.29988468, 0.29649261,True,True +1079, 0.29614880, 0.29237810,True,True +1080, 0.31802995, 0.30207467,True,True +1081, 0.31575879, 0.29649261,True,True +1082, 0.29833142, 0.29237810,True,True +1083, 0.31648690, 0.28984380,True,True +1084, 0.31421574, 0.29810228,True,True +1085, 0.31575879, 0.30547036,True,True +1086, 0.31173415, 0.29649261,True,True +1087, 0.31173415, 0.30620838,True,True +1088, 0.31575879, 0.28984380,True,True +1089, 0.30950795, 0.28984380,True,True +1090, 0.30799545, 0.29943212,True,True +1091, 0.30950795, 0.29551837,True,True +1092, 0.31802995, 0.29649261,True,True +1093, 0.30594117, 0.29551837,True,True +1094, 0.30805465, 0.29649261,True,True +1095, 0.30799545, 0.30529441,True,True +1096, 0.30799545, 0.30638485,True,True +1097, 0.31569566, 0.30547036,True,True +1098, 0.29994232, 0.28984380,True,True +1099, 0.30805465, 0.29810228,True,True +1100, 0.30950795, 0.30547036,True,True +1101, 0.30956744, 0.29810228,True,True +1102, 0.30594117, 0.28984380,True,True +1103, 0.31575879, 0.28984380,True,True +1104, 0.30805465, 0.28984380,True,True +1105, 0.30805465, 0.29943212,True,True +1106, 0.29833142, 0.30547036,True,True +1107, 0.30799545, 0.29551837,True,True +1108, 0.30799545, 0.29568868,True,True +1109, 0.31415292, 0.29568868,True,True +1110, 0.31421574, 0.30638485,True,True +1111, 0.31415292, 0.30799545,True,True +1112, 0.31415292, 0.30620838,True,True +1113, 0.31421574, 0.29810228,True,True +1114, 0.30429804, 0.30781805,True,True +1115, 0.30805465, 0.29142256,True,True +1116, 0.30805465, 0.30913260,True,True +1117, 0.30799545, 0.29237810,True,True +1118, 0.30799545, 0.29237810,True,True +1119, 0.30805465, 0.28867556,True,True +1120, 0.29833142, 0.30190730,True,True +1121, 0.31767977, 0.30032854,True,True +1122, 0.30355810, 0.30547443,True,True +1123, 0.30574150, 0.30073338,True,True +1124, 0.30431433, 0.29237810,True,True +1125, 0.30805465, 0.29237810,True,True +1126, 0.30579803, 0.29810228,True,True +1127, 0.31510811, 0.30401976,True,True +1128, 0.31305424, 0.30459491,True,True +1129, 0.30805465, 0.29237810,True,True +1130, 0.29833142, 0.28984380,True,True +1131, 0.28873105, 0.28984380,True,True +1132, 0.30799545, 0.29915607,True,True +1133, 0.30799545, 0.30985774,True,True +1134, 0.30805465, 0.29142256,True,True +1135, 0.31977390, 0.30896132,True,True +1136, 0.30355810, 0.28984380,True,True +1137, 0.30431433, 0.29551837,True,True +1138, 0.31022165, 0.29712804,True,True +1139, 0.31767977, 0.29523517,True,True +1140, 0.31362440, 0.29551837,True,True +1141, 0.30799545, 0.29551837,True,True +1142, 0.30799545, 0.28032574,True,True +1143, 0.30799545, 0.27074025,True,True +1144, 0.30805465, 0.28201377,True,True +1145, 0.30083074, 0.28296931,True,True +1146, 0.29833142, 0.29079934,True,True +1147, 0.30805465, 0.29551837,True,True +1148, 0.30574150, 0.30772001,True,True +1149, 0.31173415, 0.30500184,True,True +1150, 0.30799545, 0.30660997,True,True +1151, 0.30799545, 0.29684329,True,True +1152, 0.30579803, 0.30275907,True,True +1153, 0.30579803, 0.29684329,True,True +1154, 0.30805465, 0.28581396,True,True +1155, 0.30805465, 0.29523517,True,True +1156, 0.31767977, 0.29915607,True,True +1157, 0.30805465, 0.29280071,True,True +1158, 0.31179407, 0.29712804,True,True +1159, 0.30799545, 0.27604081,True,True +1160, 0.30805465, 0.28574522,True,True +1161, 0.30805465, 0.27604081,True,True +1162, 0.30805465, 0.29551837,True,True +1163, 0.31028128, 0.29551837,True,True +1164, 0.31028128, 0.29523517,True,True +1165, 0.31778727, 0.29551837,True,True +1166, 0.29833142, 0.29551837,True,True +1167, 0.31179407, 0.29551837,True,True +1168, 0.29994232, 0.29551837,True,True +1169, 0.30216895, 0.29551837,True,True +1170, 0.31173415, 0.28984380,True,True +1171, 0.30216895, 0.28581396,True,True +1172, 0.31179407, 0.29523517,True,True +1173, 0.30216895, 0.29551837,True,True +1174, 0.32128670, 0.29551837,True,True +1175, 0.32128670, 0.31501017,True,True +1176, 0.31510811, 0.30529441,True,True +1177, 0.31510811, 0.30529441,True,True +1178, 0.31179407, 0.30500184,True,True +1179, 0.33093234, 0.30500184,True,True +1180, 0.31179407, 0.30547036,True,True +1181, 0.30431433, 0.28957659,True,True +1182, 0.31179407, 0.28957659,True,True +1183, 0.31179407, 0.29943212,True,True +1184, 0.31767977, 0.28581396,True,True +1185, 0.31028128, 0.29943212,True,True +1186, 0.31179407, 0.29915607,True,True +1187, 0.32128670, 0.30500184,True,True +1188, 0.32128670, 0.30500184,True,True +1189, 0.31510811, 0.30529441,True,True +1190, 0.30805465, 0.30529441,True,True +1191, 0.30579803, 0.29551837,True,True +1192, 0.30805465, 0.30660997,True,True +1193, 0.31028128, 0.29684329,True,True +1194, 0.31179407, 0.30690408,True,True +1195, 0.31802995, 0.30529441,True,True +1196, 0.32122495, 0.29568868,True,True +1197, 0.31028128, 0.29523517,True,True +1198, 0.31767977, 0.31501017,True,True +1199, 0.31179407, 0.30529441,True,True +1200, 0.31977390, 0.30529441,True,True +1201, 0.32128670, 0.29943212,True,True +1202, 0.32128670, 0.31501017,True,True +1203, 0.31802995, 0.30690408,True,True +1204, 0.32128670, 0.30690408,True,True +1205, 0.30211088, 0.30529441,True,True +1206, 0.32128670, 0.29551837,True,True +1207, 0.31977390, 0.30529441,True,True +1208, 0.32128670, 0.29551837,True,True +1209, 0.31767977, 0.28581396,True,True +1210, 0.31767977, 0.30529441,True,True +1211, 0.32137794, 0.30529441,True,True +1212, 0.31977390, 0.30500184,True,True +1213, 0.32128670, 0.31501017,True,True +1214, 0.32128670, 0.31232286,True,True +1215, 0.30805465, 0.30141938,True,True +1216, 0.31362440, 0.31501017,True,True +1217, 0.31919256, 0.29649261,True,True +1218, 0.32456826, 0.31501017,True,True +1219, 0.31179407, 0.29649261,True,True +1220, 0.32456826, 0.29551837,True,True +1221, 0.32128670, 0.31501017,True,True +1222, 0.32128670, 0.30529441,True,True +1223, 0.31510811, 0.30529441,True,True +1224, 0.32128670, 0.30523413,True,True +1225, 0.31519991, 0.29551837,True,True +1226, 0.31510811, 0.31501017,True,True +1227, 0.33086875, 0.29551837,True,True +1228, 0.31767977, 0.31139064,True,True +1229, 0.32771243, 0.30529441,True,True +1230, 0.32456826, 0.29551837,True,True +1231, 0.30956744, 0.29551837,True,True +1232, 0.31157054, 0.30529441,True,True +1233, 0.32128670, 0.31501017,True,True +1234, 0.32741239, 0.29551837,True,True +1235, 0.31919256, 0.29551837,True,True +1236, 0.31179407, 0.29551837,True,True +1237, 0.32105663, 0.29943212,True,True +1238, 0.31179407, 0.30523413,True,True +1239, 0.30799545, 0.29551837,True,True +1240, 0.31642362, 0.29142256,True,True +1241, 0.30950795, 0.29523517,True,True +1242, 0.32450826, 0.30101088,True,True +1243, 0.32128670, 0.29551837,True,True +1244, 0.31519991, 0.30529441,True,True +1245, 0.31179407, 0.29551837,True,True +1246, 0.31179407, 0.29551837,True,True +1247, 0.31173415, 0.29551837,True,True +1248, 0.31173415, 0.29551837,True,True +1249, 0.31173415, 0.31061603,True,True +1250, 0.31421574, 0.29620848,True,True +1251, 0.30950795, 0.30547036,True,True +1252, 0.31173415, 0.29551837,True,True +1253, 0.30956744, 0.29551837,True,True +1254, 0.31362440, 0.30529441,True,True +1255, 0.31179407, 0.30500184,True,True +1256, 0.31913122, 0.29237810,True,True +1257, 0.31173415, 0.29551837,True,True +1258, 0.30799545, 0.29551837,True,True +1259, 0.31761871, 0.29551837,True,True +1260, 0.30805465, 0.30500184,True,True +1261, 0.30799545, 0.29523517,True,True +1262, 0.30799545, 0.29568868,True,True +1263, 0.30574150, 0.29551837,True,True +1264, 0.31761871, 0.29568868,True,True +1265, 0.30805465, 0.29551837,True,True +1266, 0.30805465, 0.29551837,True,True +1267, 0.30805465, 0.30529441,True,True +1268, 0.31767977, 0.29959812,True,True +1269, 0.32128670, 0.31501017,True,True +1270, 0.30956744, 0.30529441,True,True +1271, 0.30956744, 0.30529441,True,True +1272, 0.30956744, 0.29523517,True,True +1273, 0.30431433, 0.30500184,True,True +1274, 0.30805465, 0.28574522,True,True +1275, 0.30805465, 0.28678821,True,True +1276, 0.30805465, 0.29152120,True,True +1277, 0.29988468, 0.30498857,True,True +1278, 0.31510811, 0.31501017,True,True +1279, 0.30799545, 0.30111890,True,True +1280, 0.30805465, 0.30529441,True,True +1281, 0.30805465, 0.30529441,True,True +1282, 0.32128670, 0.31501017,True,True +1283, 0.31362440, 0.30529441,True,True +1284, 0.31510811, 0.29551837,True,True +1285, 0.31767977, 0.29551837,True,True +1286, 0.30805465, 0.28548777,True,True +1287, 0.32128670, 0.30529441,True,True +1288, 0.31510811, 0.29943212,True,True +1289, 0.31510811, 0.30896132,True,True +1290, 0.31504986, 0.30896132,True,True +1291, 0.31519991, 0.30896132,True,True +1292, 0.32450826, 0.30101088,True,True +1293, 0.32741239, 0.30660997,True,True +1294, 0.31767977, 0.30111890,True,True +1295, 0.31157054, 0.32284223,True,True +1296, 0.32456826, 0.30500184,True,True +1297, 0.31510811, 0.31501017,True,True +1298, 0.31305424, 0.30896132,True,True +1299, 0.31510811, 0.30500184,True,True +1300, 0.31519991, 0.29551837,True,True +1301, 0.31179407, 0.29551837,True,True +1302, 0.31179407, 0.29551837,True,True +1303, 0.32111599, 0.29551837,True,True +1304, 0.30799545, 0.29551837,True,True +1305, 0.32111599, 0.31652181,True,True +1306, 0.32456826, 0.30896132,True,True +1307, 0.31510811, 0.30896132,True,True +1308, 0.32741239, 0.29551837,True,True +1309, 0.31362440, 0.31134034,True,True +1310, 0.32950652, 0.31743577,True,True +1311, 0.32741239, 0.29142256,True,True +1312, 0.30431433, 0.30896132,True,True +1313, 0.31971245, 0.31501017,True,True +1314, 0.32944320, 0.31652181,True,True +1315, 0.33093234, 0.31272039,True,True +1316, 0.32741239, 0.30690408,True,True +1317, 0.31305424, 0.30494162,True,True +1318, 0.31356643, 0.31621848,True,True +1319, 0.31767977, 0.30500184,True,True +1320, 0.32245478, 0.30896132,True,True +1321, 0.32741239, 0.31501017,True,True +1322, 0.32741239, 0.30500184,True,True +1323, 0.31772620, 0.29523517,True,True +1324, 0.31995240, 0.29523517,True,True +1325, 0.31022165, 0.31501017,True,True +1326, 0.32456826, 0.30896132,True,True +1327, 0.32111599, 0.31743577,True,True +1328, 0.30805465, 0.29551837,True,True +1329, 0.31772620, 0.30500184,True,True +1330, 0.31510811, 0.29712804,True,True +1331, 0.32111599, 0.29810228,True,True +1332, 0.30805465, 0.31501017,True,True +1333, 0.32450826, 0.30032854,True,True +1334, 0.31977390, 0.31501017,True,True +1335, 0.31157054, 0.29523517,True,True +1336, 0.31767977, 0.29551837,True,True +1337, 0.31977390, 0.30500184,True,True +1338, 0.30805465, 0.30306120,True,True +1339, 0.32128670, 0.30867649,True,True +1340, 0.33086875, 0.31134034,True,True +1341, 0.31772620, 0.31044393,True,True +1342, 0.32251440, 0.31652181,True,True +1343, 0.31977390, 0.31652181,True,True +1344, 0.31510811, 0.31061603,True,True +1345, 0.31305424, 0.29649261,True,True +1346, 0.32105663, 0.31044393,True,True +1347, 0.32944320, 0.31501017,True,True +1348, 0.31022165, 0.30690408,True,True +1349, 0.30425807, 0.29559001,True,True +1350, 0.31767977, 0.30111890,True,True +1351, 0.31995240, 0.31501017,True,True +1352, 0.31767977, 0.29551837,True,True +1353, 0.31362440, 0.30660997,True,True +1354, 0.30579803, 0.30500184,True,True +1355, 0.31977390, 0.31501017,True,True +1356, 0.32741239, 0.30500184,True,True +1357, 0.32450826, 0.28984380,True,True +1358, 0.31995240, 0.30529441,True,True +1359, 0.31995240, 0.30500184,True,True +1360, 0.32311012, 0.30529441,True,True +1361, 0.32311012, 0.30500184,True,True +1362, 0.31971245, 0.29551837,True,True +1363, 0.32137794, 0.30500184,True,True +1364, 0.32450826, 0.31501017,True,True +1365, 0.32450826, 0.30529441,True,True +1366, 0.32122495, 0.30529441,True,True +1367, 0.31510811, 0.31652181,True,True +1368, 0.32001390, 0.31470830,True,True +1369, 0.32137794, 0.31501017,True,True +1370, 0.32128670, 0.31470830,True,True +1371, 0.31173415, 0.31652181,True,True +1372, 0.32128670, 0.31670422,True,True +1373, 0.31510811, 0.31519172,True,True +1374, 0.31519991, 0.30529441,True,True +1375, 0.31767977, 0.31044393,True,True +1376, 0.32122495, 0.31501017,True,True +1377, 0.31519991, 0.30896132,True,True +1378, 0.31504986, 0.31501017,True,True +1379, 0.31504986, 0.30459491,True,True +1380, 0.31173415, 0.30073338,True,True +1381, 0.31356643, 0.31044393,True,True +1382, 0.31356643, 0.30896132,True,True +1383, 0.31977390, 0.31470830,True,True +1384, 0.30788310, 0.30867649,True,True +1385, 0.32122495, 0.29551837,True,True +1386, 0.31173415, 0.31501017,True,True +1387, 0.30055805, 0.28678821,True,True +1388, 0.31519991, 0.30867649,True,True +1389, 0.31356643, 0.30985774,True,True +1390, 0.31519991, 0.30985774,True,True +1391, 0.32137794, 0.30896132,True,True +1392, 0.30574150, 0.30896132,True,True +1393, 0.32245478, 0.30190730,True,True +1394, 0.32450826, 0.31002951,True,True +1395, 0.32137794, 0.31501017,True,True +1396, 0.31519991, 0.30896132,True,True +1397, 0.31510811, 0.30867649,True,True +1398, 0.31510811, 0.30896132,True,True +1399, 0.31179407, 0.30500184,True,True +1400, 0.30574150, 0.30896132,True,True +1401, 0.30216895, 0.29551837,True,True +1402, 0.31761871, 0.29237810,True,True +1403, 0.31525818, 0.30896132,True,True +1404, 0.31519991, 0.30896132,True,True +1405, 0.32245478, 0.30867649,True,True +1406, 0.30950795, 0.29551837,True,True +1407, 0.32245478, 0.30896132,True,True +1408, 0.31504986, 0.30896132,True,True +1409, 0.31157054, 0.30690408,True,True +1410, 0.31305424, 0.28957659,True,True +1411, 0.31305424, 0.30500184,True,True +1412, 0.32456826, 0.28984380,True,True +1413, 0.32105663, 0.31621848,True,True +1414, 0.31305424, 0.30500184,True,True +1415, 0.32245478, 0.30500184,True,True +1416, 0.31504986, 0.30896132,True,True +1417, 0.32944320, 0.30500184,True,True +1418, 0.30216895, 0.30660997,True,True +1419, 0.32450826, 0.31470830,True,True +1420, 0.31977390, 0.30500184,True,True +1421, 0.31305424, 0.31105331,True,True +1422, 0.31504986, 0.31501017,True,True +1423, 0.31305424, 0.30660997,True,True +1424, 0.31157054, 0.31501017,True,True +1425, 0.30799545, 0.29781661,True,True +1426, 0.31157054, 0.30752306,True,True +1427, 0.31504986, 0.28984380,True,True +1428, 0.30574150, 0.29237810,True,True +1429, 0.33086875, 0.31470830,True,True +1430, 0.31767977, 0.30896132,True,True +1431, 0.31299637, 0.30896132,True,True +1432, 0.32311012, 0.31044393,True,True +1433, 0.32311012, 0.30459491,True,True +1434, 0.32450826, 0.30867649,True,True +1435, 0.31179407, 0.29915607,True,True +1436, 0.31356643, 0.31015773,True,True +1437, 0.31299637, 0.30985774,True,True +1438, 0.32316986, 0.31470830,True,True +1439, 0.31504986, 0.31044393,True,True +1440, 0.31173415, 0.30032854,True,True +1441, 0.31356643, 0.31855199,True,True +1442, 0.31761871, 0.30690408,True,True +1443, 0.31971245, 0.30459491,True,True +1444, 0.31504986, 0.30896132,True,True +1445, 0.31173415, 0.30896132,True,True +1446, 0.31510811, 0.31470830,True,True +1447, 0.31299637, 0.29237810,True,True +1448, 0.31971245, 0.32003460,True,True +1449, 0.31504986, 0.30529441,True,True +1450, 0.30910765, 0.30867649,True,True +1451, 0.31362440, 0.31652181,True,True +1452, 0.31157054, 0.29684329,True,True +1453, 0.32128670, 0.29712804,True,True +1454, 0.31173415, 0.30500184,True,True +1455, 0.31510811, 0.29943212,True,True +1456, 0.31510811, 0.30896132,True,True +1457, 0.31504986, 0.30896132,True,True +1458, 0.32450826, 0.30896132,True,True +1459, 0.31504986, 0.30005166,True,True +1460, 0.31504986, 0.29523517,True,True +1461, 0.31504986, 0.30867649,True,True +1462, 0.30925487, 0.30896132,True,True +1463, 0.31487530, 0.30896132,True,True +1464, 0.32122495, 0.29915607,True,True +1465, 0.31504986, 0.29943212,True,True +1466, 0.31504986, 0.30896132,True,True +1467, 0.32122495, 0.30896132,True,True +1468, 0.31504986, 0.30896132,True,True +1469, 0.30950795, 0.30867649,True,True +1470, 0.31362440, 0.30837680,True,True +1471, 0.30574150, 0.30896132,True,True +1472, 0.31504986, 0.30896132,True,True +1473, 0.30799545, 0.29551837,True,True +1474, 0.31173415, 0.30896132,True,True +1475, 0.31299637, 0.30896132,True,True +1476, 0.31504986, 0.30985774,True,True +1477, 0.30211088, 0.28984380,True,True +1478, 0.30574150, 0.28984380,True,True +1479, 0.31504986, 0.30896132,True,True +1480, 0.31173415, 0.30752306,True,True +1481, 0.31173415, 0.30500184,True,True +1482, 0.31155460, 0.29943212,True,True +1483, 0.31519991, 0.30896132,True,True +1484, 0.31971245, 0.31044393,True,True +1485, 0.32122495, 0.30500184,True,True +1486, 0.31971245, 0.30432456,True,True +1487, 0.30574150, 0.31044393,True,True +1488, 0.30338990, 0.30314023,True,True +1489, 0.31761871, 0.31134034,True,True +1490, 0.30355810, 0.30287118,True,True +1491, 0.29630323, 0.28984380,True,True +1492, 0.30211088, 0.28984380,True,True +1493, 0.29630323, 0.29142256,True,True +1494, 0.31155460, 0.30314023,True,True +1495, 0.31022165, 0.30432456,True,True +1496, 0.31761871, 0.30459491,True,True +1497, 0.31519991, 0.29943212,True,True +1498, 0.30355810, 0.30896132,True,True +1499, 0.31642362, 0.29490929,True,True +1500, 0.32122495, 0.30500184,True,True +1501, 0.31971245, 0.31470830,True,True +1502, 0.32122495, 0.31134034,True,True +1503, 0.30574150, 0.29142256,True,True +1504, 0.31151294, 0.30896132,True,True +1505, 0.30355810, 0.30073338,True,True +1506, 0.32122495, 0.30475746,True,True +1507, 0.30207467, 0.30500184,True,True +1508, 0.31299637, 0.30896132,True,True +1509, 0.31971245, 0.31044393,True,True +1510, 0.31504986, 0.29943212,True,True +1511, 0.32122495, 0.30432456,True,True +1512, 0.30207467, 0.30867649,True,True +1513, 0.31487530, 0.30459491,True,True +1514, 0.32122495, 0.30896132,True,True +1515, 0.31510811, 0.30500184,True,True +1516, 0.32122495, 0.30867649,True,True +1517, 0.31356643, 0.30867649,True,True +1518, 0.31504986, 0.30867649,True,True +1519, 0.32122495, 0.29915607,True,True +1520, 0.32122495, 0.29943212,True,True +1521, 0.32122495, 0.30867649,True,True +1522, 0.31971245, 0.30867649,True,True +1523, 0.30338990, 0.30896132,True,True +1524, 0.30207467, 0.29915607,True,True +1525, 0.30574150, 0.29915607,True,True +1526, 0.30799545, 0.30896132,True,True +1527, 0.30557210, 0.31044393,True,True +1528, 0.30211088, 0.30896132,True,True +1529, 0.30557210, 0.30896132,True,True +1530, 0.31510811, 0.30867649,True,True +1531, 0.31977390, 0.30500184,True,True +1532, 0.32456826, 0.31825831,True,True +1533, 0.30557210, 0.30459491,True,True +1534, 0.30557210, 0.30896132,True,True +1535, 0.30574150, 0.30867649,True,True +1536, 0.31173415, 0.31470830,True,True +1537, 0.30574150, 0.30459491,True,True +1538, 0.31504986, 0.30896132,True,True +1539, 0.31971245, 0.30896132,True,True +1540, 0.31504986, 0.30896132,True,True +1541, 0.31173415, 0.29943212,True,True +1542, 0.31179407, 0.28984380,True,True +1543, 0.30574150, 0.29915607,True,True +1544, 0.30557210, 0.30896132,True,True +1545, 0.31761871, 0.29943212,True,True +1546, 0.31971245, 0.30500184,True,True +1547, 0.31028128, 0.29937300,True,True +1548, 0.30361422, 0.29943212,True,True +1549, 0.31504986, 0.31470830,True,True +1550, 0.32122495, 0.30867649,True,True +1551, 0.30425807, 0.32003460,True,True +1552, 0.31022165, 0.30896132,True,True +1553, 0.30557210, 0.30432456,True,True +1554, 0.31504986, 0.30073338,True,True +1555, 0.32122495, 0.29915607,True,True +1556, 0.29254018, 0.29079934,True,True +1557, 0.30799545, 0.30896132,True,True +1558, 0.30574150, 0.30867649,True,True +1559, 0.29833142, 0.29712804,True,True +1560, 0.30815071, 0.31044393,True,True +1561, 0.31519991, 0.31855199,True,True +1562, 0.30050028, 0.30867649,True,True +1563, 0.30574150, 0.29943212,True,True +1564, 0.30207467, 0.30101088,True,True +1565, 0.29827408, 0.30500184,True,True +1566, 0.29613906, 0.28984380,True,True +1567, 0.29827408, 0.30101088,True,True +1568, 0.30594117, 0.30523413,True,True +1569, 0.29630323, 0.29237810,True,True +1570, 0.31022165, 0.31652181,True,True +1571, 0.29827408, 0.28984380,True,True +1572, 0.30815071, 0.30500184,True,True +1573, 0.30574150, 0.30867649,True,True +1574, 0.29833142, 0.28984380,True,True +1575, 0.29988468, 0.29551837,True,True +1576, 0.29833142, 0.29551837,True,True +1577, 0.29630323, 0.30500184,True,True +1578, 0.29472359, 0.29142256,True,True +1579, 0.31362440, 0.29810228,True,True +1580, 0.29833142, 0.29237810,True,True +1581, 0.29411982, 0.28984380,True,True +1582, 0.29259427, 0.28984380,True,True +1583, 0.29833142, 0.29551837,True,True +1584, 0.29833142, 0.30752306,True,True +1585, 0.32122495, 0.30896132,True,True +1586, 0.29971195, 0.28581396,True,True +1587, 0.30557210, 0.30459491,True,True +1588, 0.29827408, 0.28984380,True,True +1589, 0.30050028, 0.30529441,True,True +1590, 0.31022165, 0.30896132,True,True +1591, 0.31151294, 0.31470830,True,True +1592, 0.30193687, 0.30867649,True,True +1593, 0.30050028, 0.29142256,True,True +1594, 0.30650791, 0.29237810,True,True +1595, 0.31772620, 0.30529441,True,True +1596, 0.31173415, 0.29915607,True,True +1597, 0.31504986, 0.31470830,True,True +1598, 0.31767977, 0.29237810,True,True +1599, 0.30574150, 0.29551837,True,True +1600, 0.29472359, 0.28984380,True,True +1601, 0.31173415, 0.31470830,True,True +1602, 0.31173415, 0.30896132,True,True +1603, 0.30656921, 0.29551837,True,True +1604, 0.29254018, 0.28438290,True,True +1605, 0.30799545, 0.30867649,True,True +1606, 0.31362440, 0.30073338,True,True +1607, 0.31179407, 0.31044393,True,True +1608, 0.29254018, 0.29142256,True,True +1609, 0.31155460, 0.30896132,True,True +1610, 0.31510811, 0.28296931,True,True +1611, 0.30799545, 0.30867649,True,True +1612, 0.30190730, 0.29943212,True,True +1613, 0.31301650, 0.30101088,True,True +1614, 0.29827408, 0.29237810,True,True +1615, 0.29827408, 0.29551837,True,True +1616, 0.29827408, 0.30867649,True,True +1617, 0.29810228, 0.29915607,True,True +1618, 0.29827408, 0.29551837,True,True +1619, 0.31648690, 0.29237810,True,True +1620, 0.29827408, 0.29551837,True,True +1621, 0.31151294, 0.30500184,True,True +1622, 0.31510811, 0.30494162,True,True +1623, 0.30799545, 0.28984380,True,True +1624, 0.29254018, 0.28984380,True,True +1625, 0.30795653, 0.30494162,True,True +1626, 0.31510811, 0.31470830,True,True +1627, 0.31767977, 0.30500184,True,True +1628, 0.29635801, 0.29237810,True,True +1629, 0.30050028, 0.29551837,True,True +1630, 0.29827408, 0.28984380,True,True +1631, 0.31362440, 0.31470830,True,True +1632, 0.30799545, 0.30896132,True,True +1633, 0.30190730, 0.30459491,True,True +1634, 0.29259427, 0.29551837,True,True +1635, 0.29630323, 0.28593191,True,True +1636, 0.29827408, 0.28984380,True,True +1637, 0.30077292, 0.30500184,True,True +1638, 0.31028128, 0.31470830,True,True +1639, 0.30216895, 0.29937300,True,True +1640, 0.30781805, 0.30896132,True,True +1641, 0.32122495, 0.29943212,True,True +1642, 0.31155460, 0.29915607,True,True +1643, 0.30193687, 0.30985774,True,True +1644, 0.30579803, 0.30896132,True,True +1645, 0.32128670, 0.30867649,True,True +1646, 0.31767977, 0.30500184,True,True +1647, 0.30050028, 0.29915607,True,True +1648, 0.31915174, 0.31507285,True,True +1649, 0.31022165, 0.30867649,True,True +1650, 0.32137794, 0.30896132,True,True +1651, 0.31504986, 0.31939614,True,True +1652, 0.31173415, 0.31015773,True,True +1653, 0.31022165, 0.30896132,True,True +1654, 0.30355810, 0.30867649,True,True +1655, 0.31995240, 0.29379057,True,True +1656, 0.30799545, 0.30957207,True,True +1657, 0.31022165, 0.29943212,True,True +1658, 0.29254018, 0.28984380,True,True +1659, 0.29411982, 0.28984380,True,True +1660, 0.30574150, 0.29943212,True,True +1661, 0.29827408, 0.29551837,True,True +1662, 0.31022165, 0.30867649,True,True +1663, 0.30050028, 0.29551837,True,True +1664, 0.30207467, 0.30529441,True,True +1665, 0.29411982, 0.28984380,True,True +1666, 0.31173415, 0.30957207,True,True +1667, 0.31155460, 0.30896132,True,True +1668, 0.30050028, 0.29551837,True,True +1669, 0.32137794, 0.30867649,True,True +1670, 0.30050028, 0.29551837,True,True +1671, 0.29827408, 0.29551837,True,True +1672, 0.29810228, 0.29551837,True,True +1673, 0.31022165, 0.29142256,True,True +1674, 0.30574150, 0.30867649,True,True +1675, 0.29833142, 0.30529441,True,True +1676, 0.30193687, 0.29551837,True,True +1677, 0.30557210, 0.28984380,True,True +1678, 0.31173415, 0.30752306,True,True +1679, 0.31173415, 0.30500184,True,True +1680, 0.30805465, 0.30529441,True,True +1681, 0.30211088, 0.28823281,True,True +1682, 0.30050028, 0.30500184,True,True +1683, 0.32122495, 0.28984380,True,True +1684, 0.30211088, 0.29110264,True,True +1685, 0.30832874, 0.29551837,True,True +1686, 0.31022165, 0.29142256,True,True +1687, 0.32122495, 0.29551837,True,True +1688, 0.31173415, 0.30529441,True,True +1689, 0.30799545, 0.29551837,True,True +1690, 0.29827408, 0.30500184,True,True +1691, 0.30799545, 0.29913216,True,True +1692, 0.29827408, 0.29551837,True,True +1693, 0.30799545, 0.29551837,True,True +1694, 0.30211088, 0.29559001,True,True +1695, 0.30815071, 0.28581396,True,True +1696, 0.30211088, 0.29142256,True,True +1697, 0.31044357, 0.30529441,True,True +1698, 0.30228543, 0.28175378,True,True +1699, 0.30678600, 0.29551837,True,True +1700, 0.28629917, 0.29551837,True,True +1701, 0.29591216, 0.28574522,True,True +1702, 0.29034726, 0.28728941,True,True +1703, 0.28303909, 0.25687327,True,True +1704, 0.27345918, 0.24189515,True,True +1705, 0.23517912, 0.20494745,True,True +1706, 0.21935835, 0.15486091,True,True +1707, 0.19576213, 0.13950747,True,True +1708, 0.17314200, 0.08754263,True,True +1709, 0.10371662, 0.04376881,True,True +1710, 0.06000068, 0.02229275,True,True +1711, 0.04856429, 0.03152671,True,True +1712, 0.04124562, 0.02231941,True,True +1713, 0.03545467, 0.02723225,True,True +1714, 0.01900715, 0.02231941,True,True +1715, 0.02294366, 0.02937513,True,True +1716, 0.02294366, 0.03099224,True,True +1717, 0.02688017, 0.03099224,True,True +1718, 0.03018699, 0.02937513,True,True +1719, 0.02294366, 0.03156442,True,True +1720, 0.00968549, 0.02191482,True,True +1721, 0.03469072, 0.02723225,True,True +1722, 0.03075421, 0.02614882,True,True +1723, 0.03204813, 0.03159143,True,True +1724, 0.03949763, 0.04212254,True,True +1725, 0.03961367, 0.03438158,True,True +1726, 0.04951709, 0.03922323,True,True +1727, 0.06299380, 0.04215995,True,True +1728, 0.09133056, 0.05750731,True,True +1729, 0.10125397, 0.06928630,True,True +1730, 0.12566668, 0.06496725,True,True +1731, 0.13628169, 0.08350729,True,True +1732, 0.15085274, 0.09849424,True,True +1733, 0.16457867, 0.10090950,True,True +1734, 0.16813670, 0.13041148,True,True +1735, 0.18829323, 0.15196716,True,True +1736, 0.19859985, 0.17333748,True,True +1737, 0.20898823, 0.17333748,True,True +1738, 0.20898823, 0.16519316,True,True +1739, 0.20898823, 0.20500627,True,True +1740, 0.22648205, 0.15620764,True,True +1741, 0.24822311, 0.20505075,True,True +1742, 0.22953975, 0.21498277,True,True +1743, 0.24001783, 0.21091578,True,True +1744, 0.24531412, 0.22269145,True,True +1745, 0.25558643, 0.22380904,True,True +1746, 0.26730115, 0.23146749,True,True +1747, 0.25719226, 0.24189515,True,True +1748, 0.26730115, 0.25210279,True,True +1749, 0.25196325, 0.25712942,True,True +1750, 0.28041434, 0.26720305,True,True +1751, 0.26921606, 0.25402642,True,True +1752, 0.27845024, 0.27461839,True,True +1753, 0.27441611, 0.26374794,True,True +1754, 0.28986496, 0.26374794,True,True +1755, 0.28826200, 0.26170423,True,True +1756, 0.28986496, 0.27371859,True,True +1757, 0.28986496, 0.27720404,True,True +1758, 0.30273738, 0.28347821,True,True +1759, 0.29669240, 0.27792197,True,True +1760, 0.30194124, 0.28155289,True,True +1761, 0.28986496, 0.28330834,True,True +1762, 0.31391459, 0.28753504,True,True +1763, 0.30539196, 0.30141938,True,True +1764, 0.29833421, 0.29152120,True,True +1765, 0.30765904, 0.30690408,True,True +1766, 0.29803680, 0.29523517,True,True +1767, 0.30765904, 0.30500184,True,True +1768, 0.31155460, 0.29551837,True,True diff --git a/tests/test_earfeature.py b/tests/test_earfeature.py index b31e519..07b0a74 100644 --- a/tests/test_earfeature.py +++ b/tests/test_earfeature.py @@ -28,28 +28,30 @@ def test_ear_score_inputs(): with pytest.raises(ValueError): features.ear_score(input_data) - # Test case 5: Invalid input range - input_data = np.array([[-2, 2], [1,4], [4,4], [5,2], [4, 0], [1, 0]]) - with pytest.raises(ValueError): - features.ear_score(input_data) + # TEST DEPRIECATED + # Reason: negative values are possible (but rare) and should not raise an error + # # Test case 5: Invalid input range + # input_data = np.array([[-2, 2], [1,4], [4,4], [5,2], [4, 0], [1, 0]]) + # with pytest.raises(ValueError): + # features.ear_score(input_data) - # Test case 6: Out of range + # Test case 6: Out of range, thus not valid output input_data = np.array([[0, 2], [1,10], [4,10], [5,2], [4, 0], [1, 0]]) - with pytest.raises(ValueError): - features.ear_score(input_data) - + score, valid = features.ear_score(input_data) + assert not valid + def test_ear_score(): # Test case 1: Valid input of sphere input_data = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]) expected_output = 1.0 - assert features.ear_score(input_data) == approx(expected_output) + assert features.ear_score(input_data)[0] == approx(expected_output) # Test case 2: Valid input input_data = np.array([[0, 2], [1,4], [4,4], [5,2], [4, 0], [1, 0]]) expected_output = (4 + 4) / 10 - assert features.ear_score(input_data) == approx(expected_output) + assert features.ear_score(input_data)[0] == approx(expected_output) # Test case 3: Valid input input_data = np.array([[0, 2], [1,3], [4,3], [5,2], [4, 1], [1, 1]]) expected_output = (2 + 2) / 10 - assert features.ear_score(input_data) == approx(expected_output) + assert features.ear_score(input_data)[0] == approx(expected_output)