feat(core): 调试保存图片去重 & 默认不允许重复初始化 Context

This commit is contained in:
XcantloadX 2025-01-22 20:33:19 +08:00
parent 0519f46c7d
commit 7cc551e6d6
5 changed files with 93 additions and 20 deletions

4
.vscode/launch.json vendored
View File

@ -45,7 +45,9 @@
"-s",
"${workspaceFolder}/dumps",
"-c",
"kotonebot.run.run"
"kotonebot.run.run",
"-t",
"kotonebot.tasks.common.BaseConfig"
]
}
]

44
experiments/hash_image.py Normal file
View File

@ -0,0 +1,44 @@
import cv2
import time
import hashlib
import numpy as np
def test_image_hash_time(iterations):
# 创建一个1920x1080的随机图像
img = np.random.randint(0, 256, (1080, 1920, 3), dtype=np.uint8)
total_time = 0
for i in range(iterations):
start_time = time.time()
# 计算图像的MD5
md5_hash = hashlib.md5(img.tobytes()).hexdigest()
end_time = time.time()
total_time += (end_time - start_time)
avg_time = total_time / iterations
print(f"平均计算时间: {avg_time:.6f}")
print(f"最后一次计算的MD5值: {md5_hash}")
def test_uuid_time(iterations):
import uuid
total_time = 0
for i in range(iterations):
start_time = time.time()
# 生成 UUID
uuid_str = str(uuid.uuid4())
end_time = time.time()
total_time += (end_time - start_time)
avg_time = total_time / iterations
print(f"平均生成UUID时间: {avg_time:.6f}")
print(f"最后一次生成的UUID: {uuid_str}")
if __name__ == "__main__":
test_image_hash_time(1000)
test_uuid_time(1000)

View File

@ -553,7 +553,9 @@ config: ContextConfig = cast(ContextConfig, Forwarded(name="config"))
"""配置数据。"""
def init_context(
config_type: Type[T] = dict[str, Any]
*,
config_type: Type[T] = dict[str, Any],
force: bool = False
):
"""
初始化 Context 模块
@ -561,8 +563,13 @@ def init_context(
:param config_type:
配置数据类类型配置数据类必须继承自 pydantic `BaseModel`
默认为 `dict[str, Any]`即普通的 JSON 数据不包含任何类型信息
:param force:
是否强制重新初始化
若为 `True`则忽略已存在的 Context 实例并重新创建一个新的实例
"""
global _c, device, ocr, image, color, vars, debug, config
if _c is not None and not force:
return
_c = Context(config_type=config_type)
device._FORWARD_getter = lambda: _c.device # type: ignore
ocr._FORWARD_getter = lambda: _c.ocr # type: ignore

View File

@ -52,12 +52,12 @@ if __name__ == "__main__":
# 设置保存路径
if args.save:
save_path = Path(args.save)
debug.save_to_folder = str(save_path)
debug.auto_save_to_folder = str(save_path)
if not os.path.exists(save_path):
os.makedirs(save_path)
if args.clear:
if debug.save_to_folder:
shutil.rmtree(debug.save_to_folder)
if debug.auto_save_to_folder:
shutil.rmtree(debug.auto_save_to_folder)
# 初始化上下文
module_name, class_name = args.config_type.rsplit('.', 1)

View File

@ -4,6 +4,7 @@ import json
import time
import uuid
import psutil
import hashlib
import traceback
from pathlib import Path
from datetime import datetime
@ -23,23 +24,36 @@ class _Vars:
"""调试变量类"""
enabled: bool = False
"""是否启用调试结果显示。"""
max_results: int = -1
"""最多保存的结果数量。-1 表示不限制。"""
wait_for_message_sent: bool = False
"""
是否等待消息发送完成才继续后续代码
启用此选项可能会降低运行速度
默认禁用启用此选项会显著降低运行速度
"""
hide_server_log: bool = True
"""是否隐藏服务器日志。"""
save_to_folder: str | None = None
auto_save_to_folder: str | None = None
"""
是否将结果保存到指定文件夹
是否将结果自动保存到指定文件夹
如果为 None则不保存
"""
hash_image: bool = True
"""
是否使用图片的 MD5 值作为图片的唯一标识
若禁用则使用随机 UUID 作为图片的唯一标识
可能会导致保存大量重复图片
此选项默认启用启用此选项会轻微降低调试时运行速度
"""
debug = _Vars()
# TODO: 需要考虑释放内存的问题。释放哪些比较合适?
@ -50,13 +64,19 @@ _result_file: TextIO | None = None
def _save_image(image: MatLike) -> str:
"""缓存图片数据到 _images 字典中。返回 key。"""
key = str(uuid.uuid4())
_images[key] = image
if debug.save_to_folder:
if not os.path.exists(debug.save_to_folder):
os.makedirs(debug.save_to_folder)
file_name = f"{key}.png"
cv2.imwrite(os.path.join(debug.save_to_folder, file_name), image)
# 计算 key
if debug.hash_image:
key = hashlib.md5(image.tobytes()).hexdigest()
else:
key = str(uuid.uuid4())
# 保存图片
if key not in _images:
_images[key] = image
if debug.auto_save_to_folder:
if not os.path.exists(debug.auto_save_to_folder):
os.makedirs(debug.auto_save_to_folder)
file_name = f"{key}.png"
cv2.imwrite(os.path.join(debug.auto_save_to_folder, file_name), image)
return key
def _save_images(images: list[MatLike]) -> list[str]:
@ -72,7 +92,7 @@ def img(image: str | MatLike | None) -> str:
"""
if image is None:
return 'None'
if debug.save_to_folder:
if debug.auto_save_to_folder:
if isinstance(image, str):
image = cv2.imread(image)
key = _save_image(image)
@ -219,12 +239,12 @@ def result(
# 保存到文件
# TODO: 把这个类型转换为 dataclass/namedtuple
if debug.save_to_folder:
if debug.auto_save_to_folder:
if _result_file is None:
if not os.path.exists(debug.save_to_folder):
os.makedirs(debug.save_to_folder)
if not os.path.exists(debug.auto_save_to_folder):
os.makedirs(debug.auto_save_to_folder)
log_file_name = f"dump_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.json"
_result_file = open(os.path.join(debug.save_to_folder, log_file_name), "w")
_result_file = open(os.path.join(debug.auto_save_to_folder, log_file_name), "w")
_result_file.write(json.dumps({
"image": {
"type": "memory",