86.Python——基于OpenCV的象棋棋子检测与识别

想法:能否把人工智能应用在中国象棋的对局中,实现自动检测与识别。

实现思路:个人想法,仅供参考。

1、用OpenCV霍夫圆变换检测圆形棋子,返回棋子的圆心坐标和半径。并在第一次检测时检测红黑双方共32个棋子,并保存每个棋子的图像文件,作为后面棋子识别的原始图像。

2、用OpenCV霍夫圆变换检测任意对局画面,返回对局中的所有棋子的圆心坐标注和半径,使用OpenCV提取图像特征,并进行比较,返回特征最大相似的图片,相当于完成棋子识别。

原始棋盘和所有棋子

一、棋子检测

第一次检测原始棋盘和所有棋子,并保存棋子图片,作为原始图像。

import cv2import osimport numpy as npfrom PIL import Image, ImageDraw, ImageFont#棋子检测imgpath="img/chess1.jpg"img=cv2.imread(imgpath)imgsrc=img.copy()img=cv2.resize(img,(img.shape[1]//2,img.shape[0]//2))imgsrc=cv2.resize(imgsrc,(imgsrc.shape[1]//2,imgsrc.shape[0]//2)) #检测圆形,返回圆心坐标和半径,参数为输入图像,阈值,最小半径,最大半径def detect_circle(img,threshold,min_radius,max_radius):    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)    circles=cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,1,20, param1=50,                             param2=threshold,minRadius=min_radius,maxRadius=max_radius)    circles=np.around(circles).astype(np.int).reshape(-1,3)    for i in circles:        cv2.circle(img,(i[0],i[1]),i[2],(0,255,0),2)        #画出圆心        cv2.circle(img,(i[0],i[1]),2,(0,0,255),3)    return img,circles#根据圆心和半径,返回外接矩形def get_rect(img,circles):    lstrect=[]    for i in circles:        x,y,r=i[0],i[1],i[2]        x1,y1,x2,y2=x-r,y-r,x+r,y+r        cv2.rectangle(img,(x-r,y-r),(x+r,y+r),(0,255,0),2)        lstrect.append([x1,y1,x2,y2])    return img,lstrect#保存棋子图片,作为原始数据def save_chess(img,lst:list):    for i,xy in enumerate(lst):        x1,y1,x2,y2=xy        cv2.imwrite("img/chess/chess"+str(i+1)+".jpg",imgsrc[y1:y2,x1:x2])#检测棋子_,circles=detect_circle(img,50,10,50)#获取外接矩形dst,lstrect=get_rect(imgsrc,circles)# #保存棋子图片(只运行一次)# save_chess(dst,lstrect)

检测并保存的所有棋子

二、棋子图片的特征提取与比较

#比较两张图片的特征点,返回相似度def compare_feature(img1,img2):    sift=cv2.xfeatures2d.SIFT_create()    kp1,des1=sift.detectAndCompute(img1,None)    kp2,des2=sift.detectAndCompute(img2,None)    bf=cv2.BFMatcher()    matches=bf.knnMatch(des1,des2,k=2)    good=[]    for m,n in matches:        if m.distance<0.75*n.distance:            good.append([m])    return len(good)lstname=[] #棋盘上的棋子名称for xy in lstrect:    x1,y1,x2,y2=xy    img=imgsrc[y1:y2,x1:x2]    # cv2.imshow("img",img)    # cv2.waitKey(0)    # cv2.destroyAllWindows()    lstsim=[]    for f in os.listdir("img/chess"):        #文件名包括中文        img2=cv2.imdecode(np.fromfile("img/chess/"+f,dtype=np.uint8),-1)        #img2=cv2.cvtColor(img2,cv2.COLOR_RGB2BGR)        sim=compare_feature(img,img2)        lstsim.append({f:sim})    #按照相似度排序    lstsim.sort(key=lambda x:x[list(x.keys())[0]],reverse=True)    #获取最相似的图片的棋子名称    chessname=list(lstsim[0].keys())[0].split(".")[0].split("-")[1]    lstname.append(chessname)#输出当前棋子print(len(lstname),lstname) 

待检测的棋局

#检测结果,17 ['红帅', '黑卒', '黑将', '红兵', '黑炮', '黑士', '红仕', '黑士', '红兵',    '黑马', '黑炮', '红车', '红仕', '红相', '红马', '黑车', '红相']

三、把检测文字结果放在对应的位置,比较结果是否准确

这里因为cv2不能直接显示中文,所以需转换处理一下。

#显示中文def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):    draw = ImageDraw.Draw(img)    fontText = ImageFont.truetype("font/simsun.ttc", textSize, encoding="utf-8")    draw.text((left, top), text, textColor, font=fontText)    return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)#把棋子名称根据棋子坐标放置到棋盘上def put_chess(blank,lstname,lstrect):    for i,xy in enumerate(lstrect):        x1,y1,x2,y2=xy        if lstname[i][0]=="红":            textColor=(255,0,0)        else:            textColor=(0,0,0)        blank=cv2ImgAddText(blank,lstname[i],x1,y1,textColor=textColor,textSize=20)    return blankresult=put_chess(imgsrc,lstname,lstrect)# cv2.imshow("Original",dst)cv2.imshow("Result",result)cv2.waitKey(0)cv2.destroyAllWindows()

结果图片

说明:在实际应用中,还有很多细节需要完善处理。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年4月3日
下一篇 2022年4月3日

相关推荐