Sofware Architecture - ObayAlshaer/ChessMentor-ML GitHub Wiki
Chessboard-to-FEN Conversion: Architecture Decisions
This document outlines the technical decisions, workflows, and reasoning behind the chessboard-to-FEN conversion system for both Chess.com digital boards and real-life chessboards.
1. Overview
The goal is to convert a photo of a chessboard into FEN notation, which can then be used by chess engines like Stockfish. The system is designed to handle two scenarios:
- Chess.com Digital Boards: Screenshots of Chess.com boards.
- Real-Life Chessboards: Photos of physical boards taken from various angles.
2. Development Workflow
Python for Training & Prototyping
- Why: Python has rich libraries for machine learning (TensorFlow, PyTorch) and computer vision (OpenCV).
- How:
- Train YOLO models using Python.
- Prototype the pipeline (grid detection, piece classification, FEN generation).
- Validate the system on synthetic and real-world data.
Swift for iOS Deployment
- Why: Swift is the native language for iOS apps, ensuring optimal performance and integration with Apple frameworks (Core ML, Vision).
- How:
- Convert trained models (YOLO, MobileNet) to Core ML or TensorFlow Lite.
- Reimplement critical logic (e.g., grid detection, FEN generation) in Swift.
- Build the user interface (UI) using SwiftUI or UIKit.
3. Why Grid Detection is Necessary
FEN notation requires exact square-level precision. Even with advanced object detection (YOLO), we need to:
- Correct Perspective: Real-life boards are rarely perfectly aligned.
- Map Pieces to Squares: Assign detected pieces to specific squares (e.g., "e4").
- Validate the Board: Ensure the board is valid (e.g., 8x8 squares, correct piece counts).
4. Workflow for Chess.com Digital Boards
Step 1: Detect Chessboard Grid
- Why: Chess.com screenshots may include UI elements or be cropped.
- How: Use OpenCV to detect the 8x8 grid.
ret, corners = cv2.findChessboardCorners(gray_image, (8, 8), None)
Step 2: Warp to Top-Down View
- Why: Standardize the board for consistent piece detection.
- How: Apply perspective transformation.
M = cv2.getPerspectiveTransform(src_pts, dst_pts) warped = cv2.warpPerspective(image, M, (800, 800))
Step 3: Detect Pieces with YOLOv11s
- Why: YOLO provides fast, accurate piece detection.
- How: Run YOLO on the warped image.
detections = yolo_model.predict(warped_image)
Step 4: Map Pieces to Squares
- Why: FEN requires piece positions relative to squares.
- How: Calculate square centers and assign pieces.
square_centers = [(i * 100 + 50, j * 100 + 50) for j in range(8) for i in range(8)] fen = ['1'] * 64 for (class_name, x, y) in detections: square_idx = np.argmin([np.sqrt((x - sx)**2 + (y - sy)**2) for (sx, sy) in square_centers]) fen[square_idx] = class_name_to_fen(class_name) # Map "white_pawn" to "P", etc.
Step 5: Generate FEN
- Why: Convert piece positions to FEN notation.
- How: Concatenate piece symbols row by row.
fen_str = '/'.join([''.join(row) for row in np.array(fen).reshape(8, 8)])
5. Workflow for Real-Life Chessboards
Step 1: Detect Chessboard Boundaries
- Why: Real-life boards may be skewed or partially visible.
- How: Use YOLO to detect the board’s rough boundaries.
Step 2: Refine Grid with OpenCV
- Why: Correct perspective distortion.
- How: Use
findChessboardCorners
to extract the 8x8 grid.ret, corners = cv2.findChessboardCorners(gray_image, (8, 8), None)
Step 3: Warp to Top-Down View
- Why: Standardize the board for consistent piece detection.
- How: Apply perspective transformation.
M = cv2.getPerspectiveTransform(src_pts, dst_pts) warped = cv2.warpPerspective(image, M, (800, 800))
Step 4: Detect Pieces with YOLOv11s
- Why: YOLO handles overlapping pieces and varying lighting.
- How: Run YOLO on the warped image.
detections = yolo_model.predict(warped_image)
Step 5: Map Pieces to Squares
- Why: FEN requires piece positions relative to squares.
- How: Calculate square centers and assign pieces.
square_centers = [(i * 100 + 50, j * 100 + 50) for j in range(8) for i in range(8)] fen = ['1'] * 64 for (class_name, x, y) in detections: square_idx = np.argmin([np.sqrt((x - sx)**2 + (y - sy)**2) for (sx, sy) in square_centers]) fen[square_idx] = class_name_to_fen(class_name) # Map "white_pawn" to "P", etc.
Step 6: Generate FEN
- Why: Convert piece positions to FEN notation.
- How: Concatenate piece symbols row by row.
fen_str = '/'.join([''.join(row) for row in np.array(fen).reshape(8, 8)])
6. Mapping Piece Names to FEN Symbols
Since the training data uses piece names (e.g., white_pawn
, black_king
), we need to map these to FEN symbols (e.g., P
, k
). Here’s the mapping logic:
def class_name_to_fen(class_name):
piece_map = {
"white_pawn": "P", "white_rook": "R", "white_knight": "N",
"white_bishop": "B", "white_queen": "Q", "white_king": "K",
"black_pawn": "p", "black_rook": "r", "black_knight": "n",
"black_bishop": "b", "black_queen": "q", "black_king": "k",
"empty": "1"
}
return piece_map.get(class_name, "1") # Default to "1" (empty) if class_name is invalid
7. Why YOLOv11s?
- Unified Pipeline: Works for both digital and real-life boards.
- Handles Overlaps: Detects overlapping pieces better than classification models.
- Real-Time Performance: Processes images in <50ms on modern devices.
8. Why OpenCV?
- Perspective Correction: Aligns skewed boards into a top-down view.
- Robust Grid Detection: Ensures accurate square-level mapping.
- Lightweight: Minimal overhead compared to ML-based grid detection.
9. Validation & Error Handling
Chess Rule Validation
- Why: Ensure the FEN is valid (e.g., correct piece counts, pawn positions).
- How: Use
python-chess
to validate FEN.import chess board = chess.Board(fen) if not board.is_valid(): raise ValueError("Invalid FEN")
Handling Non-Chessboard Photos
To ensure the app works reliably, we handle cases where the input image is not a chessboard:
1. Detection
- Use OpenCV’s
findChessboardCorners
to check for an 8x8 grid. - Validate the aspect ratio and confidence score of the detected board.
2. Feedback
- Display an error message (e.g., "No chessboard detected").
- Suggest solutions (e.g., "Try taking the photo from directly above the board").
3. Fallback Mechanisms
- Allow users to manually select chessboard corners.
- Reject low-confidence detections and prompt the user to retake the photo.
4. Testing
- Test with non-chessboard images (e.g., walls, tables, partial boards).
- Measure false positive and false negative rates.
5. Example Code
def process_image(image):
try:
# Step 1: Detect chessboard
ret, corners = cv2.findChessboardCorners(gray_image, (8, 8), None)
if not ret:
raise ValueError("Chessboard not detected")
# Step 2: Warp to top-down view
warped = warp_chessboard(image, corners)
# Step 3: Detect pieces
detections = yolo_model.predict(warped)
# Step 4: Generate FEN
fen = generate_fen(detections)
# Step 5: Validate FEN
if not validate_fen(fen):
raise ValueError("Invalid FEN")
return fen
except ValueError as e:
print(f"Error: {e}")
return None
User Feedback (Potientaly in future updates)
- Why: Allow users to correct errors (e.g., misclassified pieces).
- How: Highlight ambiguous squares in the UI and provide correction options.
10. iOS Integration
Core ML for YOLO
- Convert YOLO to Core ML for iOS deployment.
python export.py --weights yolov11n.pt --include coreml
OpenCV for Grid Detection
- Use OpenCV’s iOS framework for grid detection.
let mat = Mat(uiImage: image) let corners = [Point2f]() let found = Calib3d.findChessboardCorners(mat, patternSize: Size2i(width: 8, height: 8), corners: &corners)
11. Next Steps
- Synthetic Data Generation: Create 1k Chess.com images with FEN labels.
- Train YOLO: Fine-tune on synthetic data for digital boards.
- Test Pipeline: Validate on real Chess.com screenshots.
- Expand to Real Boards: Add perspective augmentation to synthetic data.
12. Conclusion
By combining YOLO for piece detection and OpenCV for grid alignment, we achieve a robust, scalable solution for both digital and real-life chessboards. This approach balances accuracy, speed, and flexibility, ensuring the app works reliably across diverse use cases.
13. Python-to-Swift Workflow
Training & Prototyping in Python
- Advantages:
- Rich ecosystem for machine learning (TensorFlow, PyTorch, YOLO).
- Rapid prototyping with OpenCV and Python-Chess.
- Steps:
- Train YOLO models on synthetic and real-world data.
- Prototype the pipeline (grid detection, piece classification, FEN generation).
- Validate the system on diverse datasets.
Deployment in Swift
- Advantages:
- Native iOS performance and integration with Core ML, Vision, and SwiftUI.
- Optimized for mobile devices (low latency, minimal memory usage).
- Steps:
- Convert trained models to Core ML or TensorFlow Lite.
- Reimplement critical logic (e.g., grid detection, FEN generation) in Swift.
- Build the user interface (UI) using SwiftUI or UIKit.