Chess-Vision-Backend / digitize_fen.py
heigon77's picture
Chess Vision backend (digitization + move prediction)
3f9559b
Raw
History Blame Contribute Delete
2.46 kB
#!/usr/bin/env python3
"""Full image -> FEN: exact grid + crop + transform + empty detection (binarize
center) + flipUD orientation. Compares to the known FEN for i10."""
import sys
import cv2 as cv
import numpy as np
import onnxruntime as ort
from digitize_full import get_casas, crop_square
TRUE = "rn1qkb1r/pb2pppp/5n2/1ppp4/8/3P1NP1/PPP1PPBP/RNBQ1RK1"
IDX2SYM = {0:"P",1:"N",2:"B",3:"R",4:"Q",5:"K",6:"p",7:"n",8:"b",9:"r",10:"q",11:"k"}
MEAN, STD = np.array([0.485,0.456,0.406],np.float32), np.array([0.229,0.224,0.225],np.float32)
def preprocess(bgr):
rgb = cv.cvtColor(cv.resize(bgr,(224,224)),cv.COLOR_BGR2RGB).astype(np.float32)/255.0
return ((rgb-MEAN)/STD).transpose(2,0,1)[None]
def is_empty(im, quad):
cx = int(np.mean([p[0] for p in quad])); cy = int(np.mean([p[1] for p in quad]))
w = max(6, int(0.22*(max(p[0] for p in quad)-min(p[0] for p in quad))))
patch = im[max(0,cy-w):cy+w, max(0,cx-w):cx+w]
if patch.size == 0:
return True
g = cv.cvtColor(patch, cv.COLOR_BGR2GRAY)
return g.std() < 18 # flat colour -> empty
def grid_to_fen(grid):
out=[]
for row in grid:
s=""; e=0
for cell in row:
if cell==".": e+=1
else:
if e: s+=str(e); e=0
s+=cell
if e: s+=str(e)
out.append(s)
return "/".join(out)
def main():
path = sys.argv[1] if len(sys.argv) > 1 else "samples/board.png"
im, casas = get_casas(path)
sess = ort.InferenceSession("models_onnx/digitizer3d.fp32.onnx", providers=["CPUExecutionProvider"])
syms=[]
for p in casas[:64]:
if is_empty(im, p):
syms.append("."); continue
c = crop_square(im, p)
out = sess.run(None, {"input": preprocess(c)})[0].flatten()
syms.append(IDX2SYM[int(out.argmax())])
grid = np.flipud(np.array(syms, object).reshape(8,8)) # flipUD orientation
fen = grid_to_fen(grid)
print("PRED FEN:", fen)
print("TRUE FEN:", TRUE)
T = np.array([list(r) for r in
["".join("." if ch.isdigit() and False else ch for ch in row) for row in TRUE.split("/")]], object)
# build true grid properly
tg=[]
for row in TRUE.split("/"):
rr=[]
for ch in row: rr += ["."]*int(ch) if ch.isdigit() else [ch]
tg.append(rr)
T=np.array(tg,object)
print(f"exact-cell match: {int((grid==T).sum())}/64")
if __name__ == "__main__":
main()