Skip to content

Commit 6b707e6

Browse files
Merge pull request #10 from shuangluoxss/main
2.0 artifacts support
2 parents a22d507 + f78a82f commit 6b707e6

8 files changed

Lines changed: 89 additions & 15 deletions

File tree

.gitignore

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
ArtScanner/artifacts.genshinart.json
22
ArtScanner/artifacts.mingyulab.json
3-
ArtScanner/artifacts.dat
4-
ArtScanner/artifacts.dat.index
5-
ArtScanner/artifacts.dat.lock
6-
ArtScanner/artifacts.dat.tmp
73
**/__pycache__/**
84
ArtScanner/build/**
95
ArtScanner/dist/**
106
ArtScanner/*.spec
117
ArtScanner/artifacts/**
8+
ArtScanner/artifacts-all/**
129

1310
.vscode/**

ArtScanner/ArtsInfo.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@
9797
["游医的银莲", "游医的枭羽", "游医的怀钟", "游医的药壶", "游医的方巾"],
9898
["勋绩之花", "昭武翎羽", "金铜时晷", "盟誓金爵", "将帅兜鏊"],
9999
["无垢之花", "贤医之羽", "停摆之刻", "超越之盏", "嗤笑之面"],
100+
["祈望之心", "思忆之矢", "无常之面", "羁缠之花", "朝露之时"],
101+
["绯花之壶", "切落之羽", "华饰之兜", "明威之镡", "雷云之笼"]
100102
]
101103
Users = [
102104
"空",
@@ -193,6 +195,8 @@
193195
"travelingDoctor", # 游医
194196
"tenacityOfTheMillelith", # 千岩牢固
195197
"paleFlame", # 苍白之火
198+
"shimenawaReminiscence", # 追忆之注连
199+
"emblemOfSeveredFate", # 绝缘之旗印
196200
]
197201

198202

@@ -254,4 +258,6 @@
254258
"traveling_doctor", # 游医
255259
"tenacity_of_the_millelith", # 千岩牢固
256260
"pale_flame", # 苍白之火
261+
"reminiscence_of_shime", # 追忆之注连
262+
"seal_of_insulation", # 绝缘之旗印
257263
]

ArtScanner/build.cmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
pyinstaller --onefile --add-data "mn_model_weight.h5;." --add-data "Tools/ReliquaryLevelExcelConfigData.json;./Tools" --add-data "Tools/ReliquaryAffixExcelConfigData.json;./Tools" --hidden-import=h5py --hidden-import=h5py.defs --hidden-import=h5py.utils --hidden-import=h5py.h5ac --hidden-import=h5py._proxy --uac-admin -n ArtScanner main.py
1+
pyinstaller --onefile --add-data "mn_model_weight.h5;." --add-data "mn_model_weight_artnames.h5;." --add-data "Tools/ReliquaryLevelExcelConfigData.json;./Tools" --add-data "Tools/ReliquaryAffixExcelConfigData.json;./Tools" --hidden-import=h5py --hidden-import=h5py.defs --hidden-import=h5py.utils --hidden-import=h5py.h5ac --hidden-import=h5py._proxy --uac-admin -n ArtScanner main.py

ArtScanner/environment.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: ArtScanner
22
channels:
3-
- conda-forge
43
- defaults
4+
- conda-forge
55
- msys2
66
dependencies:
77
- _tflow_select=2.3.0=eigen
@@ -117,4 +117,3 @@ dependencies:
117117
- keyboard==0.13.5
118118
- mouse==0.7.1
119119
- mss==6.1.0
120-
prefix: C:\Users\marti\miniforge3\envs\ArtScanner

ArtScanner/main.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def is_admin():
2525

2626
import win32gui
2727
import time
28-
import keyboard, mouse
28+
import mouse
2929
import os
3030
import json
3131
import ocr
@@ -90,7 +90,8 @@ def is_admin():
9090
# margin near level number, color=233,229,220
9191

9292
# initialization
93-
ocr_model = ocr.OCR(scale_ratio=game_info.scale_ratio, model_weight=os.path.join(bundle_dir, 'mn_model_weight.h5'))
93+
ocr_model = ocr.OCR(scale_ratio=game_info.scale_ratio, model_weight=os.path.join(bundle_dir, 'mn_model_weight.h5'),
94+
ocr_model_artnames=ocr.OCR_artnames(model_weight=os.path.join(bundle_dir, 'mn_model_weight_artnames.h5')))
9495
art_id = 0
9596
saved = 0
9697
skipped = 0
@@ -99,8 +100,6 @@ def is_admin():
99100
star_dist_saved = [0,0,0,0,0]
100101

101102

102-
os.makedirs('artifacts', exist_ok=True)
103-
104103
input('请打开圣遗物背包界面,最好翻到圣遗物列表最上面。按回车继续')
105104
print('---------------------------------')
106105
if game_info.incomplete_lastrow:
@@ -116,6 +115,7 @@ def is_admin():
116115
level_threshold = input('请输入圣遗物等级阈值(0-20)(比如:16,则仅将保存16级及以上的圣遗物信息)。直接按回车则默认保存所有圣遗物信息。')
117116
rarity_threshold = input('请输入圣遗物星级阈值(1-5)(比如:5,则仅将保存5星的圣遗物信息)。直接按回车则默认保存所有圣遗物信息。')
118117
scroll_interval = input('请输入翻页时的检测延迟(秒),数值越大翻页速度越慢,可以解决一些翻页时的检测BUG,直接回车则为默认值0.05。')
118+
save_all = input('请输入是否保存所有圣遗物截图,若是,请输入y,直接按回车则默认不保存。')
119119
print('---------------------------------')
120120
print('程序将于5秒后自动开始运行,若此条提示显示时未自动切换到原神窗口,请手动点击原神窗口切到前台')
121121

@@ -144,8 +144,16 @@ def is_admin():
144144
except:
145145
exporter = art_data.exportGenshinArtJSON
146146
export_name = 'artifacts.genshinart.json'
147+
try:
148+
save_all = save_all.lower().startswith('y')
149+
except:
150+
save_all = False
147151

148152

153+
os.makedirs('artifacts', exist_ok=True)
154+
if save_all:
155+
os.makedirs('artifacts-all', exist_ok=True)
156+
149157
mouse.on_middle_click(art_scanner.interrupt)
150158

151159
print('正在自动对齐')
@@ -160,7 +168,15 @@ def artscannerCallback(art_img):
160168
global skipped
161169
global failed
162170
global star_dist
171+
global save_all
172+
if save_all:
173+
art_img.save(f'artifacts-all/{art_id}.png')
163174
info = ocr_model.detect_info(art_img)
175+
176+
# 修复部分错误识别
177+
if info['main_attr_name'] == '生命值' and info['main_attr_value'] == '3,957':
178+
info['main_attr_value'] = '3,967'
179+
164180
star_dist[info['star']-1] += 1
165181
if decodeValue(info['level'])<level_threshold or decodeValue(info['star'])<rarity_threshold:
166182
skipped += 1
13 MB
Binary file not shown.

ArtScanner/ocr.py

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from tensorflow import get_logger
1111
from tensorflow.keras.models import Model
1212
from tensorflow.keras.layers.experimental.preprocessing import StringLookup
13-
from tensorflow.keras.layers import Input, Reshape, Dense, Dropout, Bidirectional, LSTM
13+
from tensorflow.keras.layers import Input, Reshape, Dense, Dropout, Bidirectional, LSTM, Flatten
1414
from tensorflow.keras.backend import ctc_decode
1515
from mobilenetv3 import MobileNetV3_Small
1616
from tensorflow.strings import reduce_join
@@ -33,13 +33,13 @@ class Config:
3333
subattr_4_coords = [67, 636, 560, 676]
3434

3535
class OCR:
36-
def __init__(self, model_weight='mn_model_weight.h5', scale_ratio=1):
36+
def __init__(self, model_weight='mn_model_weight.h5', scale_ratio=1, ocr_model_artnames=None):
3737
self.scale_ratio = scale_ratio
3838
self.characters = sorted(
3939
[
4040
*set(
4141
"".join(
42-
sum(ArtsInfo.ArtNames, [])
42+
sum(ArtsInfo.ArtNames[:-2], [])
4343
+ ArtsInfo.TypeNames
4444
+ list(ArtsInfo.MainAttrNames.values())
4545
+ list(ArtsInfo.SubAttrNames.values())
@@ -63,12 +63,14 @@ def __init__(self, model_weight='mn_model_weight.h5', scale_ratio=1):
6363
self.max_length = 15
6464
self.build_model(input_shape=(self.width, self.height))
6565
self.model.load_weights(model_weight)
66+
self.ocr_model_artnames = ocr_model_artnames
6667

6768
def detect_info(self, art_img):
6869
info = self.extract_art_info(art_img)
6970
x = np.concatenate([self.preprocess(info[key]).T[None, :, :, None] for key in sorted(info.keys())], axis=0)
7071
y = self.model.predict(x)
7172
y = self.decode(y)
73+
y[3] = self.ocr_model_artnames.reg(x[3][None])
7274
return {**{key:v for key, v in zip(sorted(info.keys()), y)}, **{'star':self.detect_star(art_img)}}
7375

7476
def extract_art_info(self, art_img):
@@ -198,4 +200,51 @@ def build_model(self, input_shape):
198200
output = Dense(len(self.characters) + 2, activation="softmax", name="dense2")(x)
199201

200202
# Define the model
201-
self.model = Model(inputs=[input_img], outputs=output, name="ocr_model_v1")
203+
self.model = Model(inputs=[input_img], outputs=output, name="ocr_model_v1")
204+
205+
class OCR_artnames:
206+
def __init__(self, model_weight='mn_model_weight_artnames.h5'):
207+
self.artnames = sorted(set(sum(ArtsInfo.ArtNames, [])))
208+
209+
self.model = self.build_model(input_shape=(240, 16))
210+
self.model.load_weights(model_weight)
211+
212+
def build_model(self, input_shape):
213+
input_img = Input(
214+
shape=(input_shape[0], input_shape[1], 1), name="image", dtype="float32"
215+
)
216+
mobilenet = MobileNetV3_Small(
217+
(input_shape[0], input_shape[1], 1), 0, alpha=1.0, include_top=False
218+
).build()
219+
x = mobilenet(input_img)
220+
new_shape = ((input_shape[0] // 8), (input_shape[1] // 8) * 576)
221+
x = Reshape(target_shape=new_shape, name="reshape")(x)
222+
x = Dense(64, activation="relu", name="dense1")(x)
223+
x = Dropout(0.2)(x)
224+
225+
# RNNs
226+
x = Bidirectional(LSTM(128, return_sequences=True, dropout=0.25))(x)
227+
x = Bidirectional(LSTM(64, return_sequences=True, dropout=0.25))(x)
228+
229+
# Output layer
230+
x = Flatten(name="flatten")(x)
231+
x = Dense(
232+
len(self.artnames), activation="softmax", name="dense2"
233+
)(x)
234+
235+
output = x
236+
237+
# Define the model
238+
model = Model(inputs=[input_img], outputs=output, name="ocr_model_artnames")
239+
240+
return model
241+
242+
def decode_single(self, pred):
243+
i = pred[0].argmax()
244+
if pred[0][i] > 0.75:
245+
return self.artnames[i]
246+
else:
247+
return 'Unknown'
248+
249+
def reg(self, x):
250+
return self.decode_single(self.model.predict(x))

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,10 @@
22
Yet Another Genshin Impact Artifact Scanner
33

44
check https://bbs.nga.cn/read.php?tid=26425531&_ff=650 for details
5+
6+
Fork自[GenshinArtScanner](https://github.com/ProblemFactory/GenshinArtScanner)
7+
8+
## 主要改动
9+
- 添加了对2.0新圣遗物`追忆之注连``绝缘之旗印`的支持
10+
- 将圣遗物名称识别部分单独建立为新模型,减小新增圣遗物后重新训练的工作量
11+
- 修正了1080P分辨率下16级五星生之花主属性3967被错误识别为3957的问题

0 commit comments

Comments
 (0)