色综合老司机第九色激情 _中文字幕日韩av资源站_国产+人+亚洲_久久久精品影院_久久久视频免费观看_欧美激情亚洲自拍_亚洲成av人片在线观看香蕉_热草久综合在线_欧美极品第一页_2020国产精品自拍

千鋒教育-做有情懷、有良心、有品質的職業教育機構

手機站
千鋒教育

千鋒學習站 | 隨時隨地免費學

千鋒教育

掃一掃進入千鋒手機站

領取全套視頻
千鋒教育

關注千鋒學習站小程序
隨時隨地免費學習課程

當前位置:首頁  >  技術干貨  > 用Python+OpenCV實現自動掃雷

用Python+OpenCV實現自動掃雷

來源:千鋒教育
發布人:xqq
時間: 2023-11-07 17:45:58 1699350358

相信許多人很早就知道有掃雷這么一款經典的游(顯卡測試)戲(軟件),更是有不少人曾聽說過中國雷圣,也是中國掃雷第一、世界綜合排名第二的郭蔚嘉的頂頂大名。掃雷作為一款在Windows9x時代就已經誕生的經典游戲,從過去到現在依然都有著它獨特的魅力:快節奏高精準的鼠標操作要求、快速的反應能力、刷新紀錄的快感,這些都是掃雷給雷友們帶來的、只屬于掃雷的獨一無二的興奮點。

一.準備

準備動手制作一套掃雷自動化軟件之前,你需要準備如下一些工具/軟件/環境

-開發環境

1.Python3環境-推薦3.6或者以上[更加推薦Anaconda3,以下很多依賴庫無需安裝]

2.numpy依賴庫[如有Anaconda則無需安裝]

3.PIL依賴庫[如有Anaconda則無需安裝]

4.opencv-python

5.win32gui、win32api依賴庫

6.支持Python的IDE[可選,如果你能忍受用文本編輯器寫程序也可以]

-掃雷軟件

·MinesweeperArbiter(必須使用MS-Arbiter來進行掃雷!)

好啦,那么我們的準備工作已經全部完成了!讓我們開始吧~

二.實現思路

在去做一件事情之前最重要的是什么?是將要做的這件事情在心中搭建一個步驟框架。只有這樣,才能保證在去做這件事的過程中,盡可能的做到深思熟慮,使得最終有個好的結果。我們寫程序也要盡可能做到在正式開始開發之前,在心中有個大致的思路。

對于本項目而言,大致的開發過程是這樣的:

完成窗體內容截取部分

完成雷塊分割部分

完成雷塊類型識別部分

完成掃雷算法

好啦,既然我們有了個思路,那就擼起袖子大力干!

1.窗體截取

其實對于本項目而言,窗體截取是一個邏輯上簡單,實現起來卻相當麻煩的部分,而且還是必不可少的部分。我們通過Spy++得到了以下兩點信息:

class_name="TMain"

title_name="MinesweeperArbiter"

·ms_arbiter.exe的主窗體類別為"TMain"

·ms_arbiter.exe的主窗體名稱為"MinesweeperArbiter"

注意到了么?主窗體的名稱后面有個空格。正是這個空格讓筆者困擾了一會兒,只有加上這個空格,win32gui才能夠正常的獲取到窗體的句柄。

本項目采用了win32gui來獲取窗體的位置信息,具體代碼如下:

hwnd=win32gui.FindWindow(class_name,title_name)

ifhwnd:

left,top,right,bottom=win32gui.GetWindowRect(hwnd)

通過以上代碼,我們得到了窗體相對于整塊屏幕的位置。之后我們需要通過PIL來進行掃雷界面的棋盤截取。

我們需要先導入PIL庫:

fromPILimportImageGrab

然后進行具體的操作。

left+=15

top+=101

right-=15

bottom-=43

rect=(left,top,right,bottom)

img=ImageGrab.grab().crop(rect)

聰明的你肯定一眼就發現了那些奇奇怪怪的MagicNumbers,沒錯,這的確是MagicNumbers,是我們通過一點點細微調節得到的整個棋盤相對于窗體的位置。

注意:這些數據僅在Windows10下測試通過,如果在別的Windows系統下,不保證相對位置的正確性,因為老版本的系統可能有不同寬度的窗體邊框。

橙色的區域是我們所需要的

好啦,棋盤的圖像我們有了,下一步就是對各個雷塊進行圖像分割了~

2.雷塊分割

