feat(core): 调试保存图片去重 & 默认不允许重复初始化 Context
This commit is contained in:
parent
0519f46c7d
commit
7cc551e6d6
|
@ -45,7 +45,9 @@
|
|||
"-s",
|
||||
"${workspaceFolder}/dumps",
|
||||
"-c",
|
||||
"kotonebot.run.run"
|
||||
"kotonebot.run.run",
|
||||
"-t",
|
||||
"kotonebot.tasks.common.BaseConfig"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue