ok-script 0.0.99__tar.gz → 0.0.100__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.99 → ok-script-0.0.100}/PKG-INFO +1 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/OK.py +2 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/DeviceManager.py +0 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +19 -16
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/color/Color.py +33 -2
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/config/Config.py +5 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/CompressCoco.py +20 -15
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/FeatureSet.py +21 -24
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/FindFeature.py +11 -6
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/firebase/Analytics.py +1 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/MainWindow.py +10 -12
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/DebugTab.py +2 -3
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/FrameWidget.py +1 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/StartCard.py +1 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/ocr/OCR.py +3 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/BaseTask.py +3 -3
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/ExecutorOperation.py +29 -7
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/TaskExecutor.py +3 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/json.py +4 -8
- {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/PKG-INFO +1 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/setup.py +1 -1
- {ok-script-0.0.99 → ok-script-0.0.100}/README.md +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/emulator_base.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/emulator_windows.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/platform_base.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/platform_windows.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/alas/utils.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/BaseCaptureMethod.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/HwndWindow.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/ADBCaptureMethod.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/adb/bin/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/image/ImageCaptureMethod.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/image/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/d3d11.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/dump.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/utils.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/capture/windows/window.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/color/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/config/InfoDict.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/config/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/Box.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/Feature.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/feature/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/firebase/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/App.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/Communicate.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/MessageWindow.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/StartController.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/TabTitles.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/AboutTab.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/HttpTextEdit.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/VersionCard.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/about/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/OKIcon.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/config.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/common/style_sheet.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/AspectRatioWidget.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/InfoWidget.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/LogWindow.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/Screenshot.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/debug/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/i18n/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/i18n/path.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/i18n/update.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/icon/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/icon/icon.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/overlay/OverlayWindow.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/overlay/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/qss/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/resources.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/settings/SettingTab.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/settings/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/SelectCaptureListView.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/StartTab.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/start/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ConfigItemFactory.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndDropDown.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndList.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/LabelAndWidget.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ModifyListDialog.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/ModifyListItem.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/StartButton.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TaskCard.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TaskOpButton.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TaskTab.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TooltipTableWidget.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/TriggerTaskTab.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/tasks/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/util/Alert.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/util/InitWorker.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/util/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/Card.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/EmptyCard.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/FramelessDialog.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/ListTableWidgetItem.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/StartLoadingDialog.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/StatusBar.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/Tab.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/TabWidget.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/YesNonWidgetItem.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/gui/widget/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/ADBInteraction.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/BaseInteraction.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/DoNothingInteraction.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/Win32Interaction.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/interaction/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/logging/Logger.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/logging/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/ocr/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/Windows/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/delegate.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/export.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/idldsl.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/inspectable.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/roapi.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/types.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/rotypes/winstring.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/BlackBarProcessor.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/PostProcessor.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/SaveByInterval.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/SaveByKeyPress.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/SaveMethodBase.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/save/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/scene/FeatureScene.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/scene/Scene.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/scene/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/stats/StreamStats.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/stats/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/TriggerTask.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/task/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/GithubMultiDownloader.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/Updater.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/update/gen_md5.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/Handler.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/exit_event.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/list.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/path.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/thread.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/win32_process.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok/util/yaml.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/SOURCES.txt +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/requires.txt +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/ok_script.egg-info/top_level.txt +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/setup.cfg +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/tests/__init__.py +0 -0
- {ok-script-0.0.99 → ok-script-0.0.100}/tests/test_updater.py +0 -0
|
@@ -6,6 +6,7 @@ from typing import Dict, Any
|
|
|
6
6
|
from PySide6.QtWidgets import QApplication
|
|
7
7
|
|
|
8
8
|
import ok
|
|
9
|
+
from ok.config.Config import Config
|
|
9
10
|
from ok.logging.Logger import get_logger, config_logger
|
|
10
11
|
from ok.util.exit_event import ExitEvent
|
|
11
12
|
from ok.util.path import install_path_isascii
|
|
@@ -31,6 +32,7 @@ class OK:
|
|
|
31
32
|
def __init__(self, config: Dict[str, Any]):
|
|
32
33
|
print(f"AutoHelper init, config: {config}")
|
|
33
34
|
config["config_folder"] = config.get("config_folder") or 'configs'
|
|
35
|
+
Config.config_folder = config["config_folder"]
|
|
34
36
|
config_logger(config)
|
|
35
37
|
logger.info(f"AutoHelper init, config: {config}")
|
|
36
38
|
ok.gui.ok = self
|
|
@@ -41,7 +41,6 @@ class DeviceManager:
|
|
|
41
41
|
else:
|
|
42
42
|
self.hwnd = None
|
|
43
43
|
self.config = Config({"preferred": "none", "pc_full_path": "none", 'capture': 'windows'},
|
|
44
|
-
app_config.get('config_folder'),
|
|
45
44
|
"devices")
|
|
46
45
|
self.capture_method = None
|
|
47
46
|
self.handler = Handler(exit_event, 'RefreshAdb')
|
|
@@ -23,17 +23,17 @@ 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
|
-
last_dx_frame = None
|
|
27
|
-
last_frame_time = 0
|
|
28
|
-
frame_pool = None
|
|
29
|
-
item = None
|
|
30
|
-
session = None
|
|
31
|
-
cputex = None
|
|
32
|
-
rtdevice = None
|
|
33
|
-
dxdevice = None
|
|
34
26
|
|
|
35
27
|
def __init__(self, hwnd_window: HwndWindow):
|
|
36
28
|
super().__init__(hwnd_window)
|
|
29
|
+
self.last_frame = None
|
|
30
|
+
self.last_frame_time = 0
|
|
31
|
+
self.frame_pool = None
|
|
32
|
+
self.item = None
|
|
33
|
+
self.session = None
|
|
34
|
+
self.cputex = None
|
|
35
|
+
self.rtdevice = None
|
|
36
|
+
self.dxdevice = None
|
|
37
37
|
self.start_or_stop()
|
|
38
38
|
|
|
39
39
|
def frame_arrived_callback(self, x, y):
|
|
@@ -41,7 +41,7 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
41
41
|
self.last_frame_time = time.time()
|
|
42
42
|
next_frame = self.frame_pool.TryGetNextFrame()
|
|
43
43
|
if next_frame is not None:
|
|
44
|
-
self.
|
|
44
|
+
self.last_frame = self.convert_dx_frame(next_frame)
|
|
45
45
|
else:
|
|
46
46
|
logger.warning('frame_arrived_callback TryGetNextFrame returned None')
|
|
47
47
|
except Exception as e:
|
|
@@ -49,14 +49,10 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
49
49
|
self.close()
|
|
50
50
|
return
|
|
51
51
|
|
|
52
|
-
def convert_dx_frame(self):
|
|
53
|
-
frame = self.last_dx_frame
|
|
52
|
+
def convert_dx_frame(self, frame):
|
|
54
53
|
if not frame:
|
|
55
54
|
# logger.warning('convert_dx_frame self.last_dx_frame is none')
|
|
56
55
|
return None
|
|
57
|
-
start = time.time()
|
|
58
|
-
dx_time = self.last_frame_time
|
|
59
|
-
self.last_dx_frame = None
|
|
60
56
|
need_reset_framepool = False
|
|
61
57
|
if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
|
|
62
58
|
need_reset_framepool = True
|
|
@@ -206,9 +202,16 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
|
|
|
206
202
|
@override
|
|
207
203
|
def do_get_frame(self):
|
|
208
204
|
if self.start_or_stop():
|
|
209
|
-
frame = self.
|
|
205
|
+
frame = self.last_frame
|
|
206
|
+
self.last_frame = None
|
|
210
207
|
if frame is None:
|
|
211
|
-
|
|
208
|
+
if time.time() - self.last_frame_time > 10:
|
|
209
|
+
logger.warning(f'no frame for 10 sec, try to restart')
|
|
210
|
+
self.close()
|
|
211
|
+
self.last_frame_time = time.time()
|
|
212
|
+
return self.do_get_frame()
|
|
213
|
+
else:
|
|
214
|
+
return None
|
|
212
215
|
latency = time.time() - self.last_frame_time
|
|
213
216
|
|
|
214
217
|
frame = self.crop_image(frame)
|
|
@@ -42,6 +42,38 @@ def is_close_to_pure_color(image, max_colors=5000, percent=0.97):
|
|
|
42
42
|
return percentage > percent
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
def keep_pixels_in_color_range(image, color_range):
|
|
46
|
+
lower_bound, upper_bound = color_range_to_bound(color_range)
|
|
47
|
+
mask = cv2.inRange(image, lower_bound, upper_bound)
|
|
48
|
+
|
|
49
|
+
# Apply mask to original image
|
|
50
|
+
result = cv2.bitwise_and(image, image, mask=mask)
|
|
51
|
+
|
|
52
|
+
# Count the number of white pixels in the mask
|
|
53
|
+
pixel_count = np.count_nonzero(mask)
|
|
54
|
+
|
|
55
|
+
return result, pixel_count
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_connected_area_by_color(image, color_range, connectivity=4):
|
|
59
|
+
lower_bound, upper_bound = color_range_to_bound(color_range)
|
|
60
|
+
|
|
61
|
+
# Create mask
|
|
62
|
+
mask = cv2.inRange(image, lower_bound, upper_bound)
|
|
63
|
+
|
|
64
|
+
# Find connected components
|
|
65
|
+
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=connectivity)
|
|
66
|
+
|
|
67
|
+
# Print the area of each connected component
|
|
68
|
+
return num_labels, stats
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def color_range_to_bound(color_range):
|
|
72
|
+
lower_bound = np.array([color_range['b'][0], color_range['g'][0], color_range['r'][0]], dtype="uint8")
|
|
73
|
+
upper_bound = np.array([color_range['b'][1], color_range['g'][1], color_range['r'][1]], dtype="uint8")
|
|
74
|
+
return lower_bound, upper_bound
|
|
75
|
+
|
|
76
|
+
|
|
45
77
|
def calculate_colorfulness(image, box=None):
|
|
46
78
|
if box is not None:
|
|
47
79
|
image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
|
|
@@ -111,8 +143,7 @@ def find_color_rectangles(image, color_range, min_width, min_height, max_width=-
|
|
|
111
143
|
y_offset = 0
|
|
112
144
|
|
|
113
145
|
# Convert color range to BGR format for OpenCV
|
|
114
|
-
lower_bound =
|
|
115
|
-
upper_bound = np.array([color_range['b'][1], color_range['g'][1], color_range['r'][1]], dtype="uint8")
|
|
146
|
+
lower_bound, upper_bound = color_range_to_bound(color_range)
|
|
116
147
|
|
|
117
148
|
# Create a mask for the color range
|
|
118
149
|
mask = cv2.inRange(image, lower_bound, upper_bound)
|
|
@@ -7,7 +7,9 @@ logger = get_logger(__name__)
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Config(dict):
|
|
10
|
-
|
|
10
|
+
config_folder = 'configs'
|
|
11
|
+
|
|
12
|
+
def __init__(self, default, name, folder=None, validator=None):
|
|
11
13
|
"""
|
|
12
14
|
Initialize the Config object.
|
|
13
15
|
|
|
@@ -18,6 +20,8 @@ class Config(dict):
|
|
|
18
20
|
"""
|
|
19
21
|
self.default = default
|
|
20
22
|
self.validator = validator
|
|
23
|
+
if folder is None:
|
|
24
|
+
folder = self.config_folder
|
|
21
25
|
self.config_file = get_path_relative_to_exe(folder, f"{name}.json")
|
|
22
26
|
|
|
23
27
|
# Read the config file, if it exists, otherwise use default
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
-
import sys
|
|
4
3
|
|
|
5
4
|
import cv2
|
|
6
5
|
import numpy as np
|
|
@@ -10,8 +9,8 @@ from PIL.PngImagePlugin import PngInfo
|
|
|
10
9
|
from ok.feature.FeatureSet import read_from_json
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
def compress_coco(coco_json
|
|
14
|
-
feature_dict, *_ = read_from_json(coco_json
|
|
12
|
+
def compress_coco(coco_json) -> None:
|
|
13
|
+
feature_dict, *_ = read_from_json(coco_json)
|
|
15
14
|
with open(coco_json, 'r') as file:
|
|
16
15
|
image_dict = {}
|
|
17
16
|
data = json.load(file)
|
|
@@ -46,14 +45,22 @@ def compress_coco(coco_json, canny_upper, canny_lower) -> None:
|
|
|
46
45
|
h, w = feature.mat.shape[:2]
|
|
47
46
|
background[y:y + h, x:x + w] = feature.mat
|
|
48
47
|
|
|
49
|
-
# Add metadata
|
|
50
|
-
metadata = {
|
|
51
|
-
"ok_compressed": "1"
|
|
52
|
-
}
|
|
53
|
-
|
|
54
48
|
# Save the image with metadata
|
|
55
49
|
save_image_with_metadata(background, image_path)
|
|
56
50
|
|
|
51
|
+
replaced = False
|
|
52
|
+
for image in data['images']:
|
|
53
|
+
image['file_name'], replaced = replace_extension(image['file_name'])
|
|
54
|
+
|
|
55
|
+
if replaced:
|
|
56
|
+
with open(coco_json, 'w') as json_file:
|
|
57
|
+
json.dump(data, json_file, indent=4)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def replace_extension(filename):
|
|
61
|
+
if filename.endswith('.jpg'):
|
|
62
|
+
return filename[:-4] + '.png', True
|
|
63
|
+
|
|
57
64
|
|
|
58
65
|
def save_image_with_metadata(image, image_path):
|
|
59
66
|
# Convert OpenCV image (numpy array) to PIL Image
|
|
@@ -65,11 +72,9 @@ def save_image_with_metadata(image, image_path):
|
|
|
65
72
|
metadata.add_text('ok_compressed', '1')
|
|
66
73
|
metadata.add_text("Author", "ok_compress")
|
|
67
74
|
metadata.add_text("Description", "This is a sample image")
|
|
68
|
-
|
|
75
|
+
new_path, replaced = replace_extension(image_path)
|
|
76
|
+
if replaced:
|
|
77
|
+
os.remove(image_path)
|
|
69
78
|
# Save the image with metadata
|
|
70
|
-
pil_image.save(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if __name__ == '__main__':
|
|
74
|
-
json_file = sys.argv[1]
|
|
75
|
-
compress_coco(json_file)
|
|
79
|
+
pil_image.save(new_path, 'PNG', optimize=True, pnginfo=metadata)
|
|
80
|
+
return image_path
|
|
@@ -41,8 +41,6 @@ class FeatureSet:
|
|
|
41
41
|
# Process images and annotations
|
|
42
42
|
self.width = 0
|
|
43
43
|
self.height = 0
|
|
44
|
-
self.canny_lower = 50
|
|
45
|
-
self.canny_higher = 150
|
|
46
44
|
if default_threshold == 0:
|
|
47
45
|
default_threshold = 0.95
|
|
48
46
|
self.default_threshold = default_threshold
|
|
@@ -69,14 +67,12 @@ class FeatureSet:
|
|
|
69
67
|
width (int): Target width for scaling images.
|
|
70
68
|
height (int): Target height for scaling images.
|
|
71
69
|
"""
|
|
72
|
-
self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height
|
|
73
|
-
self.canny_lower, self.canny_higher)
|
|
70
|
+
self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height)
|
|
74
71
|
if self.debug and not compressed:
|
|
75
72
|
from ok.feature.CompressCoco import compress_coco
|
|
76
73
|
logger.info(f'coco not compressed try to compress the COCO dataset')
|
|
77
|
-
compress_coco(self.coco_json
|
|
78
|
-
self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height
|
|
79
|
-
self.canny_lower, self.canny_higher)
|
|
74
|
+
compress_coco(self.coco_json)
|
|
75
|
+
self.feature_dict, self.box_dict, compressed = read_from_json(self.coco_json, self.width, self.height)
|
|
80
76
|
|
|
81
77
|
def get_box_by_name(self, mat, category_name: str) -> Box:
|
|
82
78
|
self.check_size(mat)
|
|
@@ -106,10 +102,10 @@ class FeatureSet:
|
|
|
106
102
|
|
|
107
103
|
def find_one(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
|
|
108
104
|
vertical_variance: float = 0,
|
|
109
|
-
threshold=0, use_gray_scale=False) -> Box:
|
|
105
|
+
threshold=0, use_gray_scale=False, canny_lower=0, canny_higher=0) -> Box:
|
|
110
106
|
boxes = self.find_feature(mat, category_name, horizontal_variance=horizontal_variance,
|
|
111
107
|
vertical_variance=vertical_variance, threshold=threshold,
|
|
112
|
-
use_gray_scale=use_gray_scale)
|
|
108
|
+
use_gray_scale=use_gray_scale, canny_lower=canny_lower, canny_higher=canny_higher)
|
|
113
109
|
if len(boxes) > 1:
|
|
114
110
|
logger.warning(f"find_one:found too many {len(boxes)} return first", file=sys.stderr)
|
|
115
111
|
if len(boxes) >= 1:
|
|
@@ -117,7 +113,7 @@ class FeatureSet:
|
|
|
117
113
|
|
|
118
114
|
def find_feature(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
|
|
119
115
|
vertical_variance: float = 0, threshold: float = 0, use_gray_scale: bool = False, x=-1, y=-1,
|
|
120
|
-
to_x=-1, to_y=-1, width=-1, height=-1, box=None) -> List[Box]:
|
|
116
|
+
to_x=-1, to_y=-1, width=-1, height=-1, box=None, canny_lower=0, canny_higher=0) -> List[Box]:
|
|
121
117
|
"""
|
|
122
118
|
Find a feature within a given variance.
|
|
123
119
|
|
|
@@ -168,17 +164,19 @@ class FeatureSet:
|
|
|
168
164
|
|
|
169
165
|
search_area = mat[search_y1:search_y2, search_x1:search_x2, :3]
|
|
170
166
|
# Crop the search area from the image
|
|
171
|
-
|
|
167
|
+
|
|
172
168
|
if use_gray_scale:
|
|
173
169
|
search_area = cv2.cvtColor(search_area, cv2.COLOR_BGR2GRAY)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
search_area = cv2.Canny(search_area, self.canny_lower, self.canny_higher)
|
|
178
|
-
elif category_name.startswith('gray_'):
|
|
170
|
+
if len(feature.mat.shape) != 2:
|
|
171
|
+
feature.mat = cv2.cvtColor(feature.mat, cv2.COLOR_BGR2GRAY)
|
|
172
|
+
if canny_lower != 0 and canny_higher != 0:
|
|
179
173
|
search_area = cv2.cvtColor(search_area, cv2.COLOR_BGR2GRAY)
|
|
174
|
+
search_area = cv2.Canny(search_area, canny_lower, canny_higher)
|
|
175
|
+
if len(feature.mat.shape) != 2:
|
|
176
|
+
feature.mat = cv2.cvtColor(feature.mat, cv2.COLOR_BGR2GRAY)
|
|
177
|
+
feature.mat = cv2.Canny(feature.mat, canny_lower, canny_higher)
|
|
180
178
|
|
|
181
|
-
result = cv2.matchTemplate(search_area,
|
|
179
|
+
result = cv2.matchTemplate(search_area, feature.mat, cv2.TM_CCOEFF_NORMED)
|
|
182
180
|
|
|
183
181
|
# Define a threshold for acceptable matches
|
|
184
182
|
locations = filter_and_sort_matches(result, threshold, feature_width, feature_height)
|
|
@@ -198,7 +196,7 @@ class FeatureSet:
|
|
|
198
196
|
return result
|
|
199
197
|
|
|
200
198
|
|
|
201
|
-
def read_from_json(coco_json, width=-1, height=-1
|
|
199
|
+
def read_from_json(coco_json, width=-1, height=-1):
|
|
202
200
|
feature_dict = {}
|
|
203
201
|
box_dict = {}
|
|
204
202
|
ok_compressed = None
|
|
@@ -255,18 +253,17 @@ def read_from_json(coco_json, width=-1, height=-1, canny_lower=50, canny_upper=1
|
|
|
255
253
|
if category_name in feature_dict:
|
|
256
254
|
raise ValueError(f"Multiple boxes found for category {category_name}")
|
|
257
255
|
if not category_name.startswith('box_'):
|
|
258
|
-
if ok_compressed:
|
|
259
|
-
if category_name.startswith('edge_'):
|
|
260
|
-
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
261
|
-
image = cv2.Canny(image, canny_lower, canny_upper)
|
|
262
|
-
elif category_name.startswith('gray_'):
|
|
263
|
-
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
264
256
|
feature_dict[category_name] = Feature(image, x, y)
|
|
265
257
|
box_dict[category_name] = Box(x, y, image.shape[1], image.shape[0], name=category_name)
|
|
266
258
|
|
|
267
259
|
return feature_dict, box_dict, ok_compressed
|
|
268
260
|
|
|
269
261
|
|
|
262
|
+
def replace_extension(filename):
|
|
263
|
+
if filename.endswith('.jpg'):
|
|
264
|
+
return filename[:-4] + '.png', True
|
|
265
|
+
|
|
266
|
+
|
|
270
267
|
def filter_and_sort_matches(result, threshold, w, h):
|
|
271
268
|
# Find all matches above the confidence threshold
|
|
272
269
|
loc = np.where(result >= threshold)
|
|
@@ -11,9 +11,11 @@ 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, box=None
|
|
14
|
+
use_gray_scale=False, x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1, box=None, canny_lower=0,
|
|
15
|
+
canny_higher=0) -> List[Box]:
|
|
15
16
|
return self.feature_set.find_feature(self.executor.frame, feature_name, horizontal_variance, vertical_variance,
|
|
16
|
-
threshold, use_gray_scale, x, y, to_x, to_y, width, height, box=box
|
|
17
|
+
threshold, use_gray_scale, x, y, to_x, to_y, width, height, box=box,
|
|
18
|
+
canny_lower=canny_lower, canny_higher=canny_higher)
|
|
17
19
|
|
|
18
20
|
def get_box_by_name(self, name):
|
|
19
21
|
return self.feature_set.get_box_by_name(self.executor.frame, name)
|
|
@@ -43,9 +45,11 @@ class FindFeature:
|
|
|
43
45
|
|
|
44
46
|
def wait_click_feature(self, feature, horizontal_variance=0, vertical_variance=0, threshold=0, relative_x=0.5,
|
|
45
47
|
relative_y=0.5,
|
|
46
|
-
time_out=0, pre_action=None, post_action=None, box=None, raise_if_not_found=True
|
|
48
|
+
time_out=0, pre_action=None, post_action=None, box=None, raise_if_not_found=True,
|
|
49
|
+
use_gray_scale=False, canny_lower=0, canny_higher=0):
|
|
47
50
|
box = self.wait_until(
|
|
48
|
-
lambda: self.find_one(feature, horizontal_variance, vertical_variance, threshold, box=box
|
|
51
|
+
lambda: self.find_one(feature, horizontal_variance, vertical_variance, threshold, box=box,
|
|
52
|
+
use_gray_scale=use_gray_scale, canny_lower=canny_lower, canny_higher=canny_higher),
|
|
49
53
|
time_out,
|
|
50
54
|
pre_action,
|
|
51
55
|
post_action, raise_if_not_found)
|
|
@@ -55,9 +59,10 @@ class FindFeature:
|
|
|
55
59
|
return False
|
|
56
60
|
|
|
57
61
|
def find_one(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
|
|
58
|
-
use_gray_scale=False, box=None) -> Box:
|
|
62
|
+
use_gray_scale=False, box=None, canny_lower=0, canny_higher=0) -> Box:
|
|
59
63
|
boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold,
|
|
60
|
-
use_gray_scale=use_gray_scale, box=box
|
|
64
|
+
use_gray_scale=use_gray_scale, box=box, canny_lower=canny_lower,
|
|
65
|
+
canny_higher=canny_higher)
|
|
61
66
|
if len(boxes) > 0:
|
|
62
67
|
if len(boxes) > 1:
|
|
63
68
|
print(f"find_one:found {feature_name} too many {len(boxes)}", file=sys.stderr)
|
|
@@ -83,7 +83,7 @@ class Analytics:
|
|
|
83
83
|
@property
|
|
84
84
|
def client_id(self):
|
|
85
85
|
if self._config is None:
|
|
86
|
-
self._config = Config({'client_id': ''},
|
|
86
|
+
self._config = Config({'client_id': ''}, 'statistics')
|
|
87
87
|
if not self._config.get('client_id'):
|
|
88
88
|
self._config['client_id'] = self.get_unique_client_id()
|
|
89
89
|
else:
|
|
@@ -25,26 +25,26 @@ class Communicate(QObject):
|
|
|
25
25
|
class MainWindow(MSFluentWindow):
|
|
26
26
|
def __init__(self, config, icon, title, version, debug=False, about=None, exit_event=None):
|
|
27
27
|
super().__init__()
|
|
28
|
+
logger.info('main window __init__')
|
|
28
29
|
self.original_layout = None
|
|
29
30
|
self.exit_event = exit_event
|
|
30
31
|
self.start_tab = StartTab()
|
|
31
|
-
self.first_tab = None
|
|
32
32
|
self.onetime_tab = None
|
|
33
33
|
self.trigger_tab = None
|
|
34
34
|
self.emulator_starting_dialog = None
|
|
35
35
|
|
|
36
|
+
self.addSubInterface(self.start_tab, FluentIcon.PLAY, self.tr('Capture'))
|
|
37
|
+
|
|
36
38
|
if len(ok.gui.executor.onetime_tasks) > 0:
|
|
37
39
|
self.onetime_tab = OneTimeTaskTab()
|
|
38
|
-
self.
|
|
40
|
+
self.first_task_tab = self.onetime_tab
|
|
39
41
|
self.addSubInterface(self.onetime_tab, FluentIcon.BOOK_SHELF, self.tr('Tasks'))
|
|
40
42
|
if len(ok.gui.executor.trigger_tasks) > 0:
|
|
41
43
|
self.trigger_tab = TriggerTaskTab()
|
|
42
|
-
if self.
|
|
43
|
-
self.
|
|
44
|
+
if self.first_task_tab is None:
|
|
45
|
+
self.first_task_tab = self.trigger_tab
|
|
44
46
|
self.addSubInterface(self.trigger_tab, FluentIcon.ROBOT, self.tr('Triggers'))
|
|
45
47
|
|
|
46
|
-
self.addSubInterface(self.start_tab, FluentIcon.PLAY, self.tr('Capture'))
|
|
47
|
-
|
|
48
48
|
if debug:
|
|
49
49
|
debug_tab = DebugTab(config, exit_event)
|
|
50
50
|
self.addSubInterface(debug_tab, FluentIcon.DEVELOPER_TOOLS, self.tr('Debug'),
|
|
@@ -73,13 +73,14 @@ class MainWindow(MSFluentWindow):
|
|
|
73
73
|
self.tray.setContextMenu(menu)
|
|
74
74
|
self.tray.show()
|
|
75
75
|
|
|
76
|
-
if ok.gui.device_manager.config.get("preferred") is None or self.onetime_tab is None:
|
|
77
|
-
|
|
76
|
+
# if ok.gui.device_manager.config.get("preferred") is None or self.onetime_tab is None:
|
|
77
|
+
# self.switchTo(self.start_tab)
|
|
78
78
|
|
|
79
79
|
communicate.capture_error.connect(self.capture_error)
|
|
80
80
|
communicate.notification.connect(self.show_notification)
|
|
81
81
|
communicate.config_validation.connect(self.config_validation)
|
|
82
82
|
communicate.starting_emulator.connect(self.starting_emulator)
|
|
83
|
+
logger.info('main window __init__ done')
|
|
83
84
|
|
|
84
85
|
def starting_emulator(self, done, error, seconds_left):
|
|
85
86
|
if error:
|
|
@@ -92,7 +93,6 @@ class MainWindow(MSFluentWindow):
|
|
|
92
93
|
if self.emulator_starting_dialog is None:
|
|
93
94
|
self.emulator_starting_dialog = StartLoadingDialog(seconds_left,
|
|
94
95
|
self)
|
|
95
|
-
|
|
96
96
|
else:
|
|
97
97
|
self.emulator_starting_dialog.set_seconds_left(seconds_left)
|
|
98
98
|
self.emulator_starting_dialog.show()
|
|
@@ -133,9 +133,7 @@ class MainWindow(MSFluentWindow):
|
|
|
133
133
|
def navigate_tab(self, index):
|
|
134
134
|
if index == "start":
|
|
135
135
|
self.switchTo(self.start_tab)
|
|
136
|
-
elif index == "
|
|
137
|
-
self.switchTo(self.first_tab)
|
|
138
|
-
elif index == "first" and self.onetime_tab is not None:
|
|
136
|
+
elif index == "onetime" and self.onetime_tab is not None:
|
|
139
137
|
self.switchTo(self.onetime_tab)
|
|
140
138
|
elif index == "trigger" and self.trigger_tab is not None:
|
|
141
139
|
self.switchTo(self.trigger_tab)
|
|
@@ -28,10 +28,9 @@ class DebugTab(Tab):
|
|
|
28
28
|
super().__init__()
|
|
29
29
|
|
|
30
30
|
self.config = Config({'target_task': "", 'target_images': [], 'target_function': ""},
|
|
31
|
-
|
|
31
|
+
'debug')
|
|
32
32
|
self.log_window_config = Config({'width': 800, 'height': 300, 'x': 0, 'y': 0, 'keyword': '',
|
|
33
|
-
'level': 'ALL', 'show': True},
|
|
34
|
-
app_config.get('config_folder'), 'log_window')
|
|
33
|
+
'level': 'ALL', 'show': True}, 'log_window')
|
|
35
34
|
tool_widget = QWidget()
|
|
36
35
|
layout = FlowLayout(tool_widget, False)
|
|
37
36
|
|
|
@@ -33,7 +33,7 @@ class FrameWidget(QWidget):
|
|
|
33
33
|
relative = self.mapFromGlobal(QPoint(x / self.scaling, y / self.scaling))
|
|
34
34
|
if self._mouse_position != relative and relative.x() > 0 and relative.y() > 0:
|
|
35
35
|
self._mouse_position = relative
|
|
36
|
-
|
|
36
|
+
self.update()
|
|
37
37
|
except Exception as e:
|
|
38
38
|
logger.warning(f'GetCursorPos exception {e}')
|
|
39
39
|
|
|
@@ -18,7 +18,7 @@ class OCR:
|
|
|
18
18
|
def ocr(self, x=0, y=0, to_x=1, to_y=1, match: str | List[str] | Pattern[str] | List[Pattern[str]] | None = None,
|
|
19
19
|
width=0, height=0, box: Box = None, name=None,
|
|
20
20
|
threshold=0,
|
|
21
|
-
frame=None, target_height=0):
|
|
21
|
+
frame=None, target_height=0, use_grayscale=False):
|
|
22
22
|
if hasattr(self, 'paused') and self.paused:
|
|
23
23
|
self.sleep(1)
|
|
24
24
|
if threshold == 0:
|
|
@@ -42,6 +42,8 @@ class OCR:
|
|
|
42
42
|
image = image[y:y + h, x:x + w]
|
|
43
43
|
if not box.name and match:
|
|
44
44
|
box.name = str(match)
|
|
45
|
+
if use_grayscale:
|
|
46
|
+
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
45
47
|
|
|
46
48
|
image, scale_factor = resize_image(image, original_height, target_height)
|
|
47
49
|
|
|
@@ -136,8 +136,8 @@ class BaseTask(ExecutorOperation):
|
|
|
136
136
|
def info_add(self, key, count=1):
|
|
137
137
|
self.info[key] = self.info.get(key, 0) + count
|
|
138
138
|
|
|
139
|
-
def load_config(self
|
|
140
|
-
self.config = Config(self.default_config,
|
|
139
|
+
def load_config(self):
|
|
140
|
+
self.config = Config(self.default_config, self.__class__.__name__, validator=self.validate)
|
|
141
141
|
|
|
142
142
|
def validate(self, key, value):
|
|
143
143
|
message = self.validate_config(key, value)
|
|
@@ -168,5 +168,5 @@ class BaseTask(ExecutorOperation):
|
|
|
168
168
|
def set_executor(self, executor):
|
|
169
169
|
self.executor = executor
|
|
170
170
|
self.feature_set = executor.feature_set
|
|
171
|
-
self.load_config(
|
|
171
|
+
self.load_config()
|
|
172
172
|
self.on_create()
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import time
|
|
1
2
|
from typing import List
|
|
2
3
|
|
|
3
4
|
from ok.color.Color import calculate_color_percentage
|
|
@@ -7,6 +8,7 @@ from ok.gui.Communicate import communicate
|
|
|
7
8
|
|
|
8
9
|
class ExecutorOperation:
|
|
9
10
|
executor = None
|
|
11
|
+
last_click_time = 0
|
|
10
12
|
|
|
11
13
|
def exit_is_set(self):
|
|
12
14
|
return self.executor.exit_event.is_set()
|
|
@@ -32,13 +34,29 @@ class ExecutorOperation:
|
|
|
32
34
|
def is_scene(self, the_scene):
|
|
33
35
|
return isinstance(self.executor.current_scene, the_scene)
|
|
34
36
|
|
|
35
|
-
def
|
|
37
|
+
def reset_scene(self):
|
|
38
|
+
self.executor.reset_scene()
|
|
39
|
+
|
|
40
|
+
def click(self, x: int | Box = -1, y=-1, move_back=False, name=None, interval=-1):
|
|
36
41
|
if isinstance(x, Box):
|
|
37
|
-
self.click_box(x, move_back=move_back)
|
|
38
|
-
|
|
42
|
+
return self.click_box(x, move_back=move_back)
|
|
43
|
+
if not self.check_interval(interval):
|
|
44
|
+
self.executor.reset_scene()
|
|
45
|
+
return False
|
|
39
46
|
communicate.emit_draw_box("click", [Box(max(0, x - 10), max(0, y - 10), 20, 20, name="click")], "green")
|
|
40
47
|
self.executor.reset_scene()
|
|
41
48
|
self.executor.interaction.click(x, y, move_back, name=name)
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
def check_interval(self, interval):
|
|
52
|
+
if interval <= 0:
|
|
53
|
+
return True
|
|
54
|
+
now = time.time()
|
|
55
|
+
if now - self.last_click_time < interval:
|
|
56
|
+
return False
|
|
57
|
+
else:
|
|
58
|
+
self.last_click_time = now
|
|
59
|
+
return True
|
|
42
60
|
|
|
43
61
|
def mouse_down(self, x=-1, y=-1, name=None):
|
|
44
62
|
frame = self.executor.nullable_frame()
|
|
@@ -52,8 +70,8 @@ class ExecutorOperation:
|
|
|
52
70
|
communicate.emit_draw_box("mouse_up", self.box_of_screen(0.5, 0.5, width=0.01, height=0.01, name="click"),
|
|
53
71
|
"green",
|
|
54
72
|
frame)
|
|
55
|
-
self.executor.reset_scene()
|
|
56
73
|
self.executor.interaction.mouse_up()
|
|
74
|
+
self.executor.reset_scene()
|
|
57
75
|
|
|
58
76
|
def right_click(self, x=-1, y=-1, move_back=False, name=None):
|
|
59
77
|
communicate.emit_draw_box("right_click", [Box(max(0, x - 10), max(0, y - 10), 20, 20, name="right_click")],
|
|
@@ -75,8 +93,8 @@ class ExecutorOperation:
|
|
|
75
93
|
self.executor.interaction.swipe(from_x, from_y, to_x, to_y, ms)
|
|
76
94
|
self.sleep(duration)
|
|
77
95
|
|
|
78
|
-
def screenshot(self, name=None):
|
|
79
|
-
communicate.screenshot.emit(self.frame, name)
|
|
96
|
+
def screenshot(self, name=None, frame=None):
|
|
97
|
+
communicate.screenshot.emit(self.frame if frame is None else frame, name)
|
|
80
98
|
|
|
81
99
|
def click_box_if_name_match(self, boxes, names, relative_x=0.5, relative_y=0.5):
|
|
82
100
|
"""
|
|
@@ -158,12 +176,16 @@ class ExecutorOperation:
|
|
|
158
176
|
def sleep(self, timeout):
|
|
159
177
|
self.executor.sleep(timeout)
|
|
160
178
|
|
|
161
|
-
def send_key(self, key, down_time=0.02):
|
|
179
|
+
def send_key(self, key, down_time=0.02, interval=-1):
|
|
180
|
+
if not self.check_interval(interval):
|
|
181
|
+
self.executor.reset_scene()
|
|
182
|
+
return False
|
|
162
183
|
frame = self.executor.nullable_frame()
|
|
163
184
|
communicate.emit_draw_box("send_key", [Box(max(0, 0), max(0, 0), 20, 20, name="send_key_" + str(key))], "green",
|
|
164
185
|
frame)
|
|
165
186
|
self.executor.reset_scene()
|
|
166
187
|
self.executor.interaction.send_key(key, down_time)
|
|
188
|
+
return True
|
|
167
189
|
|
|
168
190
|
def send_key_down(self, key):
|
|
169
191
|
self.executor.reset_scene()
|
|
@@ -257,8 +257,10 @@ class TaskExecutor:
|
|
|
257
257
|
|
|
258
258
|
def execute(self):
|
|
259
259
|
logger.info(f"start execute")
|
|
260
|
-
last_frame_time = 0
|
|
261
260
|
while not self.exit_event.is_set():
|
|
261
|
+
if self.paused:
|
|
262
|
+
logger.info(f'executor is paused sleep')
|
|
263
|
+
self.sleep(1)
|
|
262
264
|
task, cycled = self.next_task()
|
|
263
265
|
if not task:
|
|
264
266
|
time.sleep(1)
|
|
@@ -17,11 +17,7 @@ def read_json_file(file_path) -> dict | None:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def write_json_file(file_path, data):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return True
|
|
25
|
-
except Exception as e:
|
|
26
|
-
print(f"Error writing to JSON file: {e}")
|
|
27
|
-
return False
|
|
20
|
+
ensure_dir_for_file(file_path)
|
|
21
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
22
|
+
json.dump(data, f, indent=4, ensure_ascii=False)
|
|
23
|
+
return True
|