ok-script 0.0.85__tar.gz → 0.0.87__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.85 → ok-script-0.0.87}/PKG-INFO +1 -1
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/OK.py +1 -1
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/HwndWindow.py +7 -2
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/DeviceManager.py +13 -14
- ok-script-0.0.87/ok/capture/adb/WindowsCaptureFactory.py +42 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +66 -59
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/config/Config.py +3 -1
- ok-script-0.0.87/ok/feature/CompressCoco.py +57 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/FeatureSet.py +68 -53
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/FindFeature.py +2 -2
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/App.py +6 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/MainWindow.py +3 -6
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/DebugTab.py +0 -3
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/FrameWidget.py +4 -6
- ok-script-0.0.87/ok/gui/debug/LogWindow.py +190 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/Screenshot.py +0 -1
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TaskCard.py +5 -5
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TaskOpButton.py +2 -8
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/BaseInteraction.py +3 -3
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/ocr/OCR.py +1 -1
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/BaseTask.py +30 -13
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/ExecutorOperation.py +8 -5
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/TaskExecutor.py +33 -35
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/TriggerTask.py +1 -2
- ok-script-0.0.87/ok/util/list.py +9 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/PKG-INFO +1 -1
- {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/SOURCES.txt +2 -2
- {ok-script-0.0.85 → ok-script-0.0.87}/setup.py +1 -1
- ok-script-0.0.85/ok/capture/adb/WindowsCaptureFactory.py +0 -41
- ok-script-0.0.85/ok/gui/debug/LoggerWidget.py +0 -77
- ok-script-0.0.85/ok/task/OneTimeTask.py +0 -35
- ok-script-0.0.85/ok/util/list.py +0 -2
- {ok-script-0.0.85 → ok-script-0.0.87}/README.md +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/emulator_base.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/emulator_windows.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/platform_base.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/platform_windows.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/utils.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/BaseCaptureMethod.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/ADBCaptureMethod.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/bin/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/image/ImageCaptureMethod.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/image/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/d3d11.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/dump.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/utils.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/window.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/color/Color.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/color/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/config/InfoDict.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/config/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/Box.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/Feature.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/firebase/Analytics.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/firebase/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/Communicate.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/MessageWindow.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/StartController.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/TabTitles.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/AboutTab.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/HttpTextEdit.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/VersionCard.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/OKIcon.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/config.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/style_sheet.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/AspectRatioWidget.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/InfoWidget.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/i18n/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/i18n/path.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/i18n/update.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/icon/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/icon/icon.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/overlay/OverlayWindow.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/overlay/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/qss/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/resources.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/settings/SettingTab.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/settings/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/SelectCaptureListView.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/StartCard.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/StartTab.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ConfigItemFactory.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndDropDown.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndList.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndWidget.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ModifyListDialog.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ModifyListItem.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/StartButton.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TooltipTableWidget.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TriggerTaskTab.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/util/Alert.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/util/InitWorker.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/util/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/Card.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/EmptyCard.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/FramelessDialog.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/ListTableWidgetItem.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/StartLoadingDialog.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/StatusBar.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/Tab.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/TabWidget.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/YesNonWidgetItem.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/ADBInteraction.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/DoNothingInteraction.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/Win32Interaction.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/logging/Logger.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/logging/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/ocr/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/delegate.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/export.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/idldsl.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/inspectable.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/roapi.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/types.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/winstring.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/BlackBarProcessor.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/PostProcessor.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/SaveByInterval.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/SaveByKeyPress.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/SaveMethodBase.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/scene/FeatureScene.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/scene/Scene.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/scene/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/stats/StreamStats.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/stats/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/GithubMultiDownloader.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/Updater.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/gen_md5.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/Handler.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/exit_event.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/json.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/path.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/thread.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/win32_process.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/yaml.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/requires.txt +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/top_level.txt +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/setup.cfg +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/tests/__init__.py +0 -0
- {ok-script-0.0.85 → ok-script-0.0.87}/tests/test_updater.py +0 -0
|
@@ -97,7 +97,7 @@ class OK:
|
|
|
97
97
|
if template_matching is not None:
|
|
98
98
|
coco_feature_json = self.config.get('template_matching').get('coco_feature_json')
|
|
99
99
|
from ok.feature.FeatureSet import FeatureSet
|
|
100
|
-
self.feature_set = FeatureSet(coco_feature_json,
|
|
100
|
+
self.feature_set = FeatureSet(self.debug, coco_feature_json,
|
|
101
101
|
default_horizontal_variance=template_matching.get(
|
|
102
102
|
'default_horizontal_variance', 0),
|
|
103
103
|
default_vertical_variance=template_matching.get('default_vertical_variance',
|
|
@@ -160,6 +160,8 @@ def find_hwnd(title, exe_name, frame_width, frame_height, player_id=-1):
|
|
|
160
160
|
elif not re.search(title, text):
|
|
161
161
|
return True
|
|
162
162
|
name, full_path, cmdline = get_exe_by_hwnd(hwnd)
|
|
163
|
+
if not name:
|
|
164
|
+
return True
|
|
163
165
|
x, y, border, title_height, width, height, scaling, ext_left_bounds, ext_top_bounds = get_window_bounds(
|
|
164
166
|
hwnd)
|
|
165
167
|
ret = (hwnd, full_path, width, height, x, y, text)
|
|
@@ -246,8 +248,11 @@ def get_exe_by_hwnd(hwnd):
|
|
|
246
248
|
_, pid = win32process.GetWindowThreadProcessId(hwnd)
|
|
247
249
|
|
|
248
250
|
# Get the process name and executable path
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
if pid > 0:
|
|
252
|
+
process = psutil.Process(pid)
|
|
253
|
+
return process.name(), process.exe(), process.cmdline()
|
|
254
|
+
else:
|
|
255
|
+
return None, None, None
|
|
251
256
|
|
|
252
257
|
|
|
253
258
|
if __name__ == '__main__':
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from adbutils import AdbTimeout
|
|
1
|
+
from adbutils import AdbTimeout, AdbError
|
|
2
2
|
|
|
3
3
|
from ok.alas.platform_windows import get_emulator_exe
|
|
4
4
|
from ok.capture.HwndWindow import HwndWindow, find_hwnd
|
|
@@ -53,27 +53,25 @@ class DeviceManager:
|
|
|
53
53
|
logger.debug(f'connect adb')
|
|
54
54
|
return self._adb
|
|
55
55
|
|
|
56
|
-
def adb_connect(self, addr):
|
|
56
|
+
def adb_connect(self, addr, try_connect=True):
|
|
57
57
|
try:
|
|
58
|
-
for
|
|
58
|
+
for device in self.adb.device_list():
|
|
59
59
|
if self.exit_event.is_set():
|
|
60
60
|
logger.error(f"adb_connect exit_event is set")
|
|
61
61
|
return None
|
|
62
|
-
if
|
|
63
|
-
if info
|
|
62
|
+
if device.serial == addr:
|
|
63
|
+
if device.info['state'] == 'offline':
|
|
64
64
|
logger.debug(f'adb_connect offline disconnect first {addr}')
|
|
65
65
|
self.adb.disconnect(addr)
|
|
66
66
|
else:
|
|
67
67
|
logger.debug(f'adb_connect already connected {addr}')
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
return device
|
|
69
|
+
if try_connect:
|
|
70
|
+
self.adb.connect(addr, timeout=5)
|
|
71
|
+
logger.debug(f'adb_connect {addr}')
|
|
72
|
+
return self.adb_connect(addr, try_connect=False)
|
|
73
73
|
except AdbTimeout as e:
|
|
74
74
|
logger.error(f"adb connect error try kill server {addr}", e)
|
|
75
|
-
# self.adb.server_kill()
|
|
76
|
-
# self._adb = None
|
|
77
75
|
except Exception as e:
|
|
78
76
|
logger.error(f"adb connect error return none {addr}", e)
|
|
79
77
|
|
|
@@ -145,7 +143,7 @@ class DeviceManager:
|
|
|
145
143
|
logger.debug(f"refresh current only skip others {preferred['imei']} != {emulator.name}")
|
|
146
144
|
break
|
|
147
145
|
adb_device = self.adb_connect(emulator.serial)
|
|
148
|
-
width, height = self.get_resolution(adb_device)
|
|
146
|
+
width, height = self.get_resolution(adb_device) if adb_device is not None else 0, 0
|
|
149
147
|
name, hwnd, full_path, x, y, width, height = find_hwnd(None,
|
|
150
148
|
emulator.path, width, height, emulator.player_id)
|
|
151
149
|
connected = adb_device is not None and name is not None
|
|
@@ -339,12 +337,13 @@ class DeviceManager:
|
|
|
339
337
|
if device is not None:
|
|
340
338
|
try:
|
|
341
339
|
return device.shell(*args, **kwargs)
|
|
340
|
+
except AdbError as e:
|
|
341
|
+
logger.debug(f'shell adb error {args} {e}')
|
|
342
342
|
except Exception as e:
|
|
343
343
|
addr = self.get_preferred_device()['address']
|
|
344
344
|
self.refresh_emulators()
|
|
345
345
|
new_addr = self.get_preferred_device()['address']
|
|
346
346
|
logger.error(f"shell_wrapper error occurred, try refresh_emulators {addr} {new_addr}", e)
|
|
347
|
-
return None
|
|
348
347
|
else:
|
|
349
348
|
raise Exception('Device is none')
|
|
350
349
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from ok.logging.Logger import get_logger
|
|
2
|
+
|
|
3
|
+
logger = get_logger(__name__)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def update_capture_method(config, capture_method, hwnd, require_bg=False, use_bit_blt_only=False):
|
|
7
|
+
try:
|
|
8
|
+
if config.get('can_bit_blt'):
|
|
9
|
+
logger.debug(
|
|
10
|
+
f"try BitBlt method {config} {hwnd} current_type:{type(capture_method)}")
|
|
11
|
+
from ok.capture.windows.BitBltCaptureMethod import BitBltCaptureMethod
|
|
12
|
+
target_method = BitBltCaptureMethod
|
|
13
|
+
capture_method = get_capture(capture_method, target_method, hwnd)
|
|
14
|
+
if capture_method.test_exclusive_full_screen():
|
|
15
|
+
return capture_method
|
|
16
|
+
else:
|
|
17
|
+
logger.info("test_exclusive_full_screen failed, can't use BitBlt")
|
|
18
|
+
if use_bit_blt_only:
|
|
19
|
+
return None
|
|
20
|
+
from ok.capture.windows.WindowsGraphicsCaptureMethod import windows_graphics_available
|
|
21
|
+
if windows_graphics_available():
|
|
22
|
+
from ok.capture.windows.WindowsGraphicsCaptureMethod import WindowsGraphicsCaptureMethod
|
|
23
|
+
target_method = WindowsGraphicsCaptureMethod
|
|
24
|
+
capture_method = get_capture(capture_method, target_method, hwnd)
|
|
25
|
+
return capture_method
|
|
26
|
+
|
|
27
|
+
if not require_bg:
|
|
28
|
+
from ok.capture.windows.DesktopDuplicationCaptureMethod import DesktopDuplicationCaptureMethod
|
|
29
|
+
target_method = DesktopDuplicationCaptureMethod
|
|
30
|
+
capture_method = get_capture(capture_method, target_method, hwnd)
|
|
31
|
+
return capture_method
|
|
32
|
+
except Exception as e:
|
|
33
|
+
logger.error(f'update_capture_method exception, return None: ', e)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_capture(capture_method, target_method, hwnd):
|
|
37
|
+
if not isinstance(capture_method, target_method):
|
|
38
|
+
if capture_method is not None:
|
|
39
|
+
capture_method.close()
|
|
40
|
+
capture_method = target_method(hwnd)
|
|
41
|
+
capture_method.hwnd_window = hwnd
|
|
42
|
+
return capture_method
|
|
@@ -23,7 +23,7 @@ logger = get_logger(__name__)
|
|
|
23
23
|
class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
24
24
|
name = "Windows Graphics Capture"
|
|
25
25
|
description = "fast, most compatible, capped at 60fps"
|
|
26
|
-
|
|
26
|
+
last_dx_frame = None
|
|
27
27
|
last_frame_time = 0
|
|
28
28
|
frame_pool = None
|
|
29
29
|
item = None
|
|
@@ -38,67 +38,71 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
38
38
|
|
|
39
39
|
def frame_arrived_callback(self, x, y):
|
|
40
40
|
try:
|
|
41
|
-
|
|
41
|
+
self.last_frame_time = time.time()
|
|
42
|
+
self.last_dx_frame = self.frame_pool.TryGetNextFrame()
|
|
42
43
|
except Exception as e:
|
|
43
44
|
logger.error(f"TryGetNextFrame error {e}")
|
|
44
45
|
self.close()
|
|
45
46
|
return
|
|
47
|
+
|
|
48
|
+
def convert_dx_frame(self):
|
|
49
|
+
frame = self.last_dx_frame
|
|
46
50
|
if not frame:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
need_reset_framepool = False
|
|
54
|
+
if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
|
|
55
|
+
need_reset_framepool = True
|
|
56
|
+
self.last_size = frame.ContentSize
|
|
57
|
+
|
|
58
|
+
if need_reset_framepool:
|
|
59
|
+
logger.info('need_reset_framepool')
|
|
60
|
+
self.reset_framepool(frame.ContentSize)
|
|
47
61
|
return
|
|
48
|
-
|
|
49
|
-
img = None
|
|
50
|
-
with frame:
|
|
51
|
-
need_reset_framepool = False
|
|
52
|
-
need_reset_device = False
|
|
53
|
-
if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
|
|
54
|
-
need_reset_framepool = True
|
|
55
|
-
self.last_size = frame.ContentSize
|
|
62
|
+
need_reset_device = False
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
self.reset_framepool(frame.ContentSize)
|
|
59
|
-
return
|
|
60
|
-
tex = None
|
|
64
|
+
tex = None
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
66
|
+
cputex = None
|
|
67
|
+
try:
|
|
68
|
+
from ok.rotypes.Windows.Graphics.DirectX.Direct3D11 import IDirect3DDxgiInterfaceAccess
|
|
69
|
+
from ok.rotypes.roapi import GetActivationFactory
|
|
70
|
+
tex = frame.Surface.astype(IDirect3DDxgiInterfaceAccess).GetInterface(
|
|
71
|
+
d3d11.ID3D11Texture2D.GUID).astype(d3d11.ID3D11Texture2D)
|
|
72
|
+
desc = tex.GetDesc()
|
|
73
|
+
desc2 = d3d11.D3D11_TEXTURE2D_DESC()
|
|
74
|
+
desc2.Width = desc.Width
|
|
75
|
+
desc2.Height = desc.Height
|
|
76
|
+
desc2.MipLevels = desc.MipLevels
|
|
77
|
+
desc2.ArraySize = desc.ArraySize
|
|
78
|
+
desc2.Format = desc.Format
|
|
79
|
+
desc2.SampleDesc = desc.SampleDesc
|
|
80
|
+
desc2.Usage = d3d11.D3D11_USAGE_STAGING
|
|
81
|
+
desc2.CPUAccessFlags = d3d11.D3D11_CPU_ACCESS_READ
|
|
82
|
+
desc2.BindFlags = 0
|
|
83
|
+
desc2.MiscFlags = 0
|
|
84
|
+
cputex = self.dxdevice.CreateTexture2D(ctypes.byref(desc2), None)
|
|
85
|
+
self.immediatedc.CopyResource(cputex, tex)
|
|
86
|
+
mapinfo = self.immediatedc.Map(cputex, 0, d3d11.D3D11_MAP_READ, 0)
|
|
87
|
+
img = np.ctypeslib.as_array(ctypes.cast(mapinfo.pData, PBYTE),
|
|
88
|
+
(desc.Height, mapinfo.RowPitch // 4, 4))[
|
|
89
|
+
:, :desc.Width].copy()
|
|
90
|
+
self.immediatedc.Unmap(cputex, 0)
|
|
91
|
+
return img
|
|
92
|
+
except OSError as e:
|
|
93
|
+
if e.winerror == d3d11.DXGI_ERROR_DEVICE_REMOVED or e.winerror == d3d11.DXGI_ERROR_DEVICE_RESET:
|
|
94
|
+
need_reset_framepool = True
|
|
95
|
+
need_reset_device = True
|
|
96
|
+
else:
|
|
97
|
+
raise e
|
|
98
|
+
finally:
|
|
99
|
+
if tex is not None:
|
|
100
|
+
tex.Release()
|
|
101
|
+
if cputex is not None:
|
|
102
|
+
cputex.Release()
|
|
103
|
+
if need_reset_framepool:
|
|
104
|
+
self.reset_framepool(frame.ContentSize, need_reset_device)
|
|
105
|
+
return self.get_frame()
|
|
102
106
|
|
|
103
107
|
@property
|
|
104
108
|
def hwnd_window(self):
|
|
@@ -139,7 +143,7 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
139
143
|
self.evtoken = item.add_Closed(delegate)
|
|
140
144
|
self.frame_pool = Direct3D11CaptureFramePool.CreateFreeThreaded(self.rtdevice,
|
|
141
145
|
DirectXPixelFormat.B8G8R8A8UIntNormalized,
|
|
142
|
-
|
|
146
|
+
2, item.Size)
|
|
143
147
|
self.session = self.frame_pool.CreateCaptureSession(item)
|
|
144
148
|
pool = self.frame_pool
|
|
145
149
|
pool.add_FrameArrived(
|
|
@@ -193,10 +197,11 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
193
197
|
@override
|
|
194
198
|
def do_get_frame(self):
|
|
195
199
|
if self.start_or_stop():
|
|
196
|
-
frame = self.
|
|
197
|
-
|
|
200
|
+
frame = self.convert_dx_frame()
|
|
201
|
+
if frame is None:
|
|
202
|
+
return
|
|
203
|
+
self.last_dx_frame = None
|
|
198
204
|
latency = time.time() - self.last_frame_time
|
|
199
|
-
self.last_frame_time = time.time()
|
|
200
205
|
|
|
201
206
|
frame = self.crop_image(frame)
|
|
202
207
|
|
|
@@ -209,14 +214,16 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
209
214
|
logger.warning(f"latency too large return None frame: {latency}")
|
|
210
215
|
return None
|
|
211
216
|
else:
|
|
217
|
+
# logger.debug(f'frame latency: {latency}')
|
|
212
218
|
return frame
|
|
213
219
|
|
|
214
220
|
def reset_framepool(self, size, reset_device=False):
|
|
221
|
+
logger.info(f'reset_framepool')
|
|
215
222
|
from ok.rotypes.Windows.Graphics.DirectX import DirectXPixelFormat
|
|
216
223
|
if reset_device:
|
|
217
224
|
self.create_device()
|
|
218
225
|
self.frame_pool.Recreate(self.rtdevice,
|
|
219
|
-
DirectXPixelFormat.B8G8R8A8UIntNormalized,
|
|
226
|
+
DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, size)
|
|
220
227
|
|
|
221
228
|
def crop_image(self, frame):
|
|
222
229
|
if frame is not None:
|
|
@@ -78,8 +78,10 @@ class Config(dict):
|
|
|
78
78
|
|
|
79
79
|
def __setitem__(self, key, value):
|
|
80
80
|
if self.validate(key, value):
|
|
81
|
+
old_value = self.get(key)
|
|
81
82
|
super().__setitem__(key, value)
|
|
82
|
-
|
|
83
|
+
if old_value != value:
|
|
84
|
+
self.save_file()
|
|
83
85
|
|
|
84
86
|
def __getitem__(self, key):
|
|
85
87
|
try:
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import cv2
|
|
6
|
+
from PIL import Image
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def compress_coco(coco_json) -> None:
|
|
10
|
+
coco_folder = os.path.dirname(coco_json)
|
|
11
|
+
|
|
12
|
+
image_dict = {}
|
|
13
|
+
with open(coco_json, 'r') as file:
|
|
14
|
+
data = json.load(file)
|
|
15
|
+
|
|
16
|
+
image_map = {image['id']: image['file_name'] for image in data['images']}
|
|
17
|
+
category_map = {category['id']: category['name'] for category in data['categories']}
|
|
18
|
+
|
|
19
|
+
for annotation in data['annotations']:
|
|
20
|
+
image_id = annotation['image_id']
|
|
21
|
+
category_id = annotation['category_id']
|
|
22
|
+
bbox = annotation['bbox']
|
|
23
|
+
|
|
24
|
+
# Load and scale the image
|
|
25
|
+
image_path = str(os.path.join(coco_folder, image_map[image_id]))
|
|
26
|
+
image = cv2.imread(image_path)
|
|
27
|
+
original_height, original_width = image.shape[:2]
|
|
28
|
+
if image is None:
|
|
29
|
+
print(f'Could not read image {image_path}')
|
|
30
|
+
continue
|
|
31
|
+
x, y, w, h = bbox
|
|
32
|
+
# Crop the image to the bounding box
|
|
33
|
+
image = image[round(y):round(y + h), round(x):round(x + w), :3]
|
|
34
|
+
|
|
35
|
+
image_features = image_dict.get(image_path, [])
|
|
36
|
+
image_features.append((round(x), round(y), image, original_width, original_height))
|
|
37
|
+
image_dict[image_path] = image_features
|
|
38
|
+
|
|
39
|
+
# Loop through the image_dict and write all the image_feature associated with it in a new PNG
|
|
40
|
+
for image_path, features in image_dict.items():
|
|
41
|
+
background = None
|
|
42
|
+
for feature in features:
|
|
43
|
+
x, y, image, original_width, original_height = feature
|
|
44
|
+
# Create a white background
|
|
45
|
+
if not background:
|
|
46
|
+
background = Image.new('RGBA', (original_width, original_height), (255, 255, 255, 255))
|
|
47
|
+
# Convert the OpenCV image (numpy array) to a PIL image
|
|
48
|
+
image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGBA))
|
|
49
|
+
# Paste the image onto the background
|
|
50
|
+
background.paste(image, (x, y), image)
|
|
51
|
+
# Save the image with compression level 9
|
|
52
|
+
background.save(image_path, 'PNG', optimize=True, compress_level=9)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == '__main__':
|
|
56
|
+
json_file = sys.argv[1]
|
|
57
|
+
compress_coco(json_file)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
|
+
import threading
|
|
4
5
|
from typing import Dict
|
|
5
6
|
from typing import List
|
|
6
7
|
|
|
@@ -21,7 +22,7 @@ class FeatureSet:
|
|
|
21
22
|
feature_dict: Dict[str, Feature] = {}
|
|
22
23
|
box_dict: Dict[str, Box] = {}
|
|
23
24
|
|
|
24
|
-
def __init__(self, coco_json: str, default_horizontal_variance=0,
|
|
25
|
+
def __init__(self, debug, coco_json: str, default_horizontal_variance=0,
|
|
25
26
|
default_vertical_variance=0, default_threshold=0.95) -> None:
|
|
26
27
|
"""
|
|
27
28
|
Initialize the FeatureSet by loading images and annotations from a COCO dataset.
|
|
@@ -33,6 +34,7 @@ class FeatureSet:
|
|
|
33
34
|
"""
|
|
34
35
|
self.coco_json = resource_path(coco_json)
|
|
35
36
|
self.coco_folder = os.path.dirname(self.coco_json)
|
|
37
|
+
self.debug = debug
|
|
36
38
|
|
|
37
39
|
logger.debug(f'Loading features from {self.coco_json}')
|
|
38
40
|
|
|
@@ -44,6 +46,7 @@ class FeatureSet:
|
|
|
44
46
|
self.default_threshold = default_threshold
|
|
45
47
|
self.default_horizontal_variance = default_horizontal_variance
|
|
46
48
|
self.default_vertical_variance = default_vertical_variance
|
|
49
|
+
self.lock = threading.Lock()
|
|
47
50
|
|
|
48
51
|
def check_size(self, frame):
|
|
49
52
|
height, width = frame.shape[:2]
|
|
@@ -52,6 +55,8 @@ class FeatureSet:
|
|
|
52
55
|
self.width = width
|
|
53
56
|
self.height = height
|
|
54
57
|
self.process_data()
|
|
58
|
+
elif not self.feature_dict:
|
|
59
|
+
self.process_data()
|
|
55
60
|
|
|
56
61
|
def process_data(self) -> None:
|
|
57
62
|
"""
|
|
@@ -61,49 +66,60 @@ class FeatureSet:
|
|
|
61
66
|
width (int): Target width for scaling images.
|
|
62
67
|
height (int): Target height for scaling images.
|
|
63
68
|
"""
|
|
64
|
-
self.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
69
|
+
with self.lock:
|
|
70
|
+
if self.debug:
|
|
71
|
+
folder_size = sum(os.path.getsize(os.path.join(dirpath, filename))
|
|
72
|
+
for dirpath, dirnames, filenames in os.walk(self.coco_folder)
|
|
73
|
+
for filename in filenames)
|
|
74
|
+
# Convert size to MB
|
|
75
|
+
folder_size_mb = folder_size / (1024 * 1024)
|
|
76
|
+
if folder_size_mb > 5:
|
|
77
|
+
from ok.feature.CompressCoco import compress_coco
|
|
78
|
+
logger.info(f'template folder greater than 5MB try to compress the COCO dataset')
|
|
79
|
+
compress_coco(self.coco_json)
|
|
80
|
+
self.feature_dict.clear()
|
|
81
|
+
self.box_dict.clear()
|
|
82
|
+
with open(self.coco_json, 'r') as file:
|
|
83
|
+
data = json.load(file)
|
|
84
|
+
|
|
85
|
+
# Create a map from image ID to file name
|
|
86
|
+
image_map = {image['id']: image['file_name'] for image in data['images']}
|
|
87
|
+
|
|
88
|
+
# Create a map from category ID to category name
|
|
89
|
+
category_map = {category['id']: category['name'] for category in data['categories']}
|
|
90
|
+
|
|
91
|
+
for annotation in data['annotations']:
|
|
92
|
+
image_id = annotation['image_id']
|
|
93
|
+
category_id = annotation['category_id']
|
|
94
|
+
bbox = annotation['bbox']
|
|
95
|
+
|
|
96
|
+
# Load and scale the image
|
|
97
|
+
image_path = str(os.path.join(self.coco_folder, image_map[image_id]))
|
|
98
|
+
image = cv2.imread(image_path)
|
|
99
|
+
_, original_width = image.shape[:2]
|
|
100
|
+
if image is None:
|
|
101
|
+
logger.error(f'Could not read image {image_path}')
|
|
102
|
+
continue
|
|
103
|
+
x, y, w, h = bbox
|
|
104
|
+
if self.width != image.shape[1] or self.height != image.shape[0]:
|
|
105
|
+
scale_x, scale_y = self.width / image.shape[1], self.height / image.shape[0]
|
|
106
|
+
logger.debug(f'scaling images {scale_x}, {scale_y}')
|
|
107
|
+
image = cv2.resize(image, (self.width, self.height))
|
|
108
|
+
# Calculate the scaled bounding box
|
|
109
|
+
x, y, w, h = x * scale_x, y * scale_y, w * scale_x, h * scale_y
|
|
110
|
+
|
|
111
|
+
# Crop the image to the bounding box
|
|
112
|
+
image = image[round(y):round(y + h), round(x):round(x + w), :3]
|
|
113
|
+
|
|
114
|
+
# Store in featureDict using the category name
|
|
115
|
+
category_name = category_map[category_id]
|
|
116
|
+
logger.debug(
|
|
117
|
+
f"loaded {category_name} resized width {self.width} / original_width:{original_width},scale_x:{self.width / original_width}")
|
|
118
|
+
if category_name in self.feature_dict:
|
|
119
|
+
raise ValueError(f"Multiple boxes found for category {category_name}")
|
|
120
|
+
if not category_name.startswith('box_'):
|
|
121
|
+
self.feature_dict[category_name] = Feature(image, x, y, w, h)
|
|
122
|
+
self.box_dict[category_name] = Box(x, y, w, h, name=category_name)
|
|
107
123
|
|
|
108
124
|
def get_box_by_name(self, mat, category_name: str) -> Box:
|
|
109
125
|
self.check_size(mat)
|
|
@@ -130,7 +146,6 @@ class FeatureSet:
|
|
|
130
146
|
|
|
131
147
|
# Save the image
|
|
132
148
|
cv2.imwrite(file_path, image.mat)
|
|
133
|
-
print(f"Saved {file_path}")
|
|
134
149
|
|
|
135
150
|
def find_one(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
|
|
136
151
|
vertical_variance: float = 0,
|
|
@@ -183,16 +198,16 @@ class FeatureSet:
|
|
|
183
198
|
width = to_x - x
|
|
184
199
|
if height == -1:
|
|
185
200
|
height = to_y - y
|
|
186
|
-
search_x1 =
|
|
187
|
-
search_y1 =
|
|
188
|
-
search_x2 =
|
|
189
|
-
search_y2 =
|
|
201
|
+
search_x1 = round(x * frame_width)
|
|
202
|
+
search_y1 = round(y * frame_height)
|
|
203
|
+
search_x2 = round((x + width) * frame_width)
|
|
204
|
+
search_y2 = round((y + height) * frame_height)
|
|
190
205
|
else:
|
|
191
206
|
# Define search area using variance
|
|
192
|
-
search_x1 = max(0,
|
|
193
|
-
search_y1 = max(0,
|
|
194
|
-
search_x2 = min(self.width,
|
|
195
|
-
search_y2 = min(self.height,
|
|
207
|
+
search_x1 = max(0, round(feature.x - self.width * horizontal_variance))
|
|
208
|
+
search_y1 = max(0, round(feature.y - self.height * vertical_variance))
|
|
209
|
+
search_x2 = min(self.width, round(feature.x + feature_width + self.width * horizontal_variance))
|
|
210
|
+
search_y2 = min(self.height, round(feature.y + feature_height + self.height * vertical_variance))
|
|
196
211
|
|
|
197
212
|
search_area = mat[search_y1:search_y2, search_x1:search_x2, :3]
|
|
198
213
|
# Crop the search area from the image
|
|
@@ -44,9 +44,9 @@ class FindFeature:
|
|
|
44
44
|
return False
|
|
45
45
|
|
|
46
46
|
def find_one(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
|
|
47
|
-
use_gray_scale=False) -> Box:
|
|
47
|
+
use_gray_scale=False, box=None) -> Box:
|
|
48
48
|
boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold,
|
|
49
|
-
use_gray_scale=use_gray_scale)
|
|
49
|
+
use_gray_scale=use_gray_scale, box=box)
|
|
50
50
|
if len(boxes) > 0:
|
|
51
51
|
if len(boxes) > 1:
|
|
52
52
|
print(f"find_one:found {feature_name} too many {len(boxes)}", file=sys.stderr)
|
|
@@ -13,6 +13,7 @@ from ok.gui.Communicate import communicate
|
|
|
13
13
|
from ok.gui.MainWindow import MainWindow
|
|
14
14
|
from ok.gui.MessageWindow import MessageWindow
|
|
15
15
|
from ok.gui.StartController import StartController
|
|
16
|
+
from ok.gui.debug.LogWindow import LogWindow
|
|
16
17
|
from ok.gui.i18n.path import i18n_path
|
|
17
18
|
from ok.gui.overlay.OverlayWindow import OverlayWindow
|
|
18
19
|
from ok.logging.Logger import get_logger
|
|
@@ -47,6 +48,7 @@ class App:
|
|
|
47
48
|
self.loading_window = None
|
|
48
49
|
self.overlay_window = None
|
|
49
50
|
self.main_window = None
|
|
51
|
+
self.log_window = None
|
|
50
52
|
self.exit_event = exit_event
|
|
51
53
|
self.icon = QIcon(self.config.get('gui_icon') or ":/icon/icon.ico")
|
|
52
54
|
if self.config.get('analytics'):
|
|
@@ -109,6 +111,10 @@ class App:
|
|
|
109
111
|
self.main_window.show()
|
|
110
112
|
self.main_window.raise_()
|
|
111
113
|
self.main_window.activateWindow()
|
|
114
|
+
if self.config.get('debug'):
|
|
115
|
+
self.log_window = LogWindow(self.config)
|
|
116
|
+
self.log_window.show()
|
|
117
|
+
logger.debug('showing log_window')
|
|
112
118
|
|
|
113
119
|
def size_relative_to_screen(self, width, height):
|
|
114
120
|
screen = self.app.primaryScreen()
|
|
@@ -43,10 +43,7 @@ class MainWindow(MSFluentWindow):
|
|
|
43
43
|
if self.first_tab is None:
|
|
44
44
|
self.first_tab = self.trigger_tab
|
|
45
45
|
self.addSubInterface(self.trigger_tab, FluentIcon.ROBOT, self.tr('Triggers'))
|
|
46
|
-
|
|
47
|
-
# debug_tab = DebugTab()
|
|
48
|
-
# self.addSubInterface(debug_tab, FluentIcon.COMMAND_PROMPT, self.tr('Debug'))
|
|
49
|
-
# ... Add other tabs similarly
|
|
46
|
+
|
|
50
47
|
self.addSubInterface(self.start_tab, FluentIcon.PLAY, self.tr('Capture'))
|
|
51
48
|
|
|
52
49
|
if debug:
|
|
@@ -77,8 +74,8 @@ class MainWindow(MSFluentWindow):
|
|
|
77
74
|
self.tray.setContextMenu(menu)
|
|
78
75
|
self.tray.show()
|
|
79
76
|
|
|
80
|
-
if ok.gui.device_manager.
|
|
81
|
-
self.switchTo(self.
|
|
77
|
+
if ok.gui.device_manager.config.get("preferred") is None or self.onetime_tab is None:
|
|
78
|
+
self.switchTo(self.start_tab)
|
|
82
79
|
|
|
83
80
|
communicate.capture_error.connect(self.capture_error)
|
|
84
81
|
communicate.notification.connect(self.show_notification)
|
|
@@ -49,9 +49,6 @@ class DebugTab(Tab):
|
|
|
49
49
|
capture_button.clicked.connect(lambda: self.handler.post(self.capture))
|
|
50
50
|
layout.addWidget(capture_button)
|
|
51
51
|
|
|
52
|
-
# self.shortcut = QShortcut(QKeySequence("Ctrl+Alt+S"), self)
|
|
53
|
-
# self.shortcut.activated.connect(lambda: self.handler.post(self.capture))
|
|
54
|
-
|
|
55
52
|
ocr_button = PushButton("OCR")
|
|
56
53
|
ocr_button.clicked.connect(lambda: self.handler.post(self.ocr))
|
|
57
54
|
layout.addWidget(ocr_button)
|