ChessPrism/sample.py

819 lines
27 KiB
Python

def create_pgn_csv(video_list, pgn_list, output_csv_path):
# Prepare the data for the CSV
rows = [{"row_id": video, "output": pgn} for video, pgn in zip(video_list, pgn_list)]
# Write to the CSV
with open(output_csv_path, mode="w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=["row_id", "output"])
writer.writeheader()
writer.writerows(rows)
print(f"CSV file has been created at {output_csv_path}.")
import os
import cv2
import numpy as np
import glob
import matplotlib.pyplot as plt
import datetime
# DRAWING
def show_cv2_image(image, title='image'):
# plt.figure()
# plt.title(title)
# plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
cv2.imwrite(f'output/temp/{title}_{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}.png', image)
# OCR
def ocr_image(input_image, verbose=False):
"""Detects text in the file."""
from google.cloud import vision
client = vision.ImageAnnotatorClient()
content = cv2.imencode('.jpg', input_image)[1].tobytes()
image = vision.Image(content=content)
response = client.text_detection(image=image)
texts = response.text_annotations
if verbose:
print("Texts:")
for text in texts:
print(f'\n"{text.description}"')
vertices = [
f"({vertex.x},{vertex.y})" for vertex in text.bounding_poly.vertices
]
print("bounds: {}".format(",".join(vertices)))
if response.error.message:
raise Exception(
"{}\nFor more info on error messages, check: "
"https://cloud.google.com/apis/design/errors".format(response.error.message)
)
return texts
def detection_to_dict(detection):
return {
'description': detection.description,
'vertices': [
(vertex.x, vertex.y) for vertex in detection.bounding_poly.vertices
]
}
def draw_box(image, a, b, c, d):
cv2.polylines(image, [np.array([a, b, c, d], np.int32)], True, (0, 255, 0), 2)
def show_image_with_ocr(image, title='ocr result'):
result = ocr_image(image)
if len(image.shape) == 2:
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
for text in result:
text_dict = detection_to_dict(text)
vertices = text_dict['vertices']
draw_box(image, vertices[0], vertices[1], vertices[2], vertices[3])
show_cv2_image(image, title)
def show_image_with_ocr_labelled(image, title='ocr result'):
result = ocr_image(image)
if len(image.shape) == 2:
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
for text in result:
text_dict = detection_to_dict(text)
vertices = text_dict['vertices']
draw_box(image, vertices[0], vertices[1], vertices[2], vertices[3])
cv2.putText(image, text_dict['description'], vertices[0], cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
show_cv2_image(image, title)
# PROCESS IMAGE
# Function to compute the intersection of two lines
def compute_intersection(line1, line2):
rho1, theta1 = line1
rho2, theta2 = line2
# Calculate the intersection of two lines
A = np.array([[np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)]])
b = np.array([rho1, rho2])
# Solve the linear system to find the intersection point
intersection = np.linalg.solve(A, b)
return int(intersection[0]), int(intersection[1])
def draw_white_board_boundaries(image):
# Convert the image to HSV color space
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# Define the range of green color in HSV
lower_green = np.array([40, 25, 40]) # Lower bound of green in HSV
upper_green = np.array([100, 200, 200]) # Upper bound of green in HSV
# Threshold the image to get only the green color
mask = cv2.inRange(hsv, lower_green, upper_green)
# Find contours
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Create a black canvas to draw contours
contour_image = np.zeros_like(mask)
# Draw the contours on the black canvas (255 for white contours)
cv2.drawContours(contour_image, contours, -1, (255), 1)
# Apply the Canny edge detector on the contour image
edges = cv2.Canny(contour_image, 50, 150, apertureSize=3)
# Apply Hough Line Transform to find lines in the edge-detected image
lines = cv2.HoughLines(edges, 1, np.pi / 180, threshold=100)
# Separate the lines into vertical and horizontal based on their angle (theta)
vertical_lines = []
horizontal_lines = []
# Find vertical and horizontal lines
if lines is not None:
for rho, theta in lines[:, 0]:
# Identify vertical lines (theta near 0 or 180 degrees)
if np.abs(theta) < np.pi / 180 * 10 or np.abs(theta - np.pi) < np.pi / 180 * 10:
vertical_lines.append((rho, theta))
# Identify horizontal lines (theta near 90 degrees)
elif np.abs(theta - np.pi / 2) < np.pi / 180 * 10:
horizontal_lines.append((rho, theta))
# Create an empty list to store intersection points
intersection_points = []
# Find intersection points between vertical and horizontal lines
for v_line in vertical_lines:
for h_line in horizontal_lines:
intersection = compute_intersection(v_line, h_line)
intersection_points.append(intersection)
# Create an empty image to draw the intersection points
intersection_image = np.zeros_like(image)
# Draw the intersection points on the image (red points)
for point in intersection_points:
cv2.circle(intersection_image, point, 10, (0, 0, 255), -1) # Red circle at intersection points
# Convert the intersection image to grayscale
grayscale_image = cv2.cvtColor(intersection_image, cv2.COLOR_BGR2GRAY)
# Find contours of the red intersection points (non-zero pixels)
contours, _ = cv2.findContours(grayscale_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Create an empty black image to draw the center points
center_image = np.copy(image)
# List to store the center points' coordinates
center_points = []
# Iterate over each contour and find the centroid (center point)
for contour in contours:
# Calculate the moments of the contour
moments = cv2.moments(contour)
# Calculate the centroid (center) of the contour
if moments['m00'] != 0:
cx = int(moments['m10'] / moments['m00'])
cy = int(moments['m01'] / moments['m00'])
# Draw the center point (blue) on the original image
cv2.circle(center_image, (cx, cy), 5, (255, 0, 0), -1) # Blue circle at center
# Store the center coordinates in the list
center_points.append((cx, cy))
center_points = sorted(center_points, key=lambda x: sum(x))
# Step 1: Find the convex hull of the center points
center_points_np = np.array(center_points, dtype=np.int32) # Convert to NumPy array
hull = cv2.convexHull(center_points_np) # Compute convex hull
# Step 2: Create a mask for the filled polygon
mask = np.ones_like(image, dtype=np.uint8) * 255 # Create a white mask with the same dimensions as the image
cv2.fillPoly(mask, [hull], (0, 0, 0)) # Draw the filled polygon in black on the mask
image[mask == 0] = 255
result_image = image
return result_image
def process_image(image):
processed_image = draw_white_board_boundaries(image)
result = processed_image
return result
# detect chess board orientation
def bounding_box(left, top, width, height):
return [(left, top), (left + width, top), (left + width, top + height), (left, top + height)]
def draw_bounding_box(image, box, color=(0, 255, 0)):
cv2.polylines(image, [np.array(box)], isClosed=True, color=color, thickness=2)
return image
def get_board_orientation(bound_8, bound_h):
# compute the center of the two bounding boxes
center_8 = np.mean(np.array(bound_8), axis=0)
center_h = np.mean(np.array(bound_h), axis=0)
# check the relative position of the two centers
if center_8[0] < center_h[0] and center_8[1] < center_h[1]:
return 'UPRIGHT'
elif center_8[0] > center_h[0] and center_8[1] > center_h[1]:
return 'UPSIDE_DOWN'
elif center_8[0] < center_h[0] and center_8[1] > center_h[1]:
return 'ROTATED_RIGHT'
elif center_8[0] > center_h[0] and center_8[1] < center_h[1]:
return 'ROTATED_LEFT'
def detect_chessboard_orientation(image):
data = ocr_image(image)
bounds_8 = [] # sample: [(x1, y1), (x2, y2), (x3, y3), (x4, y4)]
bounds_h = [] # sample: [(x1, y1), (x2, y2), (x3, y3), (x4, y4)]
for detection in data:
data_dict = detection_to_dict(detection)
if data_dict['description'] == '8':
# store the bounding box of the 8
bounds_8.append(data_dict['vertices'])
elif data_dict['description'] == 'h':
bounds_h.append(data_dict['vertices'])
# find the closest pair of 8 and h
closest = None
for bound_8 in bounds_8:
for bound_h in bounds_h:
distance = np.linalg.norm(np.array(bound_8) - np.array(bound_h))
if closest is None or distance < closest[0]:
closest = (distance, bound_8, bound_h)
print(f'Closest pair: {closest}')
if closest is None:
return False, closest
# compute the center of the two bounding boxes
center_8 = np.mean(np.array(closest[1]), axis=0)
center_h = np.mean(np.array(closest[2]), axis=0)
# draw the line between the two points
cv2.line(image, tuple(center_8.astype(int)), tuple(center_h.astype(int)), (255, 0, 0), 2)
# draw the bounding boxes
image = draw_bounding_box(image, bound_8, (0, 255, 0))
image = draw_bounding_box(image, bound_h, (0, 0, 255))
show_cv2_image(image, "detected image")
return get_board_orientation(closest[1], closest[2]), closest
def get_k(image):
images = [image]
for i in range(3):
images.append(cv2.rotate(images[-1], cv2.ROTATE_90_CLOCKWISE))
k = 0
for i in range(4):
result = detect_chessboard_orientation(process_image(images[i]))
if result[0] and result[1]:
bound_8 = result[1][1][0]
bound_h = result[1][1][1]
# bound_8 and bound_h are in the bottom-left window of the image
h, w = images[i].shape[:2]
if bound_8[0] < w / 2 and bound_8[1] > h / 2 and bound_h[0] < w / 2 and bound_h[1] > h / 2:
k = i
break
return k
import cv2
import numpy as np
from ultralytics import YOLO
from PIL import Image
import chess
import time
import chess.pgn
import mediapipe as mp
from statistics import mode
# Define a mapping of YOLO labels to chess piece names
def label_to_piece_name(label):
piece_map = {
1: "bB", # black-bishop
2: "bK", # black-king
3: "bN", # black-knight
4: "bP", # black-pawn
5: "bQ", # black-queen
6: "bR", # black-rook
7: "wB", # white-bishop
8: "wK", # white-king
9: "wN", # white-knight
10: "wP", # white-pawn
11: "wQ", # white-queen
12: "wR" # white-rook
}
return piece_map.get(label, "?")
# Function to find intersection points of the grid lines
def find_grid(image, k=0):
# image = cv2.imread(image_path)
# Convert the image to HSV color space
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
for i in range(k):
hsv = cv2.rotate(hsv, cv2.ROTATE_90_CLOCKWISE)
# Define the range of green color in HSV (assuming green grid lines)
lower_green = np.array([40, 25, 40]) # Lower bound of green in HSV
upper_green = np.array([100, 200, 200]) # Upper bound of green in HSV
# Threshold the image to get only the green color
mask = cv2.inRange(hsv, lower_green, upper_green)
# Find contours
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Create a black canvas to draw contours
contour_image = np.zeros_like(mask)
# Draw the contours on the black canvas (255 for white contours)
cv2.drawContours(contour_image, contours, -1, (255), 1)
# Apply Canny edge detector
edges = cv2.Canny(contour_image, 50, 150, apertureSize=3)
# Apply Hough Line Transform to find lines in the edge-detected image
lines = cv2.HoughLines(edges, 1, np.pi / 180, threshold=100)
# Separate the lines into vertical and horizontal based on their angle
vertical_lines = []
horizontal_lines = []
# Find vertical and horizontal lines
if lines is not None:
for rho, theta in lines[:, 0]:
# Identify vertical lines (theta near 0 or 180 degrees)
if np.abs(theta) < np.pi / 180 * 10 or np.abs(theta - np.pi) < np.pi / 180 * 10:
vertical_lines.append((rho, theta))
# Identify horizontal lines (theta near 90 degrees)
elif np.abs(theta - np.pi / 2) < np.pi / 180 * 10:
horizontal_lines.append((rho, theta))
# Create an empty list to store intersection points
intersection_points = []
# Function to compute the intersection of two lines
def compute_intersection(line1, line2):
rho1, theta1 = line1
rho2, theta2 = line2
A = np.array([[np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)]])
b = np.array([rho1, rho2])
# Solve the linear system to find the intersection point
intersection = np.linalg.solve(A, b)
return int(intersection[0]), int(intersection[1])
# Find intersection points between vertical and horizontal lines
for v_line in vertical_lines:
for h_line in horizontal_lines:
intersection = compute_intersection(v_line, h_line)
intersection_points.append(intersection)
return intersection_points
# Function to map detected chess pieces to the board using intersection points
def map_yolo_results_to_chessboard(results, chessboard_corners):
"""
Maps YOLO detection results to a chessboard grid.
Args:
- results: YOLO detection results containing labels and bounding boxes.
- chessboard_corners: List of tuples [(x1, y1), (x2, y2), ..., (x4, y4)]
representing the corners of the chessboard
(top-left, top-right, bottom-left, bottom-right).
Returns:
- A formatted string representation of the chessboard with mapped pieces.
"""
# Extract the chessboard corners
top_left, top_right, bottom_left, bottom_right = chessboard_corners
# Calculate the width and height of each cell
cell_width = (top_right[0] - top_left[0]) / 8
cell_height = (bottom_left[1] - top_left[1]) / 8
# Initialize an empty 8x8 chessboard
board = [['' for _ in range(8)] for _ in range(8)]
# Process YOLO results
for r in results:
boxes = r.boxes.xywh.numpy() # Bounding boxes in (x_center, y_center, width, height)
labels = r.boxes.cls.numpy() # Class indices
for box, label in zip(boxes, labels):
x_center, y_center, _, _ = box
piece_name = label_to_piece_name(int(label))
# Determine the row and column based on the center point
col = int((x_center - top_left[0]) / cell_width)
row = int((y_center - top_left[1]) / cell_height)
# Ensure row and col are within bounds
if 0 <= row < 8 and 0 <= col < 8:
board[row][col] = piece_name
# Format the board for display
formatted_board = '\n'.join([' '.join([cell if cell else '--' for cell in row]) for row in board])
return formatted_board
def convert_to_valid_fen(board_string):
# Mapping of custom pieces to FEN standard pieces
piece_mapping = {
"wP": "P", "wR": "R", "wN": "N", "wB": "B", "wQ": "Q", "wK": "K",
"bP": "p", "bR": "r", "bN": "n", "bB": "b", "bQ": "q", "bK": "k",
"--": "1" # Empty squares
}
# Split the input string into rows
rows = board_string.strip().split("\n")
fen_rows = []
for row in rows:
squares = row.split() # Split the row into individual squares
fen_row = ""
for square in squares:
fen_row += piece_mapping.get(square, square) # Replace with mapped value
# Compress consecutive digits (empty spaces) into single numbers
compressed_row = ""
empty_count = 0
for char in fen_row:
if char.isdigit(): # Count empty squares
empty_count += int(char)
else:
if empty_count > 0:
compressed_row += str(empty_count)
empty_count = 0
compressed_row += char
if empty_count > 0:
compressed_row += str(empty_count) # Add remaining empty squares
fen_rows.append(compressed_row)
# Combine rows with "/" and add default metadata
fen_board = "/".join(fen_rows)
fen_metadata = " w - - 0 1" # White to move, no castling, no en passant
return fen_board + fen_metadata
def rotate_fen(fen):
# Split the FEN into board state and other details
board, *rest = fen.split(' ')
# Split the board into rows
rows = board.split('/')
# Rotate each row (reverse the pieces) and then reverse the row order
rotated_rows = [''.join(reversed(row)) for row in reversed(rows)]
# Recombine the rows into the rotated FEN
rotated_board = '/'.join(rotated_rows)
# Combine the rotated board with the rest of the FEN details
return ' '.join([rotated_board] + rest)
def convert_to_san(moves):
san_moves = []
move_number = 1
for i in range(0, len(moves), 2):
if i + 1 < len(moves):
# Pair moves for each turn
san_moves.append(f"{move_number}. {moves[i]} {moves[i+1]}")
else:
# If there's an odd move at the end, only record that
san_moves.append(f"{move_number}. {moves[i]}")
move_number += 1
return " ".join(san_moves)
def get_chessboard_corners(image, k=0):
coor = find_grid(image, k)
coor = sorted(coor, key=lambda x: sum(x))
min = coor[0]
max = coor[-1]
chessboard_corners = [(min[0], min[1]), (max[0], min[1]), (min[0], max[1]), (max[0], max[1])]
return chessboard_corners
def board_list_to_list(board_list):
output = [[[],[],[],[],[],[],[],[]],
[[],[],[],[],[],[],[],[]],
[[],[],[],[],[],[],[],[]],
[[],[],[],[],[],[],[],[]],
[[],[],[],[],[],[],[],[]],
[[],[],[],[],[],[],[],[]],
[[],[],[],[],[],[],[],[]],
[[],[],[],[],[],[],[],[]]]
for board in board_list:
board_splitR = board.split("\n")
for r,board_row in enumerate(board_splitR):
board_pos = board_row.split(" ")
for c,piece in enumerate(board_pos):
output[r][c].append(piece)
for r,row in enumerate(output):
for c,col in enumerate(row):
output[r][c] = mode(col)
return output
def board_to_pgn(prev_b, curr_b):
board_pos_coor = [['a8', 'b8', 'c8', 'd8', 'e8', 'f8','g8','h8'],
['a7', 'b7', 'c7', 'd7', 'e7', 'f7','g7','h7'],
['a6', 'b6', 'c6', 'd6', 'e6', 'f6','g6','h6'],
['a5', 'b5', 'c5', 'd5', 'e5', 'f5','g5','h5'],
['a4', 'b4', 'c4', 'd4', 'e4', 'f4','g4','h4'],
['a3', 'b3', 'c3', 'd3', 'e3', 'f3','g3','h3'],
['a2', 'b2', 'c2', 'd2', 'e2', 'f2','g2','h2'],
['a1', 'b1', 'c1', 'd1', 'e1', 'f1','g1','h1']]
# Find the coordinates of the changed piece
moved_from = None
moved_to = None
for row in range(8):
for col in range(8):
if prev_b[row][col] != curr_b[row][col]:
if curr_b[row][col] == '.':
# The piece moved from this square
moved_from = (row, col)
else:
# The piece moved to this square
moved_to = (row, col)
if moved_from is None or moved_to is None:
return "No valid move found", False # In case of invalid input
# Convert coordinates to chess notation
from_square = board_pos_coor[moved_from[0]][moved_from[1]]
to_square = board_pos_coor[moved_to[0]][moved_to[1]]
moved_piece = prev_b[moved_from[0]][moved_from[1]]
if moved_piece.islower(): # black move
if prev_b[moved_to[0]][moved_to[1]] != '.': # black capture
if moved_piece == 'p':
pgn = f"{board_pos_coor[moved_from[0]][moved_from[1]][0]}x{to_square}" # black pawn capture
else:
pgn = f"{moved_piece.upper()}x{to_square}" #black non pawn capture
else: # not capture
if moved_piece == 'p':
moved_piece = ""
else:
moved_piece = moved_piece.upper()
pgn = f"{moved_piece}{to_square}" # Regular pawn move
else: # white
if prev_b[moved_to[0]][moved_to[1]] != '.': # capture
if moved_piece == 'P':
pgn = f"{board_pos_coor[moved_from[0]][moved_from[1]][0]}x{to_square}" # capture
else:
pgn = f"{moved_piece}x{to_square}"
else: # not capture
if moved_piece == 'P':
pgn = f"{to_square}" # Regular piece move
else:
pgn = f"{moved_piece}{to_square}" # Regular pawn move
is_white = prev_b[moved_from[0]][moved_from[1]].isupper()
return pgn, is_white
def gen_pgn(vid_path, model):
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(static_image_mode=False, max_num_hands=2, min_detection_confidence=0.5)
# mp_drawing = mp.solutions.drawing_utils
cap = cv2.VideoCapture(vid_path)
# Parameters for frame processing
frame_count = 0
frame_interval = int(float(cap.get(cv2.CAP_PROP_FPS)) * 0.5) # Process frame every 1 second
# previous_board = None # Track the previous board state
# previous_hand_present = False # Track if a hand was detected in the previous frame
# list of board list; appends the board_lists
board_list_list = []
# board list iterate every time hand is present
board_list = []
# get one frame
print('getting k from gen_pgn')
k = get_k(cap.read()[1])
while cap.isOpened():
ret, frame = cap.read()
if not ret:
if len(board_list) != 0:
board_list_list.append(board_list)
board_list = []
break # End of video
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Perform hand detection
hand_results = hands.process(rgb_frame)
not_hand_present = hand_results.multi_hand_landmarks == None
# Crop the frame
frame = frame[425:1495, :]
for i in range(k):
frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
# Process frame every frame_interval
if frame_count % frame_interval == 0:
if not_hand_present:
results = model(frame, conf=0.3)
chessboard_corners = get_chessboard_corners(frame, k)
formatted_board = map_yolo_results_to_chessboard(results, chessboard_corners)
fen = convert_to_valid_fen(formatted_board)
fen = rotate_fen(fen)
current_board = chess.Board(fen)
#print('board')
board_list.append(str(current_board)[1:-1])
elif not not_hand_present or not ret:
#print('hand')
if len(board_list) != 0:
board_list_list.append(board_list)
board_list = []
# Increment frame counter
frame_count += 1
#san_notation = convert_to_san(['..'] + san_move)
# print(san_notation)
# cap.release()
# cv2.destroyAllWindows()
# print(board_list_list)
# print(len(board_list_list))
# print(board_list_list[0])
# print(board_list_list[1])
# print(board_list_list[2])
for i,b_list in enumerate(board_list_list):
print(b_list)
new_board_list = board_list_to_list(b_list)
board_list_list[i] = new_board_list
print(str(new_board_list)+"\n\n")
pgn_index = 1
white_move = ".."
black_move = ".."
pgn_all = [""]
for i in range(len(board_list_list) - 1):
p_board = board_list_list[i]
c_board = board_list_list[i + 1]
pgn, is_white = board_to_pgn(prev_b=p_board, curr_b=c_board)
if is_white:
white_move = pgn
else:
black_move = pgn
pgn_row = f"{pgn_index}. {white_move} {black_move} "
if is_white or (not is_white and black_move != ".."):
if len(pgn_all) < pgn_index:
pgn_all.append(pgn_row)
else:
pgn_all[pgn_index - 1] = pgn_row
if black_move != "..":
white_move = ".."
black_move = ".."
pgn_index += 1
out_str = ""
for r in pgn_all:
out_str += r
if out_str == "":
return '1. '
return out_str
# # Initialize Mediapipe Hands
# mp_hands = mp.solutions.hands
# hands = mp_hands.Hands(static_image_mode=False, max_num_hands=2, min_detection_confidence=0.5)
# mp_drawing = mp.solutions.drawing_utils
# 1. .. move 2. move ..
# Load the YOLO model
model = YOLO("best2.pt") # Replace with the path to your trained YOLO model
# image_path = "detection/test2.jpg"
# image = cv2.imread(image_path)
video_path_2m = "kaggle/input/2_move_student.mp4" # Replace with the path to your video
video_path_4m = "kaggle/input/4_Move_studet.mp4" # Replace with the path to your video
video_path_6m = "kaggle/input/6_Move_student.mp4" # Replace with the path to your video
video_path_8m = "kaggle/input/8_Move_student.mp4" # Replace with the path to your video
video_path_2mr = "kaggle/input/2_Move_rotate_student.mp4"
video_path_list = [video_path_2mr, video_path_2m, video_path_4m, video_path_6m, video_path_8m]
output_path = "output/output_video.avi" # Optional: Specify a path to save the output video
# for vidp in vidp_list:
# for vidp in video_path_list:
# gen_pgn(vidp, model)
# print(gen_pgn(video_path_4m, model))
# Release resources
#R . B . Q . . R
#P P K . . P . P
#. . . . . N . .
#q . . P . . P .
#. . . p P . . n
#. . . . p . . .
#. p . . b p p p
#R n b k . . . .
#R . B . Q . . R
#P . K . . P . P
#. P . . . N . .
#q . . P . . P .
#. . . p P . . n
#. . . . p . . .
#. p . . b p p p
#R n b k . . . .
pgn = []
for path in video_path_list:
pgn.append(gen_pgn(path, model))
print(pgn)
import pandas as pd
vids = ['2_Move_rotate_student.mp4','2_move_student.mp4','4_Move_studet.mp4','6_Move_student.mp4','8_Move_student.mp4', '(Bonus)Long_video_student.mp4']
print(len(pgn), len(vids))
if len(pgn) < len(vids):
pgn.append('1.')
# pgn.append('1.')
df = pd.DataFrame({
"row_id": vids,
"output": pgn
})
# Save to CSV
df.to_csv("kaggle/working/submission.csv", index=False, encoding="utf-8")