@@ -23,7 +23,7 @@ def scenario_name(self) -> str:
2323 return "青春杯"
2424
2525 def get_date_img (self , img : any ) -> any :
26- return img [40 :70 , 160 :280 ]
26+ return img [40 :70 , 160 :370 ]
2727
2828 def get_turn_to_race_img (self , img ) -> any :
2929 return img [70 :120 , 30 :90 ]
@@ -98,18 +98,21 @@ def parse_training_result(self, img: any) -> list[int]:
9898 skill_point_incr = (0 if skill_point_incr_text == "" else int (skill_point_incr_text )) + (0 if skill_point_incr_extra_text == "" else int (skill_point_incr_extra_text ))
9999
100100 return [speed_icr , stamina_incr , power_incr , will_incr , intelligence_incr , skill_point_incr ]
101-
102- def parse_training_support_cord (self , img : any ) -> list [SupportCardInfo ]:
103- # TODO: 目前没有识别青春杯参数和青春杯友情条, 也没有将其作为训练权重的一部分,
104- base_x = 590
101+
102+ def parse_training_support_card (self , img : any ) -> list [SupportCardInfo ]:
103+ base_x = 550
105104 base_y = 177
106105 inc = 115
107106 support_card_list_info_result : list [SupportCardInfo ] = []
108107 for i in range (5 ):
109- support_card_icon = img [base_y :base_y + inc , base_x : base_x + 105 ]
108+ support_card_icon = img [base_y :base_y + inc , base_x : base_x + 145 ]
109+
110+ # 有青春杯训练, 且青春杯友情未满
111+ can_incr_aoharu_train = detect_aoharu_train_arrow (support_card_icon ) and aoharu_train_not_full (support_card_icon )
112+
110113 # 判断好感度
111114 support_card_icon = cv2 .cvtColor (support_card_icon , cv2 .COLOR_BGR2RGB )
112- favor_process_check_list = [support_card_icon [106 , 16 ], support_card_icon [106 , 20 ]]
115+ favor_process_check_list = [support_card_icon [106 , 56 ], support_card_icon [106 , 60 ]]
113116 support_card_favor_process = SupportCardFavorLevel .SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN
114117 for support_card_favor_process_pos in favor_process_check_list :
115118 if compare_color_equal (support_card_favor_process_pos , [255 , 235 , 120 ]):
@@ -124,13 +127,6 @@ def parse_training_support_cord(self, img: any) -> list[SupportCardInfo]:
124127 if support_card_favor_process != SupportCardFavorLevel .SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN :
125128 break
126129
127- # 判断是否有事件
128- support_card_event_pos = support_card_icon [5 , 83 ]
129- support_card_event_available = False
130- if (support_card_event_pos [0 ] >= 250
131- and 55 <= support_card_event_pos [1 ] <= 90
132- and 115 <= support_card_event_pos [2 ] <= 150 ):
133- support_card_event_available = True
134130 # 判断支援卡类型
135131 support_card_type = SupportCardType .SUPPORT_CARD_TYPE_UNKNOWN
136132 support_card_icon = cv2 .cvtColor (support_card_icon , cv2 .COLOR_RGB2GRAY )
@@ -146,11 +142,107 @@ def parse_training_support_cord(self, img: any) -> list[SupportCardInfo]:
146142 support_card_type = SupportCardType .SUPPORT_CARD_TYPE_INTELLIGENCE
147143 elif image_match (support_card_icon , REF_SUPPORT_CARD_TYPE_FRIEND ).find_match :
148144 support_card_type = SupportCardType .SUPPORT_CARD_TYPE_FRIEND
149- if support_card_favor_process is not SupportCardFavorLevel .SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN :
145+ if (can_incr_aoharu_train ) or \
146+ (support_card_favor_process is not SupportCardFavorLevel .SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN ):
150147 info = SupportCardInfo (card_type = support_card_type ,
151- favor = support_card_favor_process ,
152- has_event = support_card_event_available )
148+ favor = support_card_favor_process ,
149+ can_incr_aoharu_train = can_incr_aoharu_train )
153150 support_card_list_info_result .append (info )
154151 base_y += inc
155152
156- return support_card_list_info_result
153+ return support_card_list_info_result
154+
155+ # 检测支援卡右上角是否有箭头图标, 同时排除感叹号防止false positive
156+ # 输入的图片必须是彩色的
157+ def detect_aoharu_train_arrow (support_card_icon ):
158+ support_card_icon = cv2 .cvtColor (support_card_icon , cv2 .COLOR_BGR2RGB )
159+ # 定义右上角检测区域
160+ arrow_region_x_start = 110
161+ arrow_region_x_end = 145
162+ arrow_region_y_start = 0
163+ arrow_region_y_end = 40
164+
165+ arrow_region = support_card_icon [arrow_region_y_start :arrow_region_y_end ,
166+ arrow_region_x_start :arrow_region_x_end ]
167+
168+ # 定义箭头可能的颜色范围 (检查橙色)
169+ orange_lower = [240 , 100 , 50 ]
170+ orange_upper = [255 , 180 , 100 ]
171+
172+ # 定义红色像素范围(用于检测感叹号)
173+ red_lower = [180 , 30 ,50 ]
174+ red_upper = [255 , 100 , 150 ]
175+
176+ # 计算橙色像素和红色像素的数量
177+ orange_pixels = 0
178+ red_pixels = 0
179+ total_pixels = arrow_region .shape [0 ] * arrow_region .shape [1 ]
180+
181+ for y in range (arrow_region .shape [0 ]):
182+ for x in range (arrow_region .shape [1 ]):
183+ pixel = arrow_region [y , x ]
184+
185+ # 检测橙色像素
186+ if (orange_lower [0 ] <= pixel [0 ] <= orange_upper [0 ] and
187+ orange_lower [1 ] <= pixel [1 ] <= orange_upper [1 ] and
188+ orange_lower [2 ] <= pixel [2 ] <= orange_upper [2 ]):
189+ orange_pixels += 1
190+ # 检测红色像素
191+ elif (red_lower [0 ] <= pixel [0 ] <= red_upper [0 ] and
192+ red_lower [1 ] <= pixel [1 ] <= red_upper [1 ] and
193+ red_lower [2 ] <= pixel [2 ] <= red_upper [2 ]):
194+ red_pixels += 1
195+
196+ orange_ratio = orange_pixels / total_pixels if total_pixels > 0 else 0
197+ red_ratio = red_pixels / total_pixels if total_pixels > 0 else 0
198+
199+ has_arrow = False
200+
201+ # 首先排除感叹号:如果红色像素比例过高,判断为感叹号
202+ if red_ratio > 0.2 :
203+ has_arrow = False
204+ # 如果橙色像素比例超过阈值
205+ elif (orange_ratio > 0.05 ):
206+ has_arrow = True
207+
208+ return has_arrow
209+
210+
211+ # 检测左下角青春杯训练值是否未满
212+ # 如果已满或者不存在UI(比如已经触发了魂爆, 则返回false)
213+ # 否则返回true
214+ def aoharu_train_not_full (support_card_icon ) -> bool :
215+ support_card_icon = cv2 .cvtColor (support_card_icon , cv2 .COLOR_BGR2RGB )
216+ avatar_region_x_start = 5
217+ avatar_region_x_end = 45
218+ avatar_region_y_start = 70
219+ avatar_region_y_end = 110
220+
221+ avatar_region = support_card_icon [avatar_region_y_start :avatar_region_y_end ,
222+ avatar_region_x_start :avatar_region_x_end ]
223+
224+ total_pixels = avatar_region .shape [0 ] * avatar_region .shape [1 ]
225+ if total_pixels == 0 :
226+ return False
227+
228+ # 检测灰色
229+ grey_lower = [100 , 100 , 100 ]
230+ grey_upper = [150 , 150 , 150 ]
231+ grey_pixels = 0
232+
233+ for y in range (avatar_region .shape [0 ]):
234+ for x in range (avatar_region .shape [1 ]):
235+ pixel = avatar_region [y , x ]
236+ if (grey_lower [0 ] <= pixel [0 ] <= grey_upper [0 ] and
237+ grey_lower [1 ] <= pixel [1 ] <= grey_upper [1 ] and
238+ grey_lower [2 ] <= pixel [2 ] <= grey_upper [2 ]):
239+ grey_pixels += 1
240+
241+ grey_ratio = grey_pixels / total_pixels
242+
243+ if grey_ratio > 0.05 :
244+ status = True
245+ else :
246+ status = False
247+
248+ return status
0 commit comments