想法:能否把人工智能应用在中国象棋的对局中,实现自动检测与识别。
实现思路:个人想法,仅供参考。
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进行处理,非常感谢!