Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions dev_tools/assets_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,12 +408,10 @@ def __init__(self):
self.task_paths = [x for x in self.task_paths if 'Component' not in x]
self.task_paths.extend([str(x) for x in (self.task_path / 'Component').iterdir() if x.is_dir()])

# process_map(self.work, self.task_paths, max_workers=1)
for task_path in self.task_paths:
me = AssetsExtractor(task_path)
me.extract()


@staticmethod
def work(task_path: str):
me = AssetsExtractor(task_path)
Expand Down
8 changes: 6 additions & 2 deletions module/atom/click.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from module.base.decorator import cached_property
from module.logger import logger


class RuleClick:

def __init__(self, roi_front: tuple, roi_back: tuple, name: str = None) -> None:
Expand Down Expand Up @@ -60,14 +61,17 @@ def move(self, x: int, y: int) -> None:
x, y, w, h = self.roi_front
x += x
y += y
if x <= 0 :
if x <= 0:
x = 0
elif x >= 1280:
x = 1280

if y <= 0 :
if y <= 0:
y = 0
elif y >= 720:
y = 720

self.roi_front = x, y, w, h

def __repr__(self):
return self.name
85 changes: 53 additions & 32 deletions module/atom/ocr.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,74 @@
import numpy as np
import cv2

from module.ocr.base_ocr import BaseCor, OcrMode, OcrMethod
from module.ocr.base_ocr import BaseCor, OcrMode, OcrMethod, OcrMethodType
from module.ocr.sub_ocr import Full, Single, Digit, DigitCounter, Duration, Quantity
from module.logger import logger



class RuleOcr(Digit, DigitCounter, Duration, Single, Full, Quantity):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def pre_process(self, image):
match self.method.get_method_type():
case OcrMethodType.DEFAULT:
pass
case OcrMethodType.CF_RGB:
_val = self.method.get_val()
lower, upper = _val.split(',')
lower = np.array([int(lower[i:i + 2], 16) for i in (0, 2, 4)])
upper = np.array([int(upper[i:i + 2], 16) for i in (0, 2, 4)])
mask = cv2.inRange(image, lower, upper)
res_img = cv2.bitwise_and(image, image, mask=mask)
return res_img
case OcrMethodType.CF_HSV:
_val = self.method.get_val()
lower, upper = _val.split(',')
lower = np.array([int(lower[i:i + 2], 16) for i in (0, 2, 4)])
upper = np.array([int(upper[i:i + 2], 16) for i in (0, 2, 4)])
res_img = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
mask = cv2.inRange(res_img, lower, upper)
res_img = cv2.bitwise_and(res_img, res_img, mask=mask)
res_img = cv2.cvtColor(res_img, cv2.COLOR_HSV2RGB)
return res_img
return image

def after_process(self, result):
match self.mode:
case OcrMode.FULL: return Full.after_process(self, result)
case OcrMode.SINGLE: return Single.after_process(self, result)
case OcrMode.DIGIT: return Digit.after_process(self, result)
case OcrMode.DIGITCOUNTER: return DigitCounter.after_process(self, result)
case OcrMode.DURATION: return Duration.after_process(self, result)
case OcrMode.QUANTITY: return Quantity.after_process(self, result)
case _: return result
case OcrMode.FULL:
return Full.after_process(self, result)
case OcrMode.SINGLE:
return Single.after_process(self, result)
case OcrMode.DIGIT:
return Digit.after_process(self, result)
case OcrMode.DIGITCOUNTER:
return DigitCounter.after_process(self, result)
case OcrMode.DURATION:
return Duration.after_process(self, result)
case OcrMode.QUANTITY:
return Quantity.after_process(self, result)
case _:
return result

def ocr(self, image, keyword=None):

