import cv2
import numpy as np
import kociemba
import colorsys
# Define the colors for comparison
color_ranges = [
# c h1 h2 s1 s2 invert
['O', .04, 0.12, .4, 2, False], # Orange
['R', .9, .02, .4, 2, True], # Red
['G', .33, .45, .7, 2, False], # Green
['Y', .12, .24, .5, .8, False], # Yellow
['B', .55, .61, .6, 2, False], # Blue
['W', -1, 1, -1, .4, False] # White
]
# Define the coordinates of the 9 squares on the Rubik's Cube
squares = {
1: [(100, 100), (200, 200)],
2: [(225, 100), (325, 200)],
3: [(350, 100), (450, 200)],
4: [(100, 225), (200, 325)],
5: [(225, 225), (325, 325)],
6: [(350, 225), (450, 325)],
7: [(100, 350), (200, 450)],
8: [(225, 350), (325, 450)],
9: [(350, 350), (450, 450)]
}
# Initialize the Rubik's Cube faces
rubiks_cube = {
'U': [''] * 9,
'F': [''] * 9,
'R': [''] * 9,
'B': [''] * 9,
'L': [''] * 9,
'D': [''] * 9
}
# Initialize the current face index
current_face_index = 0
faces = list(rubiks_cube.keys())
current_face = faces[current_face_index]
# Callback function for key press event
def key_press(event):
global current_face_index, current_face
if event == ord('q'):
cv2.destroyAllWindows()
elif event == ord(' '):
current_face_index += 1
if current_face_index >= len(faces):
current_face_index = 0
current_face = faces[current_face_index]
# Capture video from webcam
cap = cv2.VideoCapture(3)
print('e')
# Set the resolution of the video
cap.set(3, 640)
cap.set(4, 480)
# Flag to track if all faces are scanned
all_faces_scanned = False
while True:
# Read the current frame from the video capture
ret, frame = cap.read()
# Draw the Rubik's Cube squares overlay on the frame
for square, coords in squares.items():
x1, y1 = coords[0]
x2, y2 = coords[1]
# Extract the region of interest (square)
roi = frame[y1:y2, x1:x2]
# Calculate the average color of the square
avg_color = np.median(roi, axis=(0, 1))
# Compare the average color with the predefined colors
hsv_color = colorsys.rgb_to_hsv(avg_color[2]/255, avg_color[1]/255, avg_color[0]/255)
print(hsv_color[0])
closest_color = "aaa"
for color in color_ranges:
if not color[5]:
if color[1] < hsv_color[0] < color[2] and color[3] < hsv_color[1] < color[4]:
closest_color = color[0]
break
else:
if (hsv_color[0] > color[1] or hsv_color[0] < color[2]) and color[3] < hsv_color[1] < color[4]:
closest_color = color[0]
break
# color_diffs = [np.linalg.norm(avg_color - np.array(color)) for color in colors.values()]
# closest_color = list(colors.keys())[color_diffs.index(min(color_diffs))]
# Draw the square overlay
cv2.rectangle(frame, coords[0], coords[1], (0, 255, 0), 2)
cv2.putText(frame, closest_color, (int((x1 + x2) / 2 - 10), int((y1 + y2) / 2 + 10)),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.putText(frame, "(" + str(round(hsv_color[0] * 1000)) + ", " + str(round(hsv_color[1] * 100)) + ")",
(int((x1 + x2) / 2 - 10), int((y1 + y2) / 2 + 40)),
cv2.FONT_HERSHEY_SIMPLEX, .5, (0, 255, 0), 1)
# Store the color for the corresponding square on the current face
rubiks_cube[current_face][square - 1] = closest_color
# Display the current face on the frame
cv2.putText(frame, 'Scanning Face: ' + current_face, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# Show the frame
cv2.imshow('Rubik\'s Cube Scanner', frame)
# Wait for key press event
key = cv2.waitKey(1) & 0xFF
# Process key press event
if key != 255:
key_press(key)
# Check if 'q' key is pressed to quit
if key == ord('q'):
break
# Check if all faces are scanned
if all(rubiks_cube[face] != [''] * 9 for face in rubiks_cube):
all_faces_scanned = True
# Break the loop if all faces are scanned and current face is 'U'
if all_faces_scanned and current_face == 'U':
break
# Release the video capture and close windows
cap.release()
cv2.destroyAllWindows()
# Combine the face colors to form the cube state
cube_state = [rubiks_cube['U'], rubiks_cube['R'], rubiks_cube['F'],
rubiks_cube['D'], rubiks_cube['L'], rubiks_cube['B']]
# Map the color changes
color_mapping = {
rubiks_cube['U'][4]: 'U',
rubiks_cube['L'][4]: 'L',
rubiks_cube['F'][4]: 'F',
rubiks_cube['R'][4]: 'R',
rubiks_cube['B'][4]: 'B',
rubiks_cube['D'][4]: 'D'
}
# Convert the cube state to a single line of 54 letters without spaces
state_line = ''.join([color_mapping[color] for face in cube_state for color in face])
# Print the cube state
print(state_line)
# Define the initial state of the Rubik's Cube using the colors/pieces
initial_state = state_line
# Solve the cube using the kociemba package
solution = kociemba.solve(initial_state)
# solution = "R2 D2 F2 D2 B3 R2 B1 D3 R2 F1 L3 B2 F3 D3 L1 F3 R3 F2 D3 (19f)"
# Reformat the string into a list
final_solution = []
i = 0
while True:
# woo if statement spam
if solution[i] == "1":
final_solution[-1] += "n"
i += 2
elif solution[i] == "3":
final_solution[-1] += "p"
i += 2
elif solution[i] == "2":
final_solution[-1] += "n"
final_solution.append(final_solution[-1])
i += 2
elif solution[i] == "(":
break
else:
final_solution.append(solution[i])
i += 1
# check for edge case if final move was a normal move
if len(final_solution[-1]) == 1:
final_solution[-1] += "n"
# Print the original solution and the final solution
print("Original Solution:", solution)
print("Modified Solution: ", final_solution)