恢复使用图像识别仓库物品
Some checks failed
ci/woodpecker/push/check_format Pipeline failed

This commit is contained in:
fuyn101 2024-09-30 17:49:16 +08:00
parent 34852d29ab
commit 48922db0da
4 changed files with 148 additions and 19 deletions

View file

@ -441,7 +441,7 @@ class Arknights数据处理器:
def 批量训练并保存扫仓库模型(self):
self.训练仓库的knn模型("NORMAL", "./mower/models/NORMAL.pkl")
self.训练仓库的knn模型("CONSUME", "./mower/models/CONSUME.pkl")
# self.训练仓库的knn模型("MATERIAL", "./mower/models/MATERIAL.pkl")
self.训练仓库的knn模型("MATERIAL", "./mower/models/MATERIAL.pkl")
def 训练在房间内的干员名的模型(self):
font = ImageFont.truetype("mower/fonts/SourceHanSansCN-Medium.otf", 37)

View file

@ -10,7 +10,8 @@ from typing import Literal
from mower.data import agent_list, base_room_list
from mower.solvers.credit import CreditSolver
from mower.solvers.credit_fight import CreditFight
from mower.solvers.cultivate_depot import cultivate as cultivateDepotSolver
# from mower.solvers.cultivate_depot import cultivate as cultivateDepotSolver
from mower.solvers.depotREC import depotREC as DepotSolver
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.clue import ClueSolver
@ -2866,7 +2867,7 @@ class BaseSchedulerSolver(SceneGraphSolver, BaseMixin):
def 仓库扫描(self):
try:
cultivateDepotSolver().start()
# cultivateDepotSolver().start()
DepotSolver().run()
except Exception as e:
logger.exception(f"先不运行 出bug了 : {e}")

View file

