This commit is contained in:
2025-12-19 06:37:19 +01:00
parent 58e19bca64
commit 9c217c0599
29 changed files with 346 additions and 2 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python3
import cv2
import numpy as np
from ultralytics import YOLO
from paths import *
def main():
model = YOLO(model_path)
# Load image
image = cv2.imread(img_path)
if image is None:
print(f"Failed to read {img_path}")
return
height, width = image.shape[:2]
warped = image # For now assume top-down view
# Run YOLO detection
results = model(warped)
res = results[0]
debug_img = res.plot() # draws boxes around detected objects
cv2.imshow("Detections", debug_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python3
from paths import *
from ultralytics import YOLO
import cv2
# Map class names to FEN characters
class_to_fen = {
'w_pawn': 'P',
'w_knight': 'N',
'w_bishop': 'B',
'w_rook': 'R',
'w_queen': 'Q',
'w_king': 'K',
'b_pawn': 'p',
'b_knight': 'n',
'b_bishop': 'b',
'b_rook': 'r',
'b_queen': 'q',
'b_king': 'k',
}
def prediction_to_fen(results, width, height):
# Initialize empty board
board = [['' for _ in range(8)] for _ in range(8)]
# Iterate through predictions
for result in results:
for box, cls in zip(result.boxes.xyxy, result.boxes.cls):
x1, y1, x2, y2 = box.tolist()
class_name = model.names[int(cls)]
fen_char = class_to_fen.get(class_name)
if fen_char:
# Compute board square
col = int((x1 + x2) / 2 / (width / 8))
row = 7 - int((y1 + y2) / 2 / (height / 8))
board[row][col] = fen_char
print(f"[{class_name}] {fen_char} {row} {col}")
# Convert board to FEN
fen_rows = []
for row in board:
fen_row = ''
empty_count = 0
for square in row:
if square == '':
empty_count += 1
else:
if empty_count > 0:
fen_row += str(empty_count)
empty_count = 0
fen_row += square
if empty_count > 0:
fen_row += str(empty_count)
fen_rows.append(fen_row)
# Join rows into a FEN string (default: white to move, all castling rights, no en passant)
fen_string = '/'.join(fen_rows) + ' w KQkq - 0 1'
return fen_string
if __name__ == "__main__":
img = cv2.imread(img_path)
height, width = img.shape[:2]
model = YOLO(model_path)
results = model.predict(source=img_path, conf=0.5)
#fen = prediction_to_fen(results, height, width)
#print("Predicted FEN:", fen)
annotated_image = results[0].plot() # Annotated image as NumPy array
cv2.namedWindow("YOLO Predictions", cv2.WINDOW_NORMAL) # make window resizable
cv2.imshow("YOLO Predictions", annotated_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

View File

@@ -0,0 +1,3 @@
model_path = "C:/Users/Laurent/Desktop/board-mate/rpi/assets/models/epoch-130.pt"
#img_path = "./test/4.jpg"
img_path = "../training/datasets/unified/train/images/WIN_20221220_11_27_27_Pro_jpg.rf.4f01cb68c8944ef1c4c7dc57847b4cd3.jpg"

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

View File

@@ -10,3 +10,6 @@ requests
python-dotenv
pyyaml
pyserial
opencv-python
numpy
ultralytics

View File

@@ -111,7 +111,7 @@ def create_char(location, pattern):
# example code
if __name__=="__main__":
setText("Hello world\nThis is an LCD test")
setText("Hello world\nThis is an LCD chesscog-bck")
setRGB(0,128,64)
time.sleep(2)
for c in range(0,255):

0
rpi/training/__init__.py Normal file
View File

6
rpi/training/chess.yaml Normal file
View File

@@ -0,0 +1,6 @@
train: C:/Users/Laurent/Desktop/board-mate/rpi/training/datasets/roboflow/labels-bck-bck-bck
val: C:/Users/Laurent/Desktop/board-mate/rpi/training/datasets/roboflow/labels-bck-bck-bck
nc: 12
names: ['w_pawn','w_knight','w_bishop','w_rook','w_queen','w_king',
'b_pawn','b_knight','b_bishop','b_rook','b_queen','b_king']

View File

@@ -0,0 +1,7 @@
train: ../train/
val: ../valid/
test: ../test/
nc: 12
names: ['w_pawn','w_knight','w_bishop','w_rook','w_queen','w_king',
'b_pawn','b_knight','b_bishop','b_rook','b_queen','b_king']

View File

@@ -0,0 +1,7 @@
train: ../train/
val: ../valid/
test: ../test/
nc: 12
names: ['w_pawn','w_knight','w_bishop','w_rook','w_queen','w_king',
'b_pawn','b_knight','b_bishop','b_rook','b_queen','b_king']

View File

@@ -0,0 +1,36 @@
import os
# --------------------------
# Configuration
# --------------------------
labels_dir = "datasets/visiope/test/labels"
# --------------------------
# Process each label file
# --------------------------
for filename in os.listdir(labels_dir):
if not filename.endswith(".txt"):
continue
txt_path = os.path.join(labels_dir, filename)
new_lines = []
with open(txt_path, "r") as f:
lines = f.readlines()
for line in lines:
parts = line.strip().split()
if len(parts) < 5:
continue # skip invalid lines
cls = int(parts[0])
cls -= 1 # subtract 1 from class index
cls = max(cls, 0) # ensure no negative indices
new_lines.append(" ".join([str(cls)] + parts[1:]))
# Overwrite file with updated indices
with open(txt_path, "w") as f:
f.write("\n".join(new_lines))
print(f"Updated {filename}")
print("All label files have been adjusted!")

70
rpi/training/labelizer.py Normal file
View File

@@ -0,0 +1,70 @@
import os
import cv2
from ultralytics import YOLO
# --------------------------
# Configuration
# --------------------------
model_path = "models/bck/best-3.pt" # your trained YOLO model
images_dir = "C:/Users/Laurent/Desktop/board-mate/rpi/training/datasets/universe/train/images"
labels_dir = "C:/Users/Laurent/Desktop/board-mate/rpi/training/datasets/universe/train/labels"
img_width = 640
img_height = 640
os.makedirs(labels_dir, exist_ok=True)
# --------------------------
# Load model
# --------------------------
model = YOLO(model_path)
# --------------------------
# Mapping YOLO class index -> piece name (optional)
# --------------------------
names = ['w_pawn','w_knight','w_bishop','w_rook','w_queen','w_king',
'b_pawn','b_knight','b_bishop','b_rook','b_queen','b_king']
# --------------------------
# Process images
# --------------------------
for img_file in os.listdir(images_dir):
if not img_file.lower().endswith((".png", ".jpg", ".jpeg")):
continue
img_path = os.path.join(images_dir, img_file)
img = cv2.imread(img_path)
if img is None:
print(f"Failed to read {img_file}")
continue
height, width = img.shape[:2]
# Run YOLO detection
results = model(img)
res = results[0]
lines = []
boxes = res.boxes.xyxy.cpu().numpy() # [x1, y1, x2, y2]
classes = res.boxes.cls.cpu().numpy()
confs = res.boxes.conf.cpu().numpy()
for box, cls, conf in zip(boxes, classes, confs):
if conf < 0.5: # skip low-confidence predictions
continue
x1, y1, x2, y2 = box
x_center = (x1 + x2) / 2 / width
y_center = (y1 + y2) / 2 / height
w_norm = (x2 - x1) / width
h_norm = (y2 - y1) / height
lines.append(f"{int(cls)} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}")
# Save YOLO .txt file with same basename as image
txt_path = os.path.join(labels_dir, os.path.splitext(img_file)[0] + ".txt")
with open(txt_path, "w") as f:
f.write("\n".join(lines))
print(f"Pre-labeled {img_file} -> {txt_path}")
print("All images have been pre-labeled!")

View File

@@ -0,0 +1,25 @@
import os
import shutil
# ----------------------------
# Configuration
# ----------------------------
source_folder = "datasets/twhpv/valid/images"
destination_folder = "datasets/_unified/valid/images"
os.makedirs(destination_folder, exist_ok=True)
# Supported image extensions
image_extensions = [".jpg", ".jpeg", ".png", ".bmp", ".gif"]
# ----------------------------
# Copy images
# ----------------------------
for filename in os.listdir(source_folder):
if any(filename.lower().endswith(ext) for ext in image_extensions):
src_path = os.path.join(source_folder, filename)
dst_path = os.path.join(destination_folder, filename)
shutil.copy2(src_path, dst_path) # copy2 preserves metadata
print(f"All images copied to '{destination_folder}'")

View File

@@ -0,0 +1,59 @@
import os
# ----------------------------
# Configuration
# ----------------------------
src_dir = "datasets/visiope/test/labels"
dest_dir = "datasets/_unified/test/labels"
os.makedirs(dest_dir, exist_ok=True)
# Reference class order you want to follow
"""[
'w_pawn','w_knight','w_bishop','w_rook','w_queen','w_king',
'b_pawn','b_knight','b_bishop','b_rook','b_queen','b_king'
]"""
reference_classes = [
'w_pawn','w_knight','w_bishop','w_rook','w_queen','w_king',
'b_pawn','b_knight','b_bishop','b_rook','b_queen','b_king'
]
# Current class order in your dataset (change this to match your dataset!)
current_classes = ['bishop', 'black-bishop', 'black-king', 'black-knight', 'black-pawn', 'black-queen', 'black-rook',
'white-bishop', 'white-king', 'white-knight', 'white-pawn', 'white-queen', 'white-rook']
# ----------------------------
# Build index mapping
# ----------------------------
index_map = {current_classes.index(cls): reference_classes.index(cls) for cls in current_classes}
# ----------------------------
# Process each label file
# ----------------------------
count = 0
for filename in os.listdir(src_dir):
if filename.endswith(".txt"):
input_path = os.path.join(src_dir, filename)
output_path = os.path.join(dest_dir, filename)
with open(input_path, "r") as f:
lines = f.readlines()
new_lines = []
for line in lines:
parts = line.strip().split()
old_idx = int(parts[0])
new_idx = index_map[old_idx]
new_lines.append(" ".join([str(new_idx)] + parts[1:]))
with open(output_path, "w") as f:
f.write("\n".join(new_lines))
if count%100 == 0:
print(count)
count += 1
print(f"All labels remapped and saved to '{dest_dir}'")

18
rpi/training/training.py Normal file
View File

@@ -0,0 +1,18 @@
from ultralytics import YOLO
def main():
model = YOLO("models/yolo11n.pt")
model.train(
data="./datasets/unified/data.yaml",
epochs=200,
patience=30,
imgsz=640,
batch=12,
device=0,
project="result",
name="unified-training",
exist_ok=True
)
if __name__ == "__main__":
main()