黄视频网站在线免费观看-黄视频网站在线看-黄视频网站在线观看-黄视频网站免费看-黄视频网站免费观看-黄视频网站免费

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

手機站
千鋒教育

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

千鋒教育

掃一掃進入千鋒手機站

領取全套視頻
千鋒教育

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

當前位置:首頁  >  技術干貨  > 用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.e7g2kmi.cn/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
国产高清视频免费观看| 色综合久久天天综合绕观看| 成人影视在线播放| 日韩中文字幕一区| 日本在线www| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 国产欧美精品| 国产综合成人观看在线| 欧美夜夜骑 青草视频在线观看完整版 久久精品99无色码中文字幕 欧美日韩一区二区在线观看视频 欧美中文字幕在线视频 www.99精品 香蕉视频久久 | 国产亚洲精品成人a在线| 欧美激情一区二区三区在线| 国产不卡在线观看| 一级女性全黄生活片免费| 日韩欧美一二三区| 成人免费观看男女羞羞视频| 亚州视频一区二区| 日韩av东京社区男人的天堂| 国产一区二区精品尤物| 四虎影视精品永久免费网站| 亚欧成人乱码一区二区| 国产不卡在线播放| 免费的黄视频| 日日夜人人澡人人澡人人看免| 精品久久久久久中文字幕一区| 亚洲 欧美 91| 人人干人人插| 久久成人亚洲| 日韩欧美一二三区| 日本特黄特黄aaaaa大片| 日韩中文字幕在线观看视频| 二级特黄绝大片免费视频大片| 午夜激情视频在线播放| 亚洲女人国产香蕉久久精品 | 日韩在线观看视频网站| 色综合久久天天综合| 精品视频一区二区三区免费| 精品视频在线观看一区二区| 亚洲精品影院久久久久久| 久久久久久久男人的天堂| 国产伦久视频免费观看视频| 成人免费观看视频| 国产一区免费观看| 99热精品一区| 99久久精品国产高清一区二区| 精品国产一区二区三区精东影业| 一级毛片视频免费| 成人影院久久久久久影院| 欧美1卡一卡二卡三新区| 精品视频在线观看视频免费视频| 四虎影视库| 色综合久久天天综合观看| 国产网站免费视频| 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 精品国产三级a∨在线观看| 麻豆系列国产剧在线观看| 欧美一级视频免费观看| 九九久久99| 国产一区二区精品| 国产高清在线精品一区a| 成人免费观看的视频黄页| 欧美爱色| 99色精品| 国产原创视频在线| 午夜在线影院| 国产一区二区精品在线观看| 免费毛片播放| 美女免费精品高清毛片在线视| 精品在线观看一区| 国产一区二区福利久久| 日韩avdvd| 欧美激情影院| 日日夜人人澡人人澡人人看免| 亚欧乱色一区二区三区| 亚洲不卡一区二区三区在线 | 91麻豆精品国产片在线观看| 午夜激情视频在线观看| 沈樵在线观看福利| 天天做人人爱夜夜爽2020毛片| 久久国产影院| 九九精品久久| 日韩一级精品视频在线观看| 成人免费观看男女羞羞视频| 九九免费精品视频| 国产麻豆精品免费视频| 亚洲 国产精品 日韩| 欧美日本免费| 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 成人影院一区二区三区| 九九久久国产精品| 久久国产精品自由自在| 九九免费高清在线观看视频| 欧美激情中文字幕一区二区| 成人影院久久久久久影院| 日本在线www| 成人a级高清视频在线观看| 日日夜夜婷婷| 午夜久久网| 国产视频一区二区在线观看| 国产激情一区二区三区| 欧美激情伊人| 青青青草视频在线观看| 日日日夜夜操| 色综合久久手机在线| 国产极品白嫩美女在线观看看| 日本在线不卡视频| 欧美激情伊人| 精品国产一区二区三区精东影业| 国产伦久视频免费观看 视频 | 天天做日日爱夜夜爽| 成人免费网站久久久| 成人av在线播放| 欧美a级片视频| 精品久久久久久中文| 黄视频网站免费观看| 国产极品精频在线观看| 国产不卡精品一区二区三区| 一本高清在线| 91麻豆精品国产高清在线| 999精品视频在线| 午夜在线亚洲男人午在线| 99久久网站| 国产成人精品影视| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 日韩中文字幕一区二区不卡| 99热精品一区| 亚洲天堂在线播放| 国产高清视频免费| 久久精品免视看国产成人2021| 日本免费看视频| 国产极品精频在线观看| 天天做日日爱| 成人在免费观看视频国产| 亚洲 欧美 91| 日本在线www| 欧美激情在线精品video| 亚欧成人毛片一区二区三区四区| 国产一区二区精品久久| 亚欧乱色一区二区三区| 国产激情视频在线观看| 九九精品在线播放| 色综合久久手机在线| 午夜欧美福利| 欧美激情一区二区三区视频| 尤物视频网站在线| 日韩中文字幕在线观看视频| 99热热久久| 国产伦精品一区二区三区在线观看| 亚洲 国产精品 日韩| 欧美爱爱动态| 欧美一区二区三区性| 黄色短视屏| 99热精品一区| 欧美日本国产| 久久精品成人一区二区三区| 欧美激情一区二区三区中文字幕| 国产国语对白一级毛片| 国产国产人免费视频成69堂| 一级毛片视频免费| 日本在线www| 午夜激情视频在线观看| 四虎影视久久久免费| 精品久久久久久中文字幕2017| 天天色成人| 国产麻豆精品视频| 日本免费乱理伦片在线观看2018| 日本乱中文字幕系列| 亚洲精品影院久久久久久| 可以免费在线看黄的网站| 国产精品自拍一区| 国产不卡高清在线观看视频| 九九国产| 精品国产三级a| 国产成人精品一区二区视频| 精品国产一区二区三区国产馆| 亚洲精品中文字幕久久久久久| 亚洲第一视频在线播放| 日日夜夜婷婷| 欧美激情一区二区三区视频| 国产亚洲男人的天堂在线观看| 成人a大片在线观看| 天堂网中文字幕| 国产成人欧美一区二区三区的| 91麻豆精品国产自产在线观看一区 | 日本在线不卡免费视频一区| 黄视频网站在线看| 香蕉视频久久| 亚洲精品中文字幕久久久久久| 精品视频在线观看一区二区三区| 黄色免费三级| 日韩专区第一页| 精品国产亚洲人成在线| 九九免费精品视频| 美国一区二区三区| 一级女性全黄久久生活片| 亚洲精品久久久中文字| 欧美日本国产| 日韩在线观看视频免费| 国产91素人搭讪系列天堂| 精品在线观看一区| 一级片片|