在進行雷塊分割之前,我們事先需要了解雷塊的尺寸以及它的邊框大小。經過筆者的測量,在ms_arbiter下,每一個雷塊的尺寸為16px*16px。

知道了雷塊的尺寸,我們就可以進行每一個雷塊的裁剪了。首先我們需要知道在橫和豎兩個方向上雷塊的數量。

block_width,block_height=16,16

blocks_x=int((right-left)/block_width)

blocks_y=int((bottom-top)/block_height)

之后,我們建立一個二維數組用于存儲每一個雷塊的圖像,并且進行圖像分割,保存在之前建立的數組中。

defcrop_block(hole_img,x,y):

x1,y1=x*block_width,y*block_height

x2,y2=x1+block_width,y1+block_height

returnhole_img.crop((x1,y1,x2,y2))

blocks_img=[[0foriinrange(blocks_y)]foriinrange(blocks_x)]

foryinrange(blocks_y):

forxinrange(blocks_x):

blocks_img[x][y]=crop_block(img,x,y)

將整個圖像獲取、分割的部分封裝成一個庫,隨時調用就OK啦~在筆者的實現中,我們將這一部分封裝成了imageProcess.py,其中函數get_frame()用于完成上述的圖像獲取、分割過程。

3.雷塊識別

這一部分可能是整個項目里除了掃雷算法本身之外最重要的部分了。筆者在進行雷塊檢測的時候采用了比較簡單的特征,高效并且可以滿足要求。

defanalyze_block(self,block,location):

block=imageProcess.pil_to_cv(block)

block_color=block[8,8]

x,y=location[0],location[1]

#-1:Notopened

#-2:Openedbutblank

#-3:Uninitialized

#Opened

ifself.equal(block_color,self.rgb_to_bgr((192,192,192))):

ifnotself.equal(block[8,1],self.rgb_to_bgr((255,255,255))):

self.blocks_num[x][y]=-2

self.is_started=True

else:

self.blocks_num[x][y]=-1

elifself.equal(block_color,self.rgb_to_bgr((0,0,255))):

self.blocks_num[x][y]=1

elifself.equal(block_color,self.rgb_to_bgr((0,128,0))):

self.blocks_num[x][y]=2

elifself.equal(block_color,self.rgb_to_bgr((255,0,0))):

self.blocks_num[x][y]=3

elifself.equal(block_color,self.rgb_to_bgr((0,0,128))):

self.blocks_num[x][y]=4

elifself.equal(block_color,self.rgb_to_bgr((128,0,0))):

self.blocks_num[x][y]=5

elifself.equal(block_color,self.rgb_to_bgr((0,128,128))):

self.blocks_num[x][y]=6

elifself.equal(block_color,self.rgb_to_bgr((0,0,0))):

ifself.equal(block[6,6],self.rgb_to_bgr((255,255,255))):

#Ismine

self.blocks_num[x][y]=9

elifself.equal(block[5,8],self.rgb_to_bgr((255,0,0))):

#Isflag

self.blocks_num[x][y]=0

else:

self.blocks_num[x][y]=7

elifself.equal(block_color,self.rgb_to_bgr((128,128,128))):

self.blocks_num[x][y]=8

else:

self.blocks_num[x][y]=-3

self.is_mine_form=False

ifself.blocks_num[x][y]==-3ornotself.blocks_num[x][y]==-1:

self.is_new_start=False

可以看到,我們采用了讀取每個雷塊的中心點像素的方式來判斷雷塊的類別,并且針對插旗、未點開、已點開但是空白等情況進行了進一步判斷。具體色值是筆者直接取色得到的,并且屏幕截圖的色彩也沒有經過壓縮,所以通過中心像素結合其他特征點來判斷類別已經足夠了,并且做到了高效率。

在本項目中,我們實現的時候采用了如下標注方式:

1-8:表示數字1到8

9:表示是地雷

0:表示插旗

-1:表示未打開

-2:表示打開但是空白

-3:表示不是掃雷游戲中的任何方塊類型

通過這種簡單快速又有效的方式,我們成功實現了高效率的圖像識別。

4.掃雷算法實現

這可能是本篇文章最激動人心的部分了。在這里我們需要先說明一下具體的掃雷算法思路:

1)遍歷每一個已經有數字的雷塊,判斷在它周圍的九宮格內未被打開的雷塊數量是否和本身數字相同,如果相同則表明周圍九宮格內全部都是地雷,進行標記。

