-
根据指定窗口句柄截图
def WindowShot(self):
"""
根据窗口句柄截图
返回: 图片对象
"""
windll.user32.SetProcessDPIAware()
hwnd = self.Handle
left, top, right, bottom = win32gui.GetClientRect(hwnd)
w = right - left
h = bottom - top
hwnd_dc = win32gui.GetWindowDC(hwnd)
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
save_dc = mfc_dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(mfc_dc, w, h)
save_dc.SelectObject(bitmap)
# If Special K is running, this number is 3. If not, 1
result = windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 3)
bmpinfo = bitmap.GetInfo()
bmpstr = bitmap.GetBitmapBits(True)
img = np.frombuffer(bmpstr, dtype=np.uint8).reshape((bmpinfo["bmHeight"], bmpinfo["bmWidth"], 4))
img = np.ascontiguousarray(img)[..., :-1] # make image C_CONTIGUOUS and drop alpha channel
#img = Image.frombuffer("RGB",(bmpinfo['bmWidth'], bmpinfo['bmHeight']),bmpstr, 'raw', 'BGRX', 0, 1)
if not result: # result should be 1
win32gui.DeleteObject(bitmap.GetHandle())
save_dc.DeleteDC()
mfc_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwnd_dc)
raise RuntimeError(f"Unable to acquire screenshot! Result: {result}")
#cv2.imwrite('./imgs/print.png', img)
#return img
return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
-
在图片中查找第一个相似的图片
def LocateOnImage(self, template, image=None, region=None, confidence=0.9, grayscale=True):
"""
在image中寻找template,返回第一个查找到的范围
参数:
template: 需要查找的图片,文件名或图片对象
image: 被查找的图片,文件名或图片对象
region: 查找范围
confidence: 置信度
grayscale: 是否为灰度图
返回值:
查找到的图片范围
"""
if image is None:
image = self.WindowShot()
return pyautogui.locate(template, image, region=region, confidence=confidence, grayscale=grayscale)
-
在图片中查找所有相似的图片
def LocateAllOnImage(self, template, image=None, region=None, confidence=0.9, grayscale=True):
"""
在image中寻找template,返回第一个查找到的范围
参数:
template: 需要查找的图片,文件名或图片对象
image: 被查找的图片,文件名或图片对象
region: 查找范围
confidence: 置信度
grayscale: 是否为灰度图
返回值:
查找到的图片范围
"""
if image is None:
image = self.WindowShot()
return pyautogui.locateAll(template, image, region=region, confidence=confidence, grayscale=grayscale)
-
识别手牌
def GetCards(self, image, player):
hand_cards = []
cards = ""
start_x = 0
width = player["width"]
for card in self.AllCardsNC:
confidence = player["confidence"] or 0.85
grayscale = True
if(card in ('D', 'X')):
confidence = 0.85
grayscale = False
card_key = player["prefix"] + card
matches = self.LocateAllOnImageName(card_key, image, player["region"], confidence, grayscale)
if len(matches) > 0:
sorted_matches = sorted(matches, key=lambda match: match[0])
#print(target_position)
#print(mark)
if(card != 'X'):
start_x = 0
for match in sorted_matches:
if(start_x == 0 or start_x + player["width"] < match[0]):
#大小王容易判断错误,需要再判断一下颜色值
if(card == 'D'):
#match = sorted_matches[0]
y,x,h,w = match
cropped_image = image[x:x+w, y:y+h]
#colors = cv2.mean(cropped_image)
mean, stddev = cv2.meanStdDev(cropped_image)
#print("均值:", mean)
#print("差值:", stddev)
if(stddev[2][0] > 30):
continue
start_x = match[0]
width = match[2]
hand_cards.append({card:match})
cards += card
return cards, hand_cards
-
将出牌记录发送给AI,进行预测
def GetCardsForPredict(self):
#将出牌记录发送给AI,进行预测
resultStr = self.PostPredict()
#获取最高胜率的出牌
last_move_cards = self.GetPredictWinRates(resultStr)
return last_move_cards
-
出牌
def PlayedCards(self, cards, image=None):
if image is not None:
window_shot_image = image
else:
window_shot_image = self.WindowShot()
player_self_cards, range = self.GetCards(window_shot_image, self.Players["PlayerSelf"])
select_index = []
select_cards = []
#将cards中的字符顺序反转
play_cards = cards[::-1]
cards = play_cards
for c in cards:
index = -1
for card in player_self_cards:
index += 1
if c == card and index not in select_index:
select_index.append(index)
select_cards.append(c)
#print(range[index])
cards = cards.replace(c, '', 1)
card_range = range[index][c]
break
cards = play_cards
index = -1
#window_shot_image = self.WindowShot()
for n in select_index:
window_shot_image = self.WindowShot()
player_self_cards, range = self.GetCards(window_shot_image, self.Players["PlayerSelf"])
if(len(player_self_cards) > n):
#player_self_cards = player_self_cards
index += 1
card_range = range[n][cards[index]]
#如果要出的牌还未选择完毕,则点击
if(card_range[1] > self.CardTop):
self.LeftClick(card_range)
time.sleep(0.2)
return self.GetSelectCards(play_cards)
-
DouZero 的请求结构体
Predict = {
"bomb_num":0,#炸弹数量
"card_play_action_seq":'',#历史出牌动作序列,用逗号分隔
"last_move_landlord":'',#地主最后出的牌
"last_move_landlord_down":'',#地主下家最后出的牌
"last_move_landlord_up":'',#地主上家最后出的牌
"num_cards_left_landlord":20,#地主手牌剩余数量
"num_cards_left_landlord_down":17,#地主下家手牌剩余数量
"num_cards_left_landlord_up":17,#地主上家手牌剩余数量
"other_hand_cards":'',#还剩余的牌
"played_cards_landlord":'',#地主所有出的牌
"played_cards_landlord_down":'',#地主下家所有出的牌
"played_cards_landlord_up":'',#地主上家所有出的牌
"player_hand_cards":'',#玩家手中的牌
"player_position":0, #-当前玩家的位置序号 0 地主,1 地主下家,2 地主上家
"three_landlord_cards":''#三张底牌
}