ok-script 0.0.82__tar.gz → 0.0.83__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ok-script-0.0.82 → ok-script-0.0.83}/PKG-INFO +1 -1
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/alas/emulator_windows.py +1 -1
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/HwndWindow.py +9 -6
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/adb/DeviceManager.py +18 -7
- ok-script-0.0.83/ok/color/Color.py +148 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/feature/Box.py +8 -8
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/feature/FeatureSet.py +7 -2
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/feature/FindFeature.py +4 -5
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/StartController.py +2 -2
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/debug/DebugTab.py +4 -2
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/interaction/BaseInteraction.py +6 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/interaction/Win32Interaction.py +31 -2
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/ocr/OCR.py +3 -6
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/task/ExecutorOperation.py +26 -2
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/task/TaskExecutor.py +1 -1
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/task/TriggerTask.py +2 -1
- {ok-script-0.0.82 → ok-script-0.0.83}/ok_script.egg-info/PKG-INFO +1 -1
- {ok-script-0.0.82 → ok-script-0.0.83}/setup.py +1 -1
- ok-script-0.0.82/ok/color/Color.py +0 -42
- {ok-script-0.0.82 → ok-script-0.0.83}/README.md +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/OK.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/alas/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/alas/emulator_base.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/alas/platform_base.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/alas/platform_windows.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/alas/utils.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/BaseCaptureMethod.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/adb/ADBCaptureMethod.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/adb/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/adb/bin/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/image/ImageCaptureMethod.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/image/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/d3d11.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/dump.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/utils.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/capture/windows/window.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/color/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/config/Config.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/config/InfoDict.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/config/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/feature/Feature.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/feature/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/firebase/Analytics.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/firebase/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/App.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/Communicate.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/MainWindow.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/MessageWindow.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/TabTitles.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/about/AboutTab.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/about/HttpTextEdit.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/about/VersionCard.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/about/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/common/OKIcon.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/common/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/common/config.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/common/style_sheet.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/debug/AspectRatioWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/debug/FrameWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/debug/InfoWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/debug/LoggerWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/debug/Screenshot.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/debug/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/i18n/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/i18n/path.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/i18n/update.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/icon/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/icon/icon.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/overlay/OverlayWindow.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/overlay/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/qss/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/resources.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/settings/SettingTab.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/settings/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/start/SelectCaptureListView.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/start/StartCard.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/start/StartTab.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/start/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/ConfigItemFactory.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/LabelAndDropDown.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/LabelAndList.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/LabelAndWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/ModifyListDialog.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/ModifyListItem.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/StartButton.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/TaskCard.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/TaskOpButton.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/TooltipTableWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/TriggerTaskTab.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/tasks/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/util/Alert.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/util/InitWorker.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/util/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/Card.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/EmptyCard.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/FramelessDialog.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/ListTableWidgetItem.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/StartLoadingDialog.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/StatusBar.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/Tab.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/TabWidget.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/YesNonWidgetItem.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/gui/widget/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/interaction/ADBInteraction.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/interaction/DoNothingInteraction.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/interaction/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/logging/Logger.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/logging/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/ocr/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/Windows/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/delegate.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/export.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/idldsl.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/inspectable.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/roapi.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/types.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/rotypes/winstring.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/save/BlackBarProcessor.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/save/PostProcessor.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/save/SaveByInterval.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/save/SaveByKeyPress.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/save/SaveMethodBase.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/save/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/scene/FeatureScene.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/scene/Scene.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/scene/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/stats/StreamStats.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/stats/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/task/BaseTask.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/task/OneTimeTask.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/task/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/update/GithubMultiDownloader.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/update/Updater.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/update/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/update/gen_md5.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/Handler.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/exit_event.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/json.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/list.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/path.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/thread.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/win32_process.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok/util/yaml.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok_script.egg-info/SOURCES.txt +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok_script.egg-info/requires.txt +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/ok_script.egg-info/top_level.txt +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/setup.cfg +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/tests/__init__.py +0 -0
- {ok-script-0.0.82 → ok-script-0.0.83}/tests/test_updater.py +0 -0
|
@@ -180,22 +180,25 @@ def find_hwnd(title, exe_name, frame_width, frame_height):
|
|
|
180
180
|
win32gui.EnumWindows(callback, None)
|
|
181
181
|
biggest = None
|
|
182
182
|
if len(results) > 0:
|
|
183
|
+
biggest = results[0]
|
|
183
184
|
for result in results:
|
|
184
185
|
from ok.capture.windows.BitBltCaptureMethod import bit_blt_test_hwnd
|
|
185
186
|
if (biggest is None or (result[2] * result[3]) > biggest[2] * biggest[3]) and bit_blt_test_hwnd(result[0]):
|
|
186
187
|
biggest = result
|
|
187
188
|
x_offset = 0
|
|
188
189
|
y_offset = 0
|
|
189
|
-
real_width
|
|
190
|
-
|
|
190
|
+
real_width = 0
|
|
191
|
+
real_height = 0
|
|
192
|
+
if frame_aspect_ratio != 0:
|
|
191
193
|
real_width, real_height = biggest[2], biggest[3]
|
|
192
194
|
matching_child = enum_child_windows(biggest, frame_aspect_ratio)
|
|
193
195
|
if matching_child is not None:
|
|
194
196
|
x_offset, y_offset, real_width, real_height = matching_child
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
logger.info(
|
|
198
|
+
f'find_hwnd {frame_width, frame_height} {biggest} {x_offset, y_offset, real_width, real_height}')
|
|
199
|
+
return biggest[6], biggest[0], biggest[1], x_offset, y_offset, real_width, real_height
|
|
200
|
+
|
|
201
|
+
return None, None, None, 0, 0, 0, 0
|
|
199
202
|
|
|
200
203
|
|
|
201
204
|
def enum_child_windows(biggest, frame_aspect_ratio):
|
|
@@ -99,12 +99,12 @@ class DeviceManager:
|
|
|
99
99
|
pc_device["resolution"] = f"{width}x{height}"
|
|
100
100
|
self.device_dict['pc'] = pc_device
|
|
101
101
|
|
|
102
|
-
def do_refresh(self,
|
|
102
|
+
def do_refresh(self, current=False):
|
|
103
103
|
self.update_pc_device()
|
|
104
104
|
|
|
105
|
-
self.refresh_emulators()
|
|
105
|
+
self.refresh_emulators(current)
|
|
106
106
|
|
|
107
|
-
self.refresh_phones()
|
|
107
|
+
self.refresh_phones(current)
|
|
108
108
|
|
|
109
109
|
if self.exit_event.is_set():
|
|
110
110
|
return
|
|
@@ -112,10 +112,16 @@ class DeviceManager:
|
|
|
112
112
|
|
|
113
113
|
logger.debug(f'refresh {self.device_dict}')
|
|
114
114
|
|
|
115
|
-
def refresh_phones(self):
|
|
115
|
+
def refresh_phones(self, current=False):
|
|
116
|
+
if self.adb_capture_config is None:
|
|
117
|
+
return
|
|
116
118
|
for adb_device in self.adb.iter_device():
|
|
117
119
|
imei = self.adb_get_imei(adb_device)
|
|
118
120
|
if imei is not None:
|
|
121
|
+
preferred = self.get_preferred_device()
|
|
122
|
+
if current and preferred is not None and preferred['imei'] != imei:
|
|
123
|
+
logger.debug(f"refresh current only skip others {preferred['imei']} != imei")
|
|
124
|
+
break
|
|
119
125
|
found = False
|
|
120
126
|
for device in self.device_dict.values():
|
|
121
127
|
if device.get('adb_imei') == imei:
|
|
@@ -129,13 +135,17 @@ class DeviceManager:
|
|
|
129
135
|
"resolution": f'{width}x{height}'}
|
|
130
136
|
self.device_dict[imei] = phone_device
|
|
131
137
|
|
|
132
|
-
def refresh_emulators(self):
|
|
138
|
+
def refresh_emulators(self, current=False):
|
|
133
139
|
if self.adb_capture_config is None:
|
|
134
140
|
return
|
|
135
141
|
from ok.alas.emulator_windows import EmulatorManager
|
|
136
142
|
manager = EmulatorManager()
|
|
137
143
|
installed_emulators = manager.all_emulator_instances
|
|
138
144
|
for emulator in installed_emulators:
|
|
145
|
+
preferred = self.get_preferred_device()
|
|
146
|
+
if current and preferred is not None and preferred['imei'] != emulator.name:
|
|
147
|
+
logger.debug(f"refresh current only skip others {preferred['imei']} != {emulator.name}")
|
|
148
|
+
break
|
|
139
149
|
adb_device = self.adb_connect(emulator.serial)
|
|
140
150
|
width, height = self.get_resolution(adb_device)
|
|
141
151
|
name, hwnd, full_path, x, y, width, height = find_hwnd(None,
|
|
@@ -192,12 +202,13 @@ class DeviceManager:
|
|
|
192
202
|
self.start()
|
|
193
203
|
logger.debug(f'preferred device: {preferred}')
|
|
194
204
|
|
|
195
|
-
|
|
205
|
+
@staticmethod
|
|
206
|
+
def adb_get_imei(device):
|
|
196
207
|
try:
|
|
197
208
|
return device.shell("settings get secure android_id") or device.shell(
|
|
198
209
|
"service call iphonesubinfo 4") or device.prop.model
|
|
199
210
|
except Exception as e:
|
|
200
|
-
logger.error(f"adb_get_imei error {device}"
|
|
211
|
+
logger.error(f"adb_get_imei error maybe offline {device}")
|
|
201
212
|
return None
|
|
202
213
|
|
|
203
214
|
def get_preferred_device(self):
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from ok.feature.Box import Box
|
|
5
|
+
|
|
6
|
+
black_color = {
|
|
7
|
+
'r': (0, 0), # Red range
|
|
8
|
+
'g': (0, 0), # Green range
|
|
9
|
+
'b': (0, 0) # Blue range
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
white_color = {
|
|
13
|
+
'r': (255, 255), # Red range
|
|
14
|
+
'g': (255, 255), # Green range
|
|
15
|
+
'b': (255, 255) # Blue range
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def calculate_colorfulness(image, box=None):
|
|
20
|
+
if box is not None:
|
|
21
|
+
image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
|
|
22
|
+
# Split the image into its respective RGB components
|
|
23
|
+
(B, G, R) = cv2.split(image.astype("float"))
|
|
24
|
+
|
|
25
|
+
# Compute rg = R - G
|
|
26
|
+
rg = np.absolute(R - G)
|
|
27
|
+
|
|
28
|
+
# Compute yb = 0.5 * (R + G) - B
|
|
29
|
+
yb = np.absolute(0.5 * (R + G) - B)
|
|
30
|
+
|
|
31
|
+
# Compute the mean and standard deviation of both rg and yb
|
|
32
|
+
(rbMean, rbStd) = (np.mean(rg), np.std(rg))
|
|
33
|
+
(ybMean, ybStd) = (np.mean(yb), np.std(yb))
|
|
34
|
+
|
|
35
|
+
# Combine the mean and standard deviation
|
|
36
|
+
stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2))
|
|
37
|
+
meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2))
|
|
38
|
+
|
|
39
|
+
# Derive the "colorfulness" metric
|
|
40
|
+
colorfulness = stdRoot + (0.3 * meanRoot)
|
|
41
|
+
|
|
42
|
+
return colorfulness / 100
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_saturation(image, box=None):
|
|
46
|
+
# Load the image
|
|
47
|
+
|
|
48
|
+
# Check if image loaded successfully
|
|
49
|
+
if image is None:
|
|
50
|
+
raise ValueError("Image not found or path is incorrect")
|
|
51
|
+
|
|
52
|
+
if box is not None:
|
|
53
|
+
if (box.x >= 0 and box.y >= 0 and
|
|
54
|
+
box.x + box.width <= image.shape[1] and # image.shape[1] is the width of the image
|
|
55
|
+
box.y + box.height <= image.shape[
|
|
56
|
+
0]) and box.width > 0 and box.height > 0: # image.shape[0] is the height of the image
|
|
57
|
+
|
|
58
|
+
# Extract the region of interest (ROI) using slicing
|
|
59
|
+
|
|
60
|
+
image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
|
|
61
|
+
|
|
62
|
+
# Convert image to HSV color space
|
|
63
|
+
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
|
64
|
+
|
|
65
|
+
# Extract the saturation channel
|
|
66
|
+
saturation_channel = hsv_image[:, :, 1]
|
|
67
|
+
|
|
68
|
+
# Calculate the mean saturation
|
|
69
|
+
mean_saturation = saturation_channel.mean() / 255
|
|
70
|
+
|
|
71
|
+
# If the mean saturation is above the threshold, the image is colored; otherwise, it is grayscale
|
|
72
|
+
return mean_saturation
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def find_color_rectangles(image, color_range, min_width, min_height, max_width=-1, max_height=-1, threshold=0.95,
|
|
76
|
+
box=None):
|
|
77
|
+
if image is None:
|
|
78
|
+
raise ValueError("Image not found or path is incorrect")
|
|
79
|
+
if box is not None:
|
|
80
|
+
image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
|
|
81
|
+
|
|
82
|
+
# Convert color range to BGR format for OpenCV
|
|
83
|
+
lower_bound = np.array([color_range['b'][0], color_range['g'][0], color_range['r'][0]], dtype="uint8")
|
|
84
|
+
upper_bound = np.array([color_range['b'][1], color_range['g'][1], color_range['r'][1]], dtype="uint8")
|
|
85
|
+
|
|
86
|
+
# Create a mask for the color range
|
|
87
|
+
mask = cv2.inRange(image, lower_bound, upper_bound)
|
|
88
|
+
|
|
89
|
+
# Find contours in the mask
|
|
90
|
+
contours, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
|
|
91
|
+
|
|
92
|
+
results = []
|
|
93
|
+
|
|
94
|
+
for contour in contours:
|
|
95
|
+
# Get the bounding rectangle
|
|
96
|
+
x, y, w, h = cv2.boundingRect(contour)
|
|
97
|
+
|
|
98
|
+
# Check if the rectangle meets the size criteria
|
|
99
|
+
if w >= min_width and h >= min_height and (max_height == -1 or h <= max_height) and (
|
|
100
|
+
max_width == -1 or w <= max_width):
|
|
101
|
+
|
|
102
|
+
# Extract the region of interest (ROI) from the mask
|
|
103
|
+
roi_mask = mask[y:y + h, x:x + w]
|
|
104
|
+
|
|
105
|
+
# Calculate the total number of pixels in the ROI
|
|
106
|
+
total_pixels = roi_mask.size
|
|
107
|
+
|
|
108
|
+
# Calculate the number of matching pixels (value 255)
|
|
109
|
+
matching_pixels = np.sum(roi_mask == 255)
|
|
110
|
+
|
|
111
|
+
# Check if the percentage of matching pixels is greater than or equal to 90%\
|
|
112
|
+
percent = (matching_pixels / total_pixels)
|
|
113
|
+
if percent >= threshold:
|
|
114
|
+
# Store the result
|
|
115
|
+
results.append(
|
|
116
|
+
Box(x, y, w, h, confidence=percent)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return results
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def calculate_color_percentage(image, color_ranges, box=None):
|
|
123
|
+
# Check if the ROI is within the image bounds
|
|
124
|
+
if box is not None:
|
|
125
|
+
if (box.x >= 0 and box.y >= 0 and
|
|
126
|
+
box.x + box.width <= image.shape[1] and # image.shape[1] is the width of the image
|
|
127
|
+
box.y + box.height <= image.shape[
|
|
128
|
+
0]) and box.width > 0 and box.height > 0: # image.shape[0] is the height of the image
|
|
129
|
+
|
|
130
|
+
# Extract the region of interest (ROI) using slicing
|
|
131
|
+
|
|
132
|
+
image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
|
|
133
|
+
else:
|
|
134
|
+
# Return some error value or raise an exception
|
|
135
|
+
# For example, return 0 or None
|
|
136
|
+
return 0 # or None, or raise an exception
|
|
137
|
+
else:
|
|
138
|
+
image = image[:, :, :3]
|
|
139
|
+
# Create a mask for the pixels within the desired color range
|
|
140
|
+
mask = cv2.inRange(image,
|
|
141
|
+
(color_ranges['b'][0], color_ranges['g'][0], color_ranges['r'][0]),
|
|
142
|
+
(color_ranges['b'][1], color_ranges['g'][1], color_ranges['r'][1]))
|
|
143
|
+
|
|
144
|
+
# Calculate the percentage of pixels within the color range
|
|
145
|
+
target_pixels = cv2.countNonZero(mask)
|
|
146
|
+
total_pixels = image.size / 3 # Divide by 3 for an RGB image
|
|
147
|
+
percentage = target_pixels / total_pixels
|
|
148
|
+
return percentage
|
|
@@ -10,14 +10,14 @@ class Box:
|
|
|
10
10
|
confidence: float = 1,
|
|
11
11
|
name=None, to_x: int | float = -1, to_y: int | float = -1) -> None:
|
|
12
12
|
self.name = name
|
|
13
|
-
self.x =
|
|
14
|
-
self.y =
|
|
13
|
+
self.x = round(x)
|
|
14
|
+
self.y = round(y)
|
|
15
15
|
if to_x != -1 and to_y != -1:
|
|
16
|
-
self.width =
|
|
17
|
-
self.height =
|
|
16
|
+
self.width = round(to_x - x)
|
|
17
|
+
self.height = round(to_y - y)
|
|
18
18
|
else:
|
|
19
|
-
self.width =
|
|
20
|
-
self.height =
|
|
19
|
+
self.width = round(width)
|
|
20
|
+
self.height = round(height)
|
|
21
21
|
if self.width <= 0 or self.height <= 0:
|
|
22
22
|
raise ValueError(f'width and height must be greater than zero {x} {y} {width} {height} {to_x} {to_y}')
|
|
23
23
|
self.confidence = confidence
|
|
@@ -265,6 +265,6 @@ def relative_box(frame_width, frame_height, x, y, to_x=1, to_y=1, width=0, heigh
|
|
|
265
265
|
width = to_x - x
|
|
266
266
|
if height == 0:
|
|
267
267
|
height = to_y - y
|
|
268
|
-
return Box(
|
|
269
|
-
|
|
268
|
+
return Box(round(x * frame_width), round(y * frame_height),
|
|
269
|
+
round(width * frame_width), round(height * frame_height),
|
|
270
270
|
name=name)
|
|
@@ -145,7 +145,7 @@ class FeatureSet:
|
|
|
145
145
|
|
|
146
146
|
def find_feature(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
|
|
147
147
|
vertical_variance: float = 0, threshold: float = 0, use_gray_scale: bool = False, x=-1, y=-1,
|
|
148
|
-
to_x=-1, to_y=-1, width=-1, height=-1) -> List[Box]:
|
|
148
|
+
to_x=-1, to_y=-1, width=-1, height=-1, box=None) -> List[Box]:
|
|
149
149
|
"""
|
|
150
150
|
Find a feature within a given variance.
|
|
151
151
|
|
|
@@ -172,7 +172,12 @@ class FeatureSet:
|
|
|
172
172
|
raise ValueError(f"FeatureSet: " + category_name + " not found in featureDict")
|
|
173
173
|
feature = self.feature_dict[category_name]
|
|
174
174
|
feature_width, feature_height = feature.width, feature.height
|
|
175
|
-
if
|
|
175
|
+
if box is not None:
|
|
176
|
+
search_x1 = box.x
|
|
177
|
+
search_y1 = box.y
|
|
178
|
+
search_x2 = box.x + box.width
|
|
179
|
+
search_y2 = box.y + box.height
|
|
180
|
+
elif x != -1 and y != -1:
|
|
176
181
|
frame_height, frame_width, *_ = mat.shape
|
|
177
182
|
if width == -1:
|
|
178
183
|
width = to_x - x
|
|
@@ -11,11 +11,9 @@ class FindFeature:
|
|
|
11
11
|
self.executor = None
|
|
12
12
|
|
|
13
13
|
def find_feature(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
|
|
14
|
-
use_gray_scale=False, x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1) -> List[Box]:
|
|
15
|
-
if self.executor.frame is None:
|
|
16
|
-
return list()
|
|
14
|
+
use_gray_scale=False, x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1, box=None) -> List[Box]:
|
|
17
15
|
return self.feature_set.find_feature(self.executor.frame, feature_name, horizontal_variance, vertical_variance,
|
|
18
|
-
threshold, use_gray_scale, x, y, to_x, to_y, width, height)
|
|
16
|
+
threshold, use_gray_scale, x, y, to_x, to_y, width, height, box=box)
|
|
19
17
|
|
|
20
18
|
def get_box_by_name(self, name):
|
|
21
19
|
return self.feature_set.get_box_by_name(self.executor.frame, name)
|
|
@@ -47,7 +45,8 @@ class FindFeature:
|
|
|
47
45
|
|
|
48
46
|
def find_one(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
|
|
49
47
|
use_gray_scale=False) -> Box:
|
|
50
|
-
boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold,
|
|
48
|
+
boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold,
|
|
49
|
+
use_gray_scale=use_gray_scale)
|
|
51
50
|
if len(boxes) > 0:
|
|
52
51
|
if len(boxes) > 1:
|
|
53
52
|
print(f"find_one:found {feature_name} too many {len(boxes)}", file=sys.stderr)
|
|
@@ -24,7 +24,7 @@ class StartController(QObject):
|
|
|
24
24
|
|
|
25
25
|
def do_start(self, task=None):
|
|
26
26
|
communicate.starting_emulator.emit(False, None, 30)
|
|
27
|
-
ok.gui.device_manager.do_refresh()
|
|
27
|
+
ok.gui.device_manager.do_refresh(True)
|
|
28
28
|
|
|
29
29
|
device = ok.gui.device_manager.get_preferred_device()
|
|
30
30
|
|
|
@@ -35,7 +35,7 @@ class StartController(QObject):
|
|
|
35
35
|
execute(path)
|
|
36
36
|
wait_until = time.time() + 30
|
|
37
37
|
while not self.exit_event.is_set():
|
|
38
|
-
ok.gui.device_manager.do_refresh()
|
|
38
|
+
ok.gui.device_manager.do_refresh(True)
|
|
39
39
|
error = self.check_device_error()
|
|
40
40
|
if error is None:
|
|
41
41
|
break
|
|
@@ -88,6 +88,7 @@ class DebugTab(Tab):
|
|
|
88
88
|
self.task_changed(self.config.get('target_task'))
|
|
89
89
|
else:
|
|
90
90
|
self.tasks_combo_box.setCurrentIndex(0)
|
|
91
|
+
self.config['target_task'] = class_names[0]
|
|
91
92
|
|
|
92
93
|
self.call_button = PushButton(self.tr("Call"))
|
|
93
94
|
self.call_button.clicked.connect(lambda: self.handler.post(self.call))
|
|
@@ -146,8 +147,9 @@ class DebugTab(Tab):
|
|
|
146
147
|
old_interaction = ok.gui.device_manager.interaction
|
|
147
148
|
try:
|
|
148
149
|
images = self.config.get("target_images")
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
if images:
|
|
151
|
+
ok.gui.device_manager.capture_method = ImageCaptureMethod(images)
|
|
152
|
+
ok.gui.device_manager.interaction = DoNothingInteraction(ok.gui.device_manager.capture_method)
|
|
151
153
|
ok.gui.executor.debug_mode = True
|
|
152
154
|
attr = getattr(task, func_name)
|
|
153
155
|
if callable(attr):
|
|
@@ -22,10 +22,23 @@ class Win32Interaction(BaseInteraction):
|
|
|
22
22
|
|
|
23
23
|
def send_key(self, key, down_time=0.02):
|
|
24
24
|
if not self.capture.clickable():
|
|
25
|
+
logger.error(f"can't click on {key}, because capture is not clickable")
|
|
25
26
|
return
|
|
26
|
-
pydirectinput.keyDown(key)
|
|
27
|
+
pydirectinput.keyDown(str(key))
|
|
27
28
|
time.sleep(down_time)
|
|
28
|
-
pydirectinput.keyUp(key)
|
|
29
|
+
pydirectinput.keyUp(str(key))
|
|
30
|
+
|
|
31
|
+
def send_key_down(self, key):
|
|
32
|
+
if not self.capture.clickable():
|
|
33
|
+
logger.error(f"can't click on {key}, because capture is not clickable")
|
|
34
|
+
return
|
|
35
|
+
pydirectinput.keyDown(str(key))
|
|
36
|
+
|
|
37
|
+
def send_key_up(self, key):
|
|
38
|
+
if not self.capture.clickable():
|
|
39
|
+
logger.error(f"can't click on {key}, because capture is not clickable")
|
|
40
|
+
return
|
|
41
|
+
pydirectinput.keyUp(str(key))
|
|
29
42
|
|
|
30
43
|
def move(self, x, y):
|
|
31
44
|
if not self.capture.clickable():
|
|
@@ -82,6 +95,22 @@ class Win32Interaction(BaseInteraction):
|
|
|
82
95
|
if current_x != -1 and current_y != -1:
|
|
83
96
|
pydirectinput.moveTo(current_x, current_y)
|
|
84
97
|
|
|
98
|
+
def mouse_down(self, x=-1, y=-1, name=None):
|
|
99
|
+
if not self.capture.clickable():
|
|
100
|
+
logger.info(f"window in background, not clickable")
|
|
101
|
+
return
|
|
102
|
+
if x != -1 and y != -1:
|
|
103
|
+
x, y = self.capture.get_abs_cords(x, y)
|
|
104
|
+
logger.info(f"left_click {x, y}")
|
|
105
|
+
pydirectinput.moveTo(x, y)
|
|
106
|
+
pydirectinput.mouseDown()
|
|
107
|
+
|
|
108
|
+
def mouse_up(self):
|
|
109
|
+
if not self.capture.clickable():
|
|
110
|
+
logger.info(f"window in background, not clickable")
|
|
111
|
+
return
|
|
112
|
+
pydirectinput.mouseUp()
|
|
113
|
+
|
|
85
114
|
def should_capture(self):
|
|
86
115
|
return self.capture.clickable()
|
|
87
116
|
|
|
@@ -44,12 +44,9 @@ class OCR:
|
|
|
44
44
|
box.name = str(match)
|
|
45
45
|
|
|
46
46
|
image, scale_factor = resize_image(image, original_height, target_height)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
logger.error('ocr_error sleep and retry once', e)
|
|
51
|
-
time.sleep(3)
|
|
52
|
-
result, _ = self.executor.ocr(image, use_det=True, use_cls=False, use_rec=True)
|
|
47
|
+
|
|
48
|
+
result, _ = self.executor.ocr(image, use_det=True, use_cls=False, use_rec=True)
|
|
49
|
+
|
|
53
50
|
detected_boxes = []
|
|
54
51
|
ocr_boxes = None
|
|
55
52
|
# Process the results and create Box objects
|
|
@@ -34,12 +34,27 @@ class ExecutorOperation:
|
|
|
34
34
|
def is_scene(self, the_scene):
|
|
35
35
|
return isinstance(self.executor.current_scene, the_scene)
|
|
36
36
|
|
|
37
|
-
def click(self, x, y, move_back=False, name=None):
|
|
37
|
+
def click(self, x=-1, y=-1, move_back=False, name=None):
|
|
38
38
|
frame = self.executor.nullable_frame()
|
|
39
39
|
communicate.emit_draw_box("click", [Box(max(0, x - 10), max(0, y - 10), 20, 20, name="click")], "green", frame)
|
|
40
40
|
self.executor.reset_scene()
|
|
41
41
|
self.executor.interaction.click(x, y, move_back, name=name)
|
|
42
42
|
|
|
43
|
+
def mouse_down(self, x=-1, y=-1, name=None):
|
|
44
|
+
frame = self.executor.nullable_frame()
|
|
45
|
+
communicate.emit_draw_box("mouse_down", [Box(max(0, x - 10), max(0, y - 10), 20, 20, name="click")], "green",
|
|
46
|
+
frame)
|
|
47
|
+
self.executor.reset_scene()
|
|
48
|
+
self.executor.interaction.mouse_down(x, y, name=name)
|
|
49
|
+
|
|
50
|
+
def mouse_up(self, name=None):
|
|
51
|
+
frame = self.executor.nullable_frame()
|
|
52
|
+
communicate.emit_draw_box("mouse_up", self.box_of_screen(0.5, 0.5, width=0.01, height=0.01, name="click"),
|
|
53
|
+
"green",
|
|
54
|
+
frame)
|
|
55
|
+
self.executor.reset_scene()
|
|
56
|
+
self.executor.interaction.mouse_up()
|
|
57
|
+
|
|
43
58
|
def swipe_relative(self, from_x, from_y, to_x, to_y, duration=0.5):
|
|
44
59
|
self.swipe(int(self.width * from_x), int(self.height * from_y), int(self.width * to_x),
|
|
45
60
|
int(self.height * to_y), duration)
|
|
@@ -83,7 +98,7 @@ class ExecutorOperation:
|
|
|
83
98
|
self.click_box(to_click, relative_x, relative_y)
|
|
84
99
|
return to_click
|
|
85
100
|
|
|
86
|
-
def box_of_screen(self, x, y, to_x=1, to_y=1, width=0, height=0, name=None):
|
|
101
|
+
def box_of_screen(self, x, y, to_x: float = 1, to_y: float = 1, width: float = 0, height: float = 0, name=None):
|
|
87
102
|
if name is None:
|
|
88
103
|
name = f"{x} {y} {width} {height}"
|
|
89
104
|
return relative_box(self.executor.method.width, self.executor.method.height, x, y,
|
|
@@ -138,8 +153,17 @@ class ExecutorOperation:
|
|
|
138
153
|
self.executor.sleep(timeout)
|
|
139
154
|
|
|
140
155
|
def send_key(self, key, down_time=0.02):
|
|
156
|
+
self.executor.reset_scene()
|
|
141
157
|
self.executor.interaction.send_key(key, down_time)
|
|
142
158
|
|
|
159
|
+
def send_key_down(self, key):
|
|
160
|
+
self.executor.reset_scene()
|
|
161
|
+
self.executor.interaction.send_key_down(key)
|
|
162
|
+
|
|
163
|
+
def send_key_up(self, key):
|
|
164
|
+
self.executor.reset_scene()
|
|
165
|
+
self.executor.interaction.send_key_up(key)
|
|
166
|
+
|
|
143
167
|
def wait_until(self, condition, time_out=0, pre_action=None, post_action=None, wait_until_before_delay=0):
|
|
144
168
|
return self.executor.wait_condition(condition, time_out, pre_action, post_action, wait_until_before_delay)
|
|
145
169
|
|
|
@@ -279,7 +279,7 @@ class TaskExecutor:
|
|
|
279
279
|
traceback.print_exc()
|
|
280
280
|
stack_trace_str = traceback.format_exc()
|
|
281
281
|
logger.error(f"{name} exception: {e}, traceback: {stack_trace_str}")
|
|
282
|
-
if self._frame:
|
|
282
|
+
if self._frame is not None:
|
|
283
283
|
communicate.screenshot.emit(self.frame, name)
|
|
284
284
|
self.current_task = None
|
|
285
285
|
if isinstance(self.current_task, OneTimeTask):
|
|
@@ -8,10 +8,11 @@ class TriggerTask(BaseTask):
|
|
|
8
8
|
|
|
9
9
|
def __init__(self):
|
|
10
10
|
super().__init__()
|
|
11
|
-
self.default_config = {'_enabled':
|
|
11
|
+
self.default_config = {'_enabled': False}
|
|
12
12
|
self.trigger_count = 0
|
|
13
13
|
|
|
14
14
|
def on_create(self):
|
|
15
|
+
self._enabled = self.config.get('_enabled', False)
|
|
15
16
|
pass
|
|
16
17
|
|
|
17
18
|
def get_status(self):
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import cv2
|
|
2
|
-
|
|
3
|
-
black_color = {
|
|
4
|
-
'r': (0, 0), # Red range
|
|
5
|
-
'g': (0, 0), # Green range
|
|
6
|
-
'b': (0, 0) # Blue range
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
white_color = {
|
|
10
|
-
'r': (255, 255), # Red range
|
|
11
|
-
'g': (255, 255), # Green range
|
|
12
|
-
'b': (255, 255) # Blue range
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def calculate_color_percentage(image, color_ranges, box=None):
|
|
17
|
-
# Check if the ROI is within the image bounds
|
|
18
|
-
if box is not None:
|
|
19
|
-
if (box.x >= 0 and box.y >= 0 and
|
|
20
|
-
box.x + box.width <= image.shape[1] and # image.shape[1] is the width of the image
|
|
21
|
-
box.y + box.height <= image.shape[
|
|
22
|
-
0]) and box.width > 0 and box.height > 0: # image.shape[0] is the height of the image
|
|
23
|
-
|
|
24
|
-
# Extract the region of interest (ROI) using slicing
|
|
25
|
-
|
|
26
|
-
image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
|
|
27
|
-
else:
|
|
28
|
-
# Return some error value or raise an exception
|
|
29
|
-
# For example, return 0 or None
|
|
30
|
-
return 0 # or None, or raise an exception
|
|
31
|
-
else:
|
|
32
|
-
image = image[:, :, :3]
|
|
33
|
-
# Create a mask for the pixels within the desired color range
|
|
34
|
-
mask = cv2.inRange(image,
|
|
35
|
-
(color_ranges['b'][0], color_ranges['g'][0], color_ranges['r'][0]),
|
|
36
|
-
(color_ranges['b'][1], color_ranges['g'][1], color_ranges['r'][1]))
|
|
37
|
-
|
|
38
|
-
# Calculate the percentage of pixels within the color range
|
|
39
|
-
target_pixels = cv2.countNonZero(mask)
|
|
40
|
-
total_pixels = image.size / 3 # Divide by 3 for an RGB image
|
|
41
|
-
percentage = target_pixels / total_pixels
|
|
42
|
-
return percentage
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|