2)再次遍歷每一個有數字的雷塊,取九宮格范圍內所有未被打開的雷塊,去除已經被上一次遍歷標記為地雷的雷塊,記錄并且點開。

3)如果以上方式無法繼續進行,那么說明遇到了死局,選擇在當前所有未打開的雷塊中隨機點擊。(當然這個方法不是最優的,有更加優秀的解決方案,但是實現相對麻煩)

基本的掃雷流程就是這樣,那么讓我們來親手實現它吧~

首先我們需要一個能夠找出一個雷塊的九宮格范圍的所有方塊位置的方法。因為掃雷游戲的特殊性,在棋盤的四邊是沒有九宮格的邊緣部分的,所以我們需要篩選來排除掉可能超過邊界的訪問。

defgenerate_kernel(k,k_width,k_height,block_location):

ls=[]

loc_x,loc_y=block_location[0],block_location[1]

fornow_yinrange(k_height):

fornow_xinrange(k_width):

ifk[now_y][now_x]:

rel_x,rel_y=now_x-1,now_y-1

ls.append((loc_y+rel_y,loc_x+rel_x))

returnls

kernel_width,kernel_height=3,3

#Kernelmode:[Row][Col]

kernel=[[1,1,1],[1,1,1],[1,1,1]]

#Leftborder

ifx==0:

foriinrange(kernel_height):

kernel[i][0]=0

#Rightborder

ifx==self.blocks_x-1:

foriinrange(kernel_height):

kernel[i][kernel_width-1]=0

#Topborder

ify==0:

foriinrange(kernel_width):

kernel[0][i]=0

#Bottomborder

ify==self.blocks_y-1:

foriinrange(kernel_width):

kernel[kernel_height-1][i]=0

#Generatethesearchmap

to_visit=generate_kernel(kernel,kernel_width,kernel_height,location)

我們在這一部分通過檢測當前雷塊是否在棋盤的各個邊緣來進行核的刪除(在核中,1為保留,0為舍棄),之后通過generate_kernel函數來進行最終坐標的生成。

defcount_unopen_blocks(blocks):

count=0

forsingle_blockinblocks:

ifself.blocks_num[single_block[1]][single_block[0]]==-1:

count+=1

returncount

defmark_as_mine(blocks):

forsingle_blockinblocks:

ifself.blocks_num[single_block[1]][single_block[0]]==-1:

self.blocks_is_mine[single_block[1]][single_block[0]]=1

unopen_blocks=count_unopen_blocks(to_visit)

ifunopen_blocks==self.blocks_num[x][y]:

mark_as_mine(to_visit)

在完成核的生成之后,我們有了一個需要去檢測的雷塊“地址簿”:to_visit。之后,我們通過count_unopen_blocks函數來統計周圍九宮格范圍的未打開數量,并且和當前雷塊的數字進行比對,如果相等則將所有九宮格內雷塊通過mark_as_mine函數來標注為地雷。

defmark_to_click_block(blocks):

forsingle_blockinblocks:

#NotMine

ifnotself.blocks_is_mine[single_block[1]][single_block[0]]==1:

#Click-able

ifself.blocks_num[single_block[1]][single_block[0]]==-1:

#SourceSyntax:[y][x]-Converted

ifnot(single_block[1],single_block[0])inself.next_steps:

self.next_steps.append((single_block[1],single_block[0]))

defcount_mines(blocks):

count=0

forsingle_blockinblocks:

ifself.blocks_is_mine[single_block[1]][single_block[0]]==1:

count+=1

returncount

mines_count=count_mines(to_visit)

ifmines_count==block:

mark_to_click_block(to_visit)

掃雷流程中的第二步我們也采用了和第一步相近的方法來實現。先用和第一步完全一樣的方法來生成需要訪問的雷塊的核,之后生成具體的雷塊位置,通過count_mines函數來獲取九宮格范圍內所有雷塊的數量,并且判斷當前九宮格內所有雷塊是否已經被檢測出來。

如果是,則通過mark_to_click_block函數來排除九宮格內已經被標記為地雷的雷塊,并且將剩余的安全雷塊加入next_steps數組內。

#Analyzethenumberofblocks

self.iterate_blocks_image(BoomMine.analyze_block)

#Markallmines

self.iterate_blocks_number(BoomMine.detect_mine)

#Calculatewheretoclick

self.iterate_blocks_number(BoomMine.detect_to_click_block)

ifself.is_in_form(mouseOperation.get_mouse_point()):

forto_clickinself.next_steps:

