chess_moves / final.py
hash-map's picture
Upload 10 files
026baa3 verified
import chess.svg
import chess
import re
import cv2
import random as rd
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.models import load_model
import chess, chess.svg
from pathlib import Path
import webbrowser
piece_symbols = 'prbnkqPRBNKQ-'
try:
model = load_model('./chess_model.h5')
print("Model loaded successfully")
except Exception as e:
print(f"Error loading model: {e}")
def onehot_from_fen(fen):
eye = np.eye(13)
output = np.empty((0, 13))
fen = re.sub('[-]', '', fen)
for char in fen:
if(char in '12345678'):
output = np.append(output, np.tile(eye[12], (int(char), 1)), axis=0)
else:
idx = piece_symbols.index(char)
output = np.append(output, eye[idx].reshape((1, 13)), axis=0)
return output
import numpy as np
import re
def board_from_fen(fen):
board = []
fen = fen.split()[0] # just the board part (ignore turn, castling, etc.)
for row in fen.split('/'):
row_out = []
for char in row:
if char.isdigit():
# expand empty squares
row_out.extend([0] * int(char))
else:
idx = piece_symbols.index(char) + 1 # +1 so 0 = empty
row_out.append(idx)
board.append(row_out)
return np.array(board, dtype=np.int8) # shape (8,8)
def fen_from_onehot(one_hot):
output = ''
for j in range(8):
for i in range(8):
if(one_hot[j][i] == 12):
output += ' '
else:
output += piece_symbols[one_hot[j][i]]
if(j != 7):
output += '-'
for i in range(8, 0, -1):
output = output.replace(' ' * i, str(i))
return output
def order_points(pts):
# Order 4 points: top-left, top-right, bottom-right, bottom-left
rect = np.zeros((4, 2), dtype="float32")
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
def preprocess_chessboard(image_path, target_size=(30, 30)):
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
edges = cv2.Canny(blur, 50, 150)
# Find contours
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cropped_board = None
warped = None
squares = []
if contours:
cnt = max(contours, key=cv2.contourArea)
epsilon = 0.02 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
# If we found 4 corners, warp
if len(approx) == 4:
pts = approx.reshape(4,2)
rect = order_points(pts)
board_size = 256 # fixed square board
dst = np.array([
[0, 0],
[board_size-1, 0],
[board_size-1, board_size-1],
[0, board_size-1]
], dtype="float32")
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(img, M, (board_size, board_size))
cropped_board = warped
else:
# fallback: just resize whole image
warped = cv2.resize(img, (256, 256))
cropped_board = warped
else:
# no contours, fallback
warped = cv2.resize(img, (256, 256))
cropped_board = warped
# Split into 64 squares
board_size = warped.shape[0]
sq_size = board_size // 8
for row in range(8):
for col in range(8):
square = warped[row*sq_size:(row+1)*sq_size,
col*sq_size:(col+1)*sq_size]
square = cv2.resize(square, target_size)
square = square / 255.0
squares.append(square)
return np.array(squares), cropped_board
def display_with_predicted_fen(image):
squares,_ = preprocess_chessboard(image)
pred = model.predict(squares).argmax(axis=1).reshape(8, 8)
fen = fen_from_onehot(pred)
return fen
def get_board_from_image(img_path):
image = cv2.imread(img_path)
if image is None:
print('sorry image is null')
return
ext = img_path.split('.')[-1]
if not (ext=='jpg' or ext == 'jpeg' or ext == 'png'):
print('sorry image needs to be in jpg/jpeg/png format')
return
predicted_fen = display_with_predicted_fen(img_path)
# Create board from predicted FEN
board = chess.Board(predicted_fen.replace('-','/'))
return predicted_fen
def get_board_from_fen(fen:str):
print(type(fen))
fen=fen.split('-')
if len(fen)!=8:
return [[]]
answers = [[] for _ in range(8)]
map={'p':'bp','r':'bR','n':'bN','k':'bK','q':'bQ','b':'bB','P':'wp','R':'wR','N':'wN','K':'wK','Q':'wQ','B':'wB'}
for i,f in enumerate(fen):
for char in f:
if char in '12345678':
answers[i].extend(['--']*(int(char)))
elif char in piece_symbols:
answers[i].append(map[char])
return answers
def get_board(image_path):
fen_notation = get_board_from_image(image_path)
if fen_notation:
board = get_board_from_fen(fen_notation)
else:
return [[]],""
return board,fen_notation.replace('-','/')
if __name__ == "__main__":
get_board()