目錄
- 1、將棋盤分割成19x19的小方格
- 2、根據(jù)像素占比識(shí)別是否是黑色棋子
- 3、根據(jù)像素占比識(shí)別是否是白色棋子
- 4、將棋盤棋子位置通過列表表示
- 完整代碼如下:
這一篇主要實(shí)現(xiàn)定位棋子位置及識(shí)別棋子顏色。
圍棋棋盤原圖如下:
經(jīng)過上一章節(jié)處理,已經(jīng)將棋盤位置找到,如下圖:
現(xiàn)在根據(jù)新圖,進(jìn)行棋子位置的定位
1、將棋盤分割成19x19的小方格
為了定位出棋盤每個(gè)交叉點(diǎn)上,是否有棋子,需要將棋盤分割成19X19的小方格,由于圍棋棋盤每個(gè)交叉線直接距離相同,是矩形,因此分割成小方格十分容易,如下圖:
若想將棋盤分割成19x19的小方格,需要知道以下幾個(gè)參數(shù)。
small_length=38 #每個(gè)小格寬高
qizi_zhijing=38#棋子直徑
zuoshangjiao=20#棋盤四周的寬度
這些可以使用imagewathch(VS下opencv的插件)工具,方便的知道,這個(gè)工具可以實(shí)時(shí)查看圖像的寬高,某個(gè)位置的像素值。這個(gè)工具的使用可以看我另外一篇文章:opencv用VS2013調(diào)試時(shí)用Image Watch插件查看圖片,代替一堆數(shù)據(jù),直觀很多。
下面是將原圖分割成19X19小方格的代碼
img = cv2.imread("src.jpg")
cv2.imshow("src",img)
#變量定義
small_length=38 #每個(gè)小格寬高
qizi_zhijing=38#棋子直徑
zuoshangjiao=20#棋盤四周的寬度
for i in range(19):
for j in range(19):
#print(i,j)
lie = i
hang = j
Tp_x = small_length * lie
Tp_y = small_length * hang
Tp_width = qizi_zhijing
Tp_height = qizi_zhijing
#測試用
cv2.rectangle(img, (Tp_x, Tp_y), (Tp_x + Tp_width, Tp_y + Tp_height),(255, 0, 0), 2)
cv2.imwrite('img.jpg', img)
img_temp=img[Tp_y:Tp_y+Tp_height, Tp_x:Tp_x+Tp_width]#參數(shù)含義分別是:y、y+h、x、x+w
cv2.imwrite('img_temp3.jpg', img_temp)
cv2.imshow("3", img_temp)
cv2.waitKey(20)
2、根據(jù)像素占比識(shí)別是否是黑色棋子
上面三種圖像是我們分割成小方格后的三種主要形態(tài),分別代表黑色棋子,白色棋子以及無棋子。其中黑色棋子最好查找,我們將圖像進(jìn)行灰度化——二值化后,通過統(tǒng)計(jì)黑色像素占比超過一定數(shù)值,就能知道該處是否有黑色棋子。
這里我將統(tǒng)計(jì)黑色占比的代碼,封裝成了一個(gè)函數(shù),如下;
""" "*******************************************************************************************
*函數(shù)功能 :統(tǒng)計(jì)二值化圖片黑色像素點(diǎn)百分比
*輸入?yún)?shù) :輸入裁剪后圖像,
*返 回 值 :返回黑色像素點(diǎn)占比0-1之間
*編寫時(shí)間 : 2021.6.30
*作 者 : diyun
********************************************************************************************"""
def Heise_zhanbi(img):
[height, width, tongdao] = img.shape
#print(width, height, tongdao)
# cv2.imshow("3", img)
# cv2.waitKey(20)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imshow("binary", gray)
# cv2.waitKey(100)
etVal, threshold = cv2.threshold(gray, 125, 255, cv2.THRESH_BINARY)
# cv2.imshow("threshold", threshold)
# cv2.waitKey(200)
a = 0
b = 0
counter = 0#;/*目標(biāo)像素點(diǎn)個(gè)數(shù)*/
zhanbi = 0#;/*目標(biāo)像素點(diǎn)比值*/
for row in range(height):
for col in range(width):
val = threshold[row][col]
if (val) == 0:#黑色
a = a + 1
else:
b = b + 1
zhanbi = (float)(a) / (float)(height*width)
#print("黑色像素個(gè)數(shù)", a, "黑色像素占比", zhanbi)
return zhanbi
3、根據(jù)像素占比識(shí)別是否是白色棋子
同樣的,我們可以統(tǒng)計(jì)像素中白色占比,來進(jìn)行識(shí)別該位置是否是白色棋子,但是這里需要注意一個(gè)問題,如果按照上面黑色棋子識(shí)別方法進(jìn)行灰度化、二值化會(huì)造成白色棋子和無棋子分辨不了,二者都有大面積的白色,因此這里需要調(diào)整二值化的閾值,分開無棋子和白色棋子的圖像。
封裝好的代碼如下:
""" "*******************************************************************************************
*函數(shù)功能 :統(tǒng)計(jì)二值化圖片白色像素點(diǎn)百分比
*輸入?yún)?shù) :輸入裁剪后圖像,
*返 回 值 :返回白色像素點(diǎn)占比0-1之間
*編寫時(shí)間 : 2021.6.30
*作 者 : diyun
********************************************************************************************"""
def Baise_zhanbi(img):
[height, width, tongdao] = img.shape
#print(width, height, tongdao)
# cv2.imshow("3", img)
# cv2.waitKey(20)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imshow("binary", gray)
# cv2.waitKey(100)
etVal, threshold = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
# cv2.imshow("threshold", threshold)
# cv2.waitKey(200)
a = 0
b = 0
counter = 0#;/*目標(biāo)像素點(diǎn)個(gè)數(shù)*/
zhanbi = 0#;/*目標(biāo)像素點(diǎn)比值*/
for row in range(height):
for col in range(width):
val = threshold[row][col]
if (val) == 0:#黑色
a = a + 1
else:
b = b + 1
zhanbi = (float)(b) / (float)(height*width)
#print("白色像素個(gè)數(shù)", b, "白色像素占比", zhanbi)
return zhanbi
效果圖如下:
4、將棋盤棋子位置通過列表表示
我們新建一個(gè)19*19的列表來存儲(chǔ)棋子,列表中:
0:代表無棋子
1:代表白色
2:代表黑色
代碼如下:
list = [[0 for i in range(19)] for j in range(19)]
當(dāng)為黑色棋子時(shí):
list[hang][lie]=2#黑色
#print("當(dāng)前棋子為黑色")
print("第", i, "行,第", j, "列棋子為黑色:", i, j)
當(dāng)為白色棋子時(shí):
list[hang][lie] = 1 # 白色
#print("當(dāng)前棋子為白色")
print("第", i, "行,第", j, "列棋子為白色:", i, j)
效果圖如下:
完整代碼如下:
from PIL import ImageGrab
import numpy as np
import cv2
from glob import glob
import os
import time
#Python將數(shù)字轉(zhuǎn)換成大寫字母
def getChar(number):
factor, moder = divmod(number, 26) # 26 字母個(gè)數(shù)
modChar = chr(moder + 65) # 65 -> 'A'
if factor != 0:
modChar = getChar(factor-1) + modChar # factor - 1 : 商為有效值時(shí)起始數(shù)為 1 而余數(shù)是 0
return modChar
def getChars(length):
return [getChar(index) for index in range(length)]
""" "*******************************************************************************************
*函數(shù)功能 :統(tǒng)計(jì)二值化圖片黑色像素點(diǎn)百分比
*輸入?yún)?shù) :輸入裁剪后圖像,
*返 回 值 :返回黑色像素點(diǎn)占比0-1之間
*編寫時(shí)間 : 2021.6.30
*作 者 : diyun
********************************************************************************************"""
def Heise_zhanbi(img):
[height, width, tongdao] = img.shape
#print(width, height, tongdao)
# cv2.imshow("3", img)
# cv2.waitKey(20)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imshow("binary", gray)
# cv2.waitKey(100)
etVal, threshold = cv2.threshold(gray, 125, 255, cv2.THRESH_BINARY)
# cv2.imshow("threshold", threshold)
# cv2.waitKey(200)
a = 0
b = 0
counter = 0#;/*目標(biāo)像素點(diǎn)個(gè)數(shù)*/
zhanbi = 0#;/*目標(biāo)像素點(diǎn)比值*/
for row in range(height):
for col in range(width):
val = threshold[row][col]
if (val) == 0:#黑色
a = a + 1
else:
b = b + 1
zhanbi = (float)(a) / (float)(height*width)
#print("黑色像素個(gè)數(shù)", a, "黑色像素占比", zhanbi)
return zhanbi
""" "*******************************************************************************************
*函數(shù)功能 :統(tǒng)計(jì)二值化圖片白色像素點(diǎn)百分比
*輸入?yún)?shù) :輸入裁剪后圖像,
*返 回 值 :返回白色像素點(diǎn)占比0-1之間
*編寫時(shí)間 : 2021.6.30
*作 者 : diyun
********************************************************************************************"""
def Baise_zhanbi(img):
[height, width, tongdao] = img.shape
#print(width, height, tongdao)
# cv2.imshow("3", img)
# cv2.waitKey(20)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imshow("binary", gray)
# cv2.waitKey(100)
etVal, threshold = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
# cv2.imshow("threshold", threshold)
# cv2.waitKey(200)
a = 0
b = 0
counter = 0#;/*目標(biāo)像素點(diǎn)個(gè)數(shù)*/
zhanbi = 0#;/*目標(biāo)像素點(diǎn)比值*/
for row in range(height):
for col in range(width):
val = threshold[row][col]
if (val) == 0:#黑色
a = a + 1
else:
b = b + 1
zhanbi = (float)(b) / (float)(height*width)
#print("白色像素個(gè)數(shù)", b, "白色像素占比", zhanbi)
return zhanbi
""" "*******************************************************************************************
*函數(shù)功能 :定位棋盤位置
*輸入?yún)?shù) :截圖
*返 回 值 :裁剪后的圖像
*編寫時(shí)間 : 2021.6.30
*作 者 : diyun
********************************************************************************************"""
def dingweiqizi_weizhi(img):
'''********************************************
1、定位棋盤位置
********************************************'''
#img = cv2.imread("./screen/1.jpg")
image = img.copy()
w, h, c = img.shape
img2 = np.zeros((w, h, c), np.uint8)
img3 = np.zeros((w, h, c), np.uint8)
# img = ImageGrab.grab() #bbox specifies specific region (bbox= x,y,width,height *starts top-left)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([10, 0, 0])
upper = np.array([40, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
erodeim = cv2.erode(mask, None, iterations=2) # 腐蝕
dilateim = cv2.dilate(erodeim, None, iterations=2)
img = cv2.bitwise_and(img, img, mask=dilateim)
frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, dst = cv2.threshold(frame, 100, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(dst, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
#cv2.imshow("0", img)
i = 0
maxarea = 0
nextarea = 0
maxint = 0
for c in contours:
if cv2.contourArea(c) > maxarea:
maxarea = cv2.contourArea(c)
maxint = i
i += 1
# 多邊形擬合
epsilon = 0.02 * cv2.arcLength(contours[maxint], True)
if epsilon 1:
print("error : epsilon 1")
pass
# 多邊形擬合
approx = cv2.approxPolyDP(contours[maxint], epsilon, True)
[[x1, y1]] = approx[0]
[[x2, y2]] = approx[2]
checkerboard = image[y1:y2, x1:x2]
# cv2.imshow("1", checkerboard)
# cv2.waitKey(1000)
#cv2.destroyAllWindows()
return checkerboard
""" "*******************************************************************************************
*函數(shù)功能 :定位棋子顏色及位置
*輸入?yún)?shù) :裁剪后的圖像
*返 回 值 :棋子顏色及位置列表
*編寫時(shí)間 : 2021.6.30
*作 者 : diyun
********************************************************************************************"""
def dingweiqizi_yanse_weizhi(img):
'''********************************************
2、識(shí)別棋盤棋子位置及顏色及序號;
********************************************'''
#img = cv2.imread("./checkerboard/checkerboard_1.jpg")
img = cv2.resize(img, (724,724), interpolation=cv2.INTER_AREA)
#cv2.imshow("src",img)
#cv2.waitKey(1000)
#變量定義
small_length=38 #每個(gè)小格寬高
qizi_zhijing=38#棋子直徑
zuoshangjiao=20#棋盤四周的寬度
list = [[0 for i in range(19)] for j in range(19)]
#print(list)
for i in range(19):
for j in range(19):
lie = i
hang = j
Tp_x = small_length * lie
Tp_y = small_length * hang
Tp_width = qizi_zhijing
Tp_height = qizi_zhijing
img_temp=img[Tp_y:Tp_y+Tp_height, Tp_x:Tp_x+Tp_width]#參數(shù)含義分別是:y、y+h、x、x+w
heise_zhanbi=Heise_zhanbi(img_temp)
if heise_zhanbi>0.5:
list[hang][lie]=2#黑色
print("第", j+1, "行,第", i+1, "列棋子為黑色")
#print("當(dāng)前棋子為黑色")
else:
baise_zhanbi = Baise_zhanbi(img_temp)
if baise_zhanbi > 0.15:
list[hang][lie] = 1 # 白色
print("第", j+1, "行,第",i+1 , "列棋子為白色")
#print("當(dāng)前棋子為白色")
else:
list[hang][lie] = 0 # 無棋子
#print("當(dāng)前位置沒有棋子")
#print(heise_zhanbi)
#cv2.imshow("2",img)
#print("\n")
#print(list)
return list
if __name__ =="__main__":
list0 = [[0 for i in range(19)] for j in range(19)]
list_finall = []
img = cv2.imread("./screen/9.jpg")
'''********************************************
1、定位棋盤位置
********************************************'''
img_after=dingweiqizi_weizhi(img)
#cv2.imshow("src",img)
'''********************************************
2、識(shí)別棋盤棋子位置及顏色及序號;
********************************************'''
list1=dingweiqizi_yanse_weizhi(img_after)
print(list1)
到此這篇關(guān)于基于python定位棋子位置及識(shí)別棋子顏色的文章就介紹到這了,更多相關(guān)python定位棋子位置及識(shí)別棋子顏色內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!