on_screen_location=self.rel_loc_to_real(to_click)

mouseOperation.mouse_move(on_screen_location[0],on_screen_location[1])

mouseOperation.mouse_click()

在最終的實現內,筆者將幾個過程都封裝成為了函數,并且可以通過iterate_blocks_number方法來對所有雷塊都使用傳入的函數來進行處理,這有點類似Python中Filter的作用。

之后筆者做的工作就是判斷當前鼠標位置是否在棋盤之內,如果是,就會自動開始識別并且點擊。具體的點擊部分,筆者采用了作者為"wp"的一份代碼(從互聯網搜集而得),里面實現了基于win32api的窗體消息發送工作,進而完成了鼠標移動和點擊的操作。

以上內容為大家介紹了用Python+OpenCV實現自動掃雷,希望對大家有所幫助,如果想要了解更多Python相關知識,請關注多測師。http://www.duolefu.net/xwzx/


tags: python培訓
聲明:本站稿件版權均屬千鋒教育所有,未經許可不得擅自轉載。
10年以上業內強師集結,手把手帶你蛻變精英
請您保持通訊暢通,專屬學習老師24小時內將與您1V1溝通
免費領取
今日已有369人領取成功
劉同學 138****2860 剛剛成功領取
王同學 131****2015 剛剛成功領取
張同學 133****4652 剛剛成功領取
李同學 135****8607 剛剛成功領取
楊同學 132****5667 剛剛成功領取
岳同學 134****6652 剛剛成功領取
梁同學 157****2950 剛剛成功領取
劉同學 189****1015 剛剛成功領取
張同學 155****4678 剛剛成功領取
鄒同學 139****2907 剛剛成功領取
董同學 138****2867 剛剛成功領取
周同學 136****3602 剛剛成功領取
相關推薦HOT
色综合老司机第九色激情 _中文字幕日韩av资源站_国产+人+亚洲_久久久精品影院_久久久视频免费观看_欧美激情亚洲自拍_亚洲成av人片在线观看香蕉_热草久综合在线_欧美极品第一页_2020国产精品自拍
午夜亚洲福利老司机| 欧美最新大片在线看| 麻豆成人久久精品二区三区小说| 成人永久免费视频| 久久久久9999亚洲精品| 蜜臀a∨国产成人精品| 91精品麻豆日日躁夜夜躁| 一区二区三区四区不卡视频 | 亚洲视频狠狠干| a级高清视频欧美日韩| 国产精品短视频| 色欧美日韩亚洲| 丝袜诱惑亚洲看片| 日韩一区二区三区四区五区六区 | 国产精品18久久久久| 日韩一区二区三| 国产精品主播直播| 亚洲欧美一区二区不卡| 欧美亚洲综合在线| 极品少妇xxxx精品少妇| 国产精品久久久久久久久久久免费看 | 国产欧美日韩亚州综合| 久久成人免费日本黄色| 久久久91精品国产一区二区三区| 国产精品18久久久久久久久| 亚洲乱码国产乱码精品精的特点| 在线精品视频免费观看| 久久99国产乱子伦精品免费| 亚洲欧美在线视频| 欧美大度的电影原声| k8久久久一区二区三区| 首页国产欧美久久| 国产精品色噜噜| 欧美少妇一区二区| 成人免费观看男女羞羞视频| 午夜视频在线观看一区二区| 国产欧美日韩视频在线观看| 欧美天天综合网| 岛国精品一区二区| 国内久久精品视频| 亚洲成人在线网站| 亚洲欧美激情在线| 久久久久久影视| 欧美美女一区二区三区| 色美美综合视频| 福利一区二区在线观看| 精品一区二区精品| 久久精品国产999大香线蕉| 亚洲成人一区在线| ㊣最新国产の精品bt伙计久久| 精品美女在线观看| 日韩丝袜美女视频| 在线综合亚洲欧美在线视频| 99re亚洲国产精品| av中文字幕在线不卡| 成人av资源站| 99久久久久久| 日本道在线观看一区二区| 成人午夜在线免费| 丁香五精品蜜臀久久久久99网站| 国内精品国产三级国产a久久| 看片的网站亚洲| 精品系列免费在线观看| 日韩制服丝袜av| 日韩av在线免费观看不卡| 日日夜夜精品视频免费| 看国产成人h片视频| 国产成人在线视频网站| 成人美女在线观看| 日本韩国欧美国产| 欧美日本韩国一区| 久久精品72免费观看| 91污片在线观看| 91精品国产综合久久小美女| 在线一区二区三区做爰视频网站| 97se亚洲国产综合在线| 欧美午夜精品一区二区三区| 91在线播放网址| 欧美丝袜丝交足nylons| 欧美va日韩va| 亚洲欧美一区二区三区国产精品| 亚洲尤物在线视频观看| 日本视频中文字幕一区二区三区| 久久精品噜噜噜成人88aⅴ| 国产高清精品久久久久| 色综合中文字幕国产| 成人久久久精品乱码一区二区三区 | 精品亚洲国内自在自线福利| 国产福利91精品| 欧美日韩亚洲综合在线 欧美亚洲特黄一级| 91激情五月电影| 精品日产卡一卡二卡麻豆| 亚洲欧美在线aaa| 另类综合日韩欧美亚洲| 在线一区二区三区做爰视频网站| 欧美电影免费观看高清完整版在线观看 | 欧美刺激午夜性久久久久久久| 一本大道av伊人久久综合| 欧美一区二区精品| 国产精品美女久久久久久久网站| 午夜精品久久久久久| 国产成人免费xxxxxxxx| 91麻豆精品国产91久久久久| 中文文精品字幕一区二区| 午夜精品福利一区二区三区蜜桃| 国产精品2024| 欧美精品一区二区久久久| 亚洲一级二级在线| av影院午夜一区| 久久精品人人做人人综合 | 国产精品免费视频一区| 日本亚洲免费观看| 欧美日韩国产综合久久| 亚洲欧美电影一区二区| 大白屁股一区二区视频| 26uuu久久综合| 美腿丝袜亚洲三区| 日韩欧美一区二区不卡| 丝袜诱惑亚洲看片| 欧美二区三区91| 日韩一区欧美二区| 欧美一区二区三区小说| 美腿丝袜一区二区三区| 欧美一级淫片007| 久久精品国产99| 亚洲精品一线二线三线| 国产成人午夜片在线观看高清观看| 91精品国产乱| 久久99九九99精品| 欧美激情一区二区三区在线| 成人永久aaa| 亚洲久草在线视频| 欧美图区在线视频| 日韩精品亚洲一区| 久久午夜国产精品| 国产精品一区二区免费不卡| 日本一区二区电影| 在线观看网站黄不卡| 日韩av一级片| 久久久久久亚洲综合影院红桃| 国产成人亚洲精品青草天美| 一色桃子久久精品亚洲| 91精品啪在线观看国产60岁| 精品一区二区三区影院在线午夜| 久久精品夜夜夜夜久久| 91美女视频网站| 日本午夜一区二区| 国产精品欧美综合在线| 欧美亚日韩国产aⅴ精品中极品| 蜜桃视频一区二区三区| 亚洲男女一区二区三区| 日韩欧美一区二区久久婷婷| 粉嫩蜜臀av国产精品网站| 亚洲国产美国国产综合一区二区| 久久天天做天天爱综合色| 色综合咪咪久久| 国产在线精品一区二区夜色| 亚洲精品精品亚洲| 久久久亚洲综合| 在线播放中文字幕一区| 成人免费福利片| 国产一区二区三区黄视频 | 91麻豆精品在线观看| 久久国产精品99精品国产| 亚洲欧美另类久久久精品| 国产亚洲综合色| 欧美成va人片在线观看| 欧美精品亚洲一区二区在线播放| av一本久道久久综合久久鬼色| 日韩成人精品视频| 亚瑟在线精品视频| 亚洲男人的天堂av| 亚洲欧美日韩在线播放| 中文字幕二三区不卡| 日韩欧美国产电影| 欧美丰满美乳xxx高潮www| 欧美日韩一区二区三区免费看 | 国产精品538一区二区在线| 日本不卡一区二区三区| 亚洲一区中文日韩| 亚洲精选视频在线| 最新久久zyz资源站| 国产精品毛片久久久久久久| 国产视频一区二区在线| 久久精品视频一区| 国产精品久久国产精麻豆99网站| av一区二区三区四区| 91搞黄在线观看| 国产另类ts人妖一区二区| 国产成人精品综合在线观看| 国产福利一区二区三区视频在线 | 婷婷综合另类小说色区| 天天免费综合色| 日韩电影免费在线观看网站| 青娱乐精品视频| 国产精品77777| 色综合天天在线| 国产乱人伦精品一区二区在线观看| 国产精品小仙女| 欧美无乱码久久久免费午夜一区|