@ -9,6 +9,7 @@ import cv2
import numpy as np
import pandas as pd
from skimage.feature import hog
from sklearn.cluster import KMeans
from mower import __rootdir__
from mower.utils import config
@ -36,6 +37,47 @@ def 导入_数字模板():
return 数字模板列表
def 找几何中心(coordinates, n_clusters=3):
coordinates_array = np.array(coordinates).reshape(-1, 1)
kmeans = KMeans(n_clusters=n_clusters)
kmeans.fit(coordinates_array)
centers = kmeans.cluster_centers_.flatten().astype(int)
logger.debug(centers)
return sorted(centers)
def 找圆(拼接结果, 参数1=50, 参数2=30, 圆心间隔=230, 最小半径=90, 最大半径=100):
灰图 = cv2.cvtColor(拼接结果, cv2.COLOR_RGB2GRAY)
= cv2.HoughCircles(
灰图,
cv2.HOUGH_GRADIENT,
dp=1,
minDist=圆心间隔,
param1=参数1,
param2=参数2,
minRadius=最小半径,
maxRadius=最大半径,
)
return
def 拼图(图片列表):
try:
stitcher = cv2.Stitcher.create(mode=cv2.Stitcher_SCANS)
status, result = stitcher.stitch(图片列表)
if status == cv2.Stitcher_OK:
logger.info("仓库扫描: 拼接完成。")
return result
else:
logger.warning(f"仓库扫描: 拼接失败,状态码: {status}")
raise RuntimeError(f"拼接失败,状态码: {status}")
except RuntimeError as e:
logger.error(f"仓库扫描: 拼接过程中出现错误: {e}")
raise
def 提取特征点(模板):
模板 = 模板[40:173, 40:173]
hog_features = hog(
@ -50,15 +92,35 @@ def 提取特征点(模板):
return hog_features
def 算坐标():
circles_x = sorted([:, 0])
groups = []
start_index = 0
for i in range(1, len(circles_x)):
if circles_x[i] - circles_x[i - 1] >= 20:
groups.append(circles_x[start_index:i])
start_index = i
groups.append(circles_x[start_index:])
circles_x = [int(sum(group) / len(group)) for group in groups]
circles_y = 找几何中心([:, 1], 3)
return circles_x, circles_y
def 识别空物品(物品灰):
物品灰 = 物品灰[0:130, 130:260]
_, 二值图 = cv2.threshold(物品灰, 60, 255, cv2.THRESH_BINARY)
白像素个数 = cv2.countNonZero(二值图)
所有像素个数 = 二值图.shape[0] * 二值图.shape[1]
白像素比值 = int((白像素个数 / 所有像素个数) * 100)
# saveimg_depot(
# cv2.hconcat([物品灰, 二值图]),
# f"{白像素比值}_{datetime.now().timestamp()}.png",
# "depot_3_empty",
# )
if 白像素比值 > 99:
logger.info("删除一次空物品")
logger.info("仓库扫描: 删除一次空物品")
return False
else:
@ -80,9 +142,18 @@ def 切图(圆心x坐标, 圆心y坐标, 拼接结果, 正方形边长=130):
id = str(datetime.now().timestamp())
正方形切 = 正方形[26:239, 26:239]
图片.append([正方形切, 正方形灰, id])
# saveimg_depot(正方形切, id + ".png", "depot_4_name")
# saveimg_depot(正方形灰, id + ".png", "depot_4_num")
return 图片
def 经验卡分类(物品):
# 图像处理
# return 物品名称
logger.info("没有写具体内容 ")
pass
class depotREC(SceneGraphSolver):
def __init__(self) -> None:
start_time = datetime.now()
@ -90,6 +161,8 @@ class depotREC(SceneGraphSolver):
# sift = cv2.SIFT_create()
orb = cv2.ORB_create()
bf = cv2.BFMatcher(cv2.NORM_HAMMING2, crossCheck=True)
# flann = cv2.FlannBasedMatcher(
# dict(algorithm=1, trees=2), dict(checks=50))
self.detector = orb
self.matcher = bf
@ -97,17 +170,27 @@ class depotREC(SceneGraphSolver):
with lzma.open(f"{__rootdir__}/models/CONSUME.pkl", "rb") as pkl:
self.knn模型_CONSUME = pickle.load(pkl)
with lzma.open(f"{__rootdir__}/models/MATERIAL.pkl", "rb") as pkl:
self.knn模型_MATERIAL = pickle.load(pkl)
with lzma.open(f"{__rootdir__}/models/NORMAL.pkl", "rb") as pkl:
self.knn模型_NORMAL = pickle.load(pkl)
# self.时间模板 = self.导入_时间模板()
self.物品数字 = 导入_数字模板()
self.结果字典 = {}
self.明日方舟工具箱json = {}
logger.info(f"吟唱用时{datetime.now() - start_time}")
logger.info(f"仓库扫描: 吟唱用时{datetime.now() - start_time}")
def 切图主程序(self, 拼接好的图片):
横坐标 = [188 + 234 * i for i in range(0, 8)]
纵坐标 = [144, 430, 715]
= 找圆(拼接好的图片)
if is not None and len([0]) > 2:
= np.round([0, :]).astype("int")
横坐标, 纵坐标 = 算坐标()
else:
横坐标 = [188 + 234 * i for i in range(0, 8)]
纵坐标 = [144, 430, 715]
logger.warning("仓库扫描: 在这个分类下没有找到足够多的圆,使用预设坐标")
切图列表 = 切图(横坐标, 纵坐标, 拼接好的图片)
return 切图列表
@ -152,26 +235,29 @@ class depotREC(SceneGraphSolver):
super().run()
def transition(self) -> bool:
logger.info("回到桌面")
logger.info("仓库扫描: 回到桌面")
self.back_to_index()
if self.scene() == Scene.INDEX:
self.tap_index_element("warehouse")
logger.info("从主界面点击仓库界面")
logger.info("仓库扫描: 从主界面点击仓库界面")
time = datetime.now()
任务组 = [
(1200, self.knn模型_CONSUME, "消耗物品"),
(1400, self.knn模型_NORMAL, "基础物品"),
(1700, self.knn模型_MATERIAL, "养成材料"),
]
for 任务 in 任务组:
self.tap((任务[0], 70))
if not self.find("depot_empty"):
self.分类扫描(任务[1])
logger.info(f"{任务[2]}识别,识别用时{datetime.now() - time}")
self.分类扫描(任务[1], 任务[2])
logger.info(
f"仓库扫描: {任务[2]}识别,识别用时{datetime.now() - time}"
)
else:
logger.info("这个分类下没有物品")
logger.info(self.结果字典)
logger.info("仓库扫描: 这个分类下没有物品")
logger.info(f"仓库扫描: {self.结果字典}")
result = [
int(datetime.now().timestamp()),
json.dumps(self.结果字典, ensure_ascii=False),
@ -194,17 +280,53 @@ class depotREC(SceneGraphSolver):
similarity = len(matches) / max(len(descriptors1), len(descriptors2))
return similarity * 100
def 分类扫描(self, 模型名称):
def 分类扫描(self, 模型名称, 分类名称):
截图列表 = []
旧的截图 = config.recog.img
旧的截图 = 旧的截图[140:1000, :]
截图列表.append(旧的截图)
# saveimg(旧的截图, "depot_1_screenshot")
config.recog.update()
拼接好的图片 = 截图列表[0]
logger.info(f"仓库扫描: 把第{len(截图列表)}页保存进内存中等待识别")
if "养成材料" in 分类名称:
while True:
self.swipe_noinertia((1800, 450), (-1000, 0)) # 滑动
config.recog.update()
新的截图 = config.recog.img
新的截图 = 新的截图[140:1000, :]
# saveimg(新的截图, "depot_1_screenshot")
相似度 = self.对比截图(截图列表[-1], 新的截图)
if 相似度 < 70:
截图列表.append(新的截图)
logger.info(
f"仓库扫描: 把第{len(截图列表)}页保存进内存中等待识别,相似度{相似度}"
)
else:
logger.info("仓库扫描: 这大抵是最后一页了")
break
logger.info(f"仓库扫描: 截图读取完了,有{len(截图列表)}张截图")
logger.info("仓库扫描: 开始计算裁切图像")
if len(截图列表) > 1:
拼接好的图片 = 拼图(截图列表)
else:
拼接好的图片 = 截图列表[0]
# saveimg(拼接好的图片, "depot_2_stitcher")
切图列表 = self.切图主程序(拼接好的图片)
logger.info(f"需要识别{len(切图列表)}个物品")
logger.info(f"仓库扫描: 需要识别{len(切图列表)}个物品")
for [物品, 物品灰, id] in 切图列表:
[物品名称, 物品数字] = self.匹配物品一次(物品, 物品灰, 模型名称)
# saveimg_depot(
# 物品,
# f"{id}_{物品名称}_{物品数字}.png",
# "depot_5_result",
# )
logger.debug([物品名称, 物品数字])
if "作战记录" in 物品名称:
logger.info("对经验卡进行重新识别")
经验卡分类(物品) # TODO
self.结果字典[物品名称] = self.结果字典.get(物品名称, 0) + 物品数字

View file

@ -17,6 +17,12 @@ def 读取仓库():
创建json()
with open(path, "r", encoding="utf-8") as f:
depotinfo = json.load(f)
depotinfo = {
"code": 0,
"message": "OK",
"timestamp": "0",
"data": {"items": [{"id": "0", "count": "0"}]},
}
物品数量 = depotinfo["data"]["items"]
新物品1 = {
key_mapping[item["id"]][2]: int(item["count"])
@ -224,8 +230,8 @@ def 创建json():
a = {
"code": 0,
"message": "OK",
"timestamp": "1719065002",
"data": {"items": [{"id": "31063", "count": "0"}]},
"timestamp": "0",
"data": {"items": [{"id": "0", "count": "0"}]},
}
with open(path, "w", encoding="utf-8") as f:
json.dump(a, f)