match self.mode:
case OcrMode.FULL: return Full.ocr_full(self, image, keyword)
case OcrMode.SINGLE: return Single.ocr_single(self, image)
case OcrMode.DIGIT: return Digit.ocr_digit(self, image)
case OcrMode.DIGITCOUNTER: return DigitCounter.ocr_digit_counter(self, image)
case OcrMode.DURATION: return Duration.ocr_duration(self, image)
case OcrMode.QUANTITY: return Quantity.ocr_quantity(self, image)
case _: return None
case OcrMode.FULL:
return Full.ocr_full(self, image, keyword)
case OcrMode.SINGLE:
return Single.ocr_single(self, image)
case OcrMode.DIGIT:
return Digit.ocr_digit(self, image)
case OcrMode.DIGITCOUNTER:
return DigitCounter.ocr_digit_counter(self, image)
case OcrMode.DURATION:
return Duration.ocr_duration(self, image)
case OcrMode.QUANTITY:
return Quantity.ocr_quantity(self, image)
case _:
return None

def coord(self) -> tuple:
"""
Expand All @@ -55,20 +91,5 @@ def coord(self) -> tuple:
return x, y



if __name__ == "__main__":
O_MALL_RESOURCE_1 = RuleOcr(roi=(144, 7, 100, 43), area=(144, 7, 100, 43), mode="Quantity", method="Default",
keyword="", name="mall_resource_1")
O_MALL_RESOURCE_2 = RuleOcr(roi=(326, 8, 124, 39), area=(326, 8, 124, 39), mode="Quantity", method="Default",
keyword="", name="mall_resource_2")
O_MALL_RESOURCE_3 = RuleOcr(roi=(533, 9, 107, 38), area=(533, 9, 107, 38), mode="Quantity", method="Default",
keyword="", name="mall_resource_3")
O_MALL_RESOURCE_4 = RuleOcr(roi=(739, 8, 100, 39), area=(739, 8, 100, 39), mode="Quantity", method="Default",
keyword="", name="mall_resource_4")
O_MALL_RESOURCE_5 = RuleOcr(roi=(935, 11, 100, 37), area=(935, 11, 100, 37), mode="Quantity", method="Default",
keyword="", name="mall_resource_5")
O_MALL_RESOURCE_6 = RuleOcr(roi=(1129, 6, 100, 41), area=(1129, 6, 100, 41), mode="Quantity", method="Default",
keyword="", name="mall_resource_6")
image = cv2.imread(r"E:\2025-01-16225353.png")
print(O_MALL_RESOURCE_5.ocr_quantity(image))

pass
43 changes: 39 additions & 4 deletions module/ocr/base_ocr.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,43 @@ class OcrMode(Enum):
DURATION = 5 # str: "Duration"
QUANTITY = 6 # str: "Quantity"

class OcrMethod(Enum):
DEFAULT = 1 # str: "Default"

class OcrMethodType(Enum):
# 默认,不需要预处理
DEFAULT = "DEFAULT"
# # 颜色过滤Color Filter
# 配置相关CF_RGB(lower, upper)
# lower ,upper 格式为6位16进制,例如FFFFFF
# 过滤图片中颜色,仅保留符合指定范围(lower到upper)的颜色
CF_HSV = "CF_HSV"
# 与CF_HSV 相似
CF_RGB = "CF_RGB"


class OcrMethod:
_reg = r"([^()]+)\((.*?)\)?$"

def __init__(self, val: str = None):
self._method_type: OcrMethodType = OcrMethodType.DEFAULT
self._val: str = val
if val is None:
return
import re
match = re.match(self._reg, val)
if not match:
return
type_str = match.group(1).upper()
if type_str not in OcrMethodType.__members__:
return
self._method_type = OcrMethodType[type_str]
self._val = match.group(2)

def get_method_type(self):
return self._method_type

def get_val(self):
return self._val


class BaseCor:

Expand All @@ -51,7 +86,7 @@ class BaseCor:

name: str = "ocr"
mode: OcrMode = OcrMode.FULL
method: OcrMethod = OcrMethod.DEFAULT # 占位符
method: OcrMethod = OcrMethod()
roi: list = [] # [x, y, width, height]
area: list = [] # [x, y, width, height]
keyword: str = "" # 默认为空
Expand Down Expand Up @@ -79,7 +114,7 @@ def __init__(self,
elif isinstance(mode, OcrMode):
self.mode = mode
if isinstance(method, str):
self.method = OcrMethod[method.upper()]
self.method = OcrMethod(method.upper())
elif isinstance(method, OcrMethod):
self.method = method
self.roi: list = list(roi)
Expand Down
49 changes: 45 additions & 4 deletions tasks/AbyssShadows/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class AbyssShadowsAssets:
C_ABYSS_FOX = RuleClick(roi_front=(822,184,49,144), roi_back=(789,130,148,249), name="abyss_fox")
# 狭间_黑豹入口
C_ABYSS_LEOPARD = RuleClick(roi_front=(1140,190,50,162), roi_back=(1093,143,138,297), name="abyss_leopard")
# 刚进入神社时,可点击进入狭间暗域的区域,用于开启狭间暗域
C_ABYSS_SHENSHE_ENTER_ABYSS = RuleClick(roi_front=(740,640,45,15), roi_back=(740,640,45,15), name="abyss_shenshe_enter_abyss")
# 战斗时,左上角退出战斗按钮区域 下半部分
C_QUIT_AREA = RuleClick(roi_front=(20,36,30,14), roi_back=(20,36,30,14), name="quit_area")
# 红标主怪点击区域
C_MARK_MAIN = RuleClick(roi_front=(380,15,45,30), roi_back=(380,15,45,30), name="mark_main")


# Image Rule Assets
Expand All @@ -49,7 +55,9 @@ class AbyssShadowsAssets:
# 神社->狭间暗域
I_RYOU_ABYSS_SHADOWS = RuleImage(roi_front=(707,492,110,27), roi_back=(707,492,110,27), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_ryou_abyss_shadows.png")
# 狭间_神龙入口
I_ABYSS_DRAGON = RuleImage(roi_front=(227,211,55,151), roi_back=(190,147,140,283), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_dragon.png")
I_ABYSS_DRAGON = RuleImage(roi_front=(200,150,110,270), roi_back=(200,150,110,270), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_dragon.png")
# 狭间_神龙入口_已封印
I_ABYSS_DRAGON_OVER = RuleImage(roi_front=(200,150,110,270), roi_back=(200,150,110,270), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_dragon_over.png")
# 狭间_孔雀入口
I_ABYSS_PEACOCK = RuleImage(roi_front=(521,152,48,165), roi_back=(465,104,145,312), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_peacock.png")
# 狭间_白藏主入口
Expand All @@ -68,14 +76,20 @@ class AbyssShadowsAssets:
I_ABYSS_MAP = RuleImage(roi_front=(306,147,170,48), roi_back=(306,147,170,48), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_map.png")
# 战报退出按钮
I_ABYSS_MAP_EXIT = RuleImage(roi_front=(1154,96,32,32), roi_back=(1154,96,32,32), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_map_exit.png")
# 怪物信息页面退出按钮
I_ABYSS_ENEMY_INFO_EXIT = RuleImage(roi_front=(975,80,90,70), roi_back=(975,80,90,70), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_enemy_info_exit.png")
# 挑战按钮
I_ABYSS_FIRE = RuleImage(roi_front=(1121,605,77,50), roi_back=(1121,605,77,50), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_fire.png")
# 前往
I_ABYSS_GOTO_ENEMY = RuleImage(roi_front=(1120,610,75,45), roi_back=(1120,610,75,45), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_goto_enemy.png")
# description
I_CHANGE_AREA = RuleImage(roi_front=(993,610,63,61), roi_back=(993,610,63,61), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_change_area.png")
# description
I_ENSURE_BUTTON = RuleImage(roi_front=(672,405,169,55), roi_back=(672,405,169,55), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_ensure_button.png")
# 进攻中
I_IS_ATTACK = RuleImage(roi_front=(586,62,73,27), roi_back=(586,62,73,27), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_is_attack.png")
I_IS_ATTACK = RuleImage(roi_front=(576,54,91,45), roi_back=(576,54,91,45), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_is_attack.png")
# 狭间暗域 挑战结束
I_CHECK_FINISH = RuleImage(roi_front=(570,50,120,60), roi_back=(570,50,120,60), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_check_finish.png")
# description
I_PEACOCK_AREA = RuleImage(roi_front=(577,14,127,36), roi_back=(577,14,127,36), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_peacock_area.png")
# 黑豹领域
Expand All @@ -88,8 +102,22 @@ class AbyssShadowsAssets:
I_DRAGON_AREA = RuleImage(roi_front=(584,15,111,34), roi_back=(584,15,111,34), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_dragon_area.png")
# description
I_WAIT_TO_START = RuleImage(roi_front=(588,64,70,26), roi_back=(588,64,70,26), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_wait_to_start.png")
# description
I_EQUIPPING = RuleImage(roi_front=(1126,545,100,83), roi_back=(1126,545,100,83), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_equipping.png")
# 选择难度按钮
I_SELECT_DIFFICULTY = RuleImage(roi_front=(703,645,50,55), roi_back=(703,645,50,55), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_select_difficulty.png")
# 容易难度
I_DIFFICULTY_EASY = RuleImage(roi_front=(620,445,90,210), roi_back=(620,445,90,210), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_difficulty_easy.png")
# 普通难度
I_DIFFICULTY_NORMAL = RuleImage(roi_front=(620,445,90,210), roi_back=(620,445,90,210), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_difficulty_normal.png")
# 困难难度
I_DIFFICULTY_HARD = RuleImage(roi_front=(620,445,90,210), roi_back=(620,445,90,210), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_difficulty_hard.png")
# 开启按钮
I_BTN_START = RuleImage(roi_front=(1120,570,100,120), roi_back=(1120,570,100,120), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_btn_start.png")
# 开启确认按钮
I_START_ENSURE = RuleImage(roi_front=(660,390,190,80), roi_back=(660,390,190,80), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_start_ensure.png")
# 当附近有可用怪物时,右下角出现的开始战斗按钮
I_ABYSS_ENEMY_FIRE = RuleImage(roi_front=(1100,560,130,130), roi_back=(1100,560,130,130), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_abyss_enemy_fire.png")
# 红标主怪
I_MARK_MAIN = RuleImage(roi_front=(375,40,60,30), roi_back=(375,40,60,30), threshold=0.8, method="Template matching", file="./tasks/AbyssShadows/res/res_mark_main.png")


# List Rule Assets
Expand All @@ -98,6 +126,19 @@ class AbyssShadowsAssets:
array=["道馆", "首领", "狭间"])


# Ocr Rule Assets
# 伤害
O_DAMAGE = RuleOcr(roi=(50,110,300,50), area=(50,110,300,50), mode="Digit", method="CF_HSV(0980B4,1ED2FF)", keyword="", name="damage")
# 神龙暗域已完成
O_DRAGON_DONE = RuleOcr(roi=(130,160,180,360), area=(130,160,180,360), mode="Single", method="CF_RGB(CCCCCC,FFFFFF)", keyword="封印", name="dragon_done")
# 孔雀暗域已完成
O_PEACOCK_DONE = RuleOcr(roi=(420,160,180,360), area=(420,160,180,360), mode="Single", method="CF_RGB(CCCCCC,FFFFFF)", keyword="封印", name="peacock_done")
# 白藏主暗域已完成
O_FOX_DONE = RuleOcr(roi=(680,160,180,360), area=(680,160,180,360), mode="Single", method="CF_RGB(CCCCCC,FFFFFF)", keyword="封印", name="fox_done")
# 黑豹暗域已完成
O_LEOPARD_DONE = RuleOcr(roi=(1000,160,180,360), area=(1000,160,180,360), mode="Single", method="CF_RGB(CCCCCC,FFFFFF)", keyword="封印", name="leopard_done")


# Swipe Rule Assets
# 滑到狭间
S_TO_ABBSY_SHADOWS = RuleSwipe(roi_front=(752,395,62,66), roi_back=(758,193,62,48), mode="default", name="to_abbsy_shadows")
Expand Down
Loading