代码包括了棋盘与棋子的识别,初始十颗棋子的坐标标定以及棋子移动后的棋子跟踪,写的着急,有些过于冗余,当然我是选择了一个比较难的方案,就是将十字滑台放在棋盘下面,通过磁吸拖着棋子移动,路径规划部分在封箱前一小时还在挣扎,基本思路没错,调整bug的时间几乎是没有的,结果就是只能做好一题,后面的题目都需要路径规划。。。
时间短,只写了三天,没写注释,看不懂就请教GPT吧。
import cv2
import numpy as np
import heapq
img_height = 0
img_width = 0
chessNum = [[2, 2, 2],
[2, 2, 2],
[2, 2, 2]]
NUM = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
grid_centers = [[(0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0)]]
grid_coord = [[(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)],
[(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)],
[(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)]]
white_chess_center = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
black_chess_center = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
white_chess_center_fixed = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
black_chess_center_fixed = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
white_chess_center_fixed_temp = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
black_chess_center_fixed_temp = [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
path_chess_num = [[2, 2, 2, 2, 2, 2, 2],
[2, 0, 2, 2, 2, 0, 2],
[2, 0, 2, 2, 2, 0, 2],
[2, 0, 2, 2, 2, 0, 2],
[2, 2, 2, 2, 2, 2, 2]]
path_chess_num_centers = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)],
[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]]
chess_init = 0
check_init = 0
move_path = []
move_path_temp = []
outer_rect = []
board_size = 0
nextstep = 99
cap = cv2.VideoCapture(0)
def path_design(nextstep, blacknum, white_num):
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
path_chess_num = [[2, 2, 2, 2, 2, 2, 2],
[2, 0, 2, 2, 2, 0, 2],
[2, 0, 2, 2, 2, 0, 2],
[2, 0, 2, 2, 2, 0, 2],
[2, 2, 2, 2, 2, 2, 2]]
for _ in range(3):
for __ in range(3):
path_chess_num[1 + _][2 + __] = chessNum[_][__]
for i in range(3):
for j in range(3):
path_chess_num_centers[1 + i][2 + j] = grid_centers[i][j]
for i in range(5):
centerblack = black_chess_center_fixed[i]
centerw = white_chess_center_fixed[i]
path_chess_num_centers[i][0] = 0, centerblack[0]
path_chess_num_centers[i][6] = centerw[0], img_height // 5 * 3
for i in range(3):
center_up = grid_centers[1][i]
center_down = grid_centers[2][i]
path_chess_num_centers[0][2 + i] = img_height // 5 * 3, center_up[1]
path_chess_num_centers[4][2 + i] = img_height // 5 * 3, center_down[1]
path_chess_num_centers[0][1] = 150, 0
path_chess_num_centers[4][1] = 150, img_height // 5 * 3
path_chess_num_centers[0][5] = img_width // 5 * 3 - 150, 0
path_chess_num_centers[4][5] = img_width // 5 * 3 - 150, img_height // 5 * 3
if blacknum != 0 and white_num == 0:
if blacknum == 1:
start = (0, 0)
elif blacknum == 2:
start = (0, 1)
elif blacknum == 3:
start = (0, 2)
elif blacknum == 4:
start = (0, 3)
elif blacknum == 5:
start = (0, 4)
elif blacknum == 0 and white_num != 0:
if white_num == 1:
start = (6, 0)
elif white_num == 2:
start = (6, 1)
elif white_num == 3:
start = (6, 2)
elif white_num == 4:
start = (6, 3)
elif white_num == 5:
start = (6, 4)
if nextstep == 1:
goal = (1, 2)
elif nextstep == 2:
goal = (1, 3)
elif nextstep == 3:
goal = (1, 4)
elif nextstep == 4:
goal = (2, 2)
elif nextstep == 5:
goal = (2, 3)
elif nextstep == 6:
goal = (2, 4)
elif nextstep == 7:
goal = (3, 2)
elif nextstep == 8:
goal = (3, 3)
elif nextstep == 9:
goal = (3, 4)
def is_valid(x, y):
return 0 <= x < 5 and 0 <= y < 7 and path_chess_num[x][y] == 2
def heuristic(a, b):
return abs(a[0] - b[0]) + abs(a[1] - b[1])
def a_star(start, goal):
open_set = []
heapq.heappush(open_set, (0 + heuristic(start, goal), 0, start))
came_from = {}
g_score = {start: 0}
f_score = {start: heuristic(start, goal)}
while open_set:
_, current_g, current = heapq.heappop(open_set)
if current == goal:
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
return path[::-1]
for direction in directions:
neighbor = (current[0] + direction[0], current[1] + direction[1])
if not is_valid(neighbor[0], neighbor[1]):
continue
tentative_g_score = g_score[current] + 1
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
f_score[neighbor] = tentative_g_score + heuristic(neighbor, goal)
heapq.heappush(open_set, (f_score[neighbor], tentative_g_score, neighbor))
return None
paths = a_star(start, goal)
itemp = 0
if paths != None:
for i in range(len(paths)):
if itemp == 0 and blacknum != 0 and white_num == 0:
if blacknum == 1:
move_path_temp.append(black_chess_center_fixed[0])
itemp += 1
elif blacknum == 2:
move_path_temp.append(black_chess_center_fixed[1])
itemp += 1
elif blacknum == 3:
move_path_temp.append(black_chess_center_fixed[2])
itemp += 1
elif blacknum == 4:
move_path_temp.append(black_chess_center_fixed[3])
itemp += 1
elif blacknum == 5:
move_path_temp.append(black_chess_center_fixed[4])
itemp += 1
elif itemp == 0 and blacknum == 0 and white_num != 0:
if white_num == 1:
move_path_temp.append(white_chess_center_fixed[0])
itemp += 1
elif white_num == 2:
move_path_temp.append(white_chess_center_fixed[1])
itemp += 1
elif white_num == 3:
move_path_temp.append(white_chess_center_fixed[2])
itemp += 1
elif white_num == 4:
move_path_temp.append(white_chess_center_fixed[3])
itemp += 1
elif white_num == 5:
move_path_temp.append(white_chess_center_fixed[4])
itemp += 1
x, y = paths[i]
center = path_chess_num_centers[x][y]
move_path_temp.append(center)
move_path = move_path_temp
print(move_path)
for i in range(len(move_path_temp)):
move_path_temp.pop()
return move_path
def are_circles_similar(c1, c2):
x1, y1, r1 = c1
x2, y2, r2 = c2
distance = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
return distance < (r1 + r2) / 2
def detect_color_in_circle(frame, circle):
x, y, r = circle
mask = np.zeros_like(frame[:, :, 0], dtype=np.uint8)
cv2.circle(mask, (x, y), r, (255), -1)
masked_img = cv2.bitwise_and(frame, frame, mask=mask)
hsv_img = cv2.cvtColor(masked_img, cv2.COLOR_BGR2HSV)
mean_color = cv2.mean(hsv_img, mask=mask)
h, s, v = mean_color[0:3]
if s < 60 and v > 170:
return 1
else:
return 0
def detect_board_chess(frame):
global chess_init, white_chess_center, black_chess_center, check_init, grid_coord, grid_centers, NUM, chessNum, black_chess_center_fixed, white_chess_center_fixed, black_chess_center_fixed_temp, white_chess_center_fixed_temp
rectangles = []
if check_init == 0:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 50, 150, apertureSize=3)
contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 0:
return frame
for contour in contours:
if 4000 < cv2.contourArea(contour) < 60000:
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = box.astype(int)
_, (width, height), _ = rect
if 80 < width < 200 and 80 < height < 200:
duplicate = False
for existing_box, _ in rectangles:
if cv2.pointPolygonTest(existing_box, rect[0], False) >= 0:
duplicate = True
break
if not duplicate:
rectangles.append((box, rect))
if len(rectangles) != 9:
return frame
rectangles = sorted(rectangles, key=lambda r: r[1][0][1])
rows = [sorted(rectangles[i:i + 3], key=lambda r: r[1][0][0]) for i in range(0, 9, 3)]
for i, row in enumerate(rows):
for j, (box, rect) in enumerate(row):
center = (int(rect[0][0]), int(rect[0][1]))
x, y, w, h = cv2.boundingRect(box)
grid_coord[i][j] = box
grid_centers[i][j] = center
check_init += 1
if chess_init == 0:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (9, 9), 2)
circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=20, param1=50, param2=40,
minRadius=10, maxRadius=50)
if circles is not None:
circles = np.round(circles[0, :]).astype("int")
unique_circles = []
for circle in circles:
is_unique = True
for u_circle in unique_circles:
if are_circles_similar(circle, u_circle):
is_unique = False
break
if is_unique:
unique_circles.append(circle)
unique_circles = unique_circles[:10]
black_chess_num = 0
white_chess_num = 0
for (x, y, r) in unique_circles:
color = detect_color_in_circle(frame, (x, y, r))
if color == 0:
if black_chess_num <= 4:
black_chess_num += 1
black_chess_center_fixed_temp[black_chess_num - 1] = (x, y)
else:
black_chess_num = 0
elif color == 1:
if white_chess_num <= 4:
white_chess_num += 1
white_chess_center_fixed_temp[white_chess_num - 1] = (x, y)
else:
white_chess_num = 0
if black_chess_num == 5 and white_chess_num == 5:
black_chess_center_fixed = sorted(black_chess_center_fixed_temp, key=lambda piece: piece[1])
white_chess_center_fixed = sorted(white_chess_center_fixed_temp, key=lambda piece: piece[1])
chess_init += 1
if check_init == 1:
for i in range(3):
for j in range(3):
box = grid_coord[i][j]
center = grid_centers[i][j]
cv2.drawContours(frame, [box], 0, (0, 255, 0), 2)
cv2.putText(frame, str(NUM[i][j]), center, cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2, cv2.LINE_AA)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (9, 9), 2)
circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=20, param1=50, param2=40,
minRadius=10, maxRadius=50)
if circles is not None:
circles = np.round(circles[0, :]).astype("int")
unique_circles = []
for circle in circles:
is_unique = True
for u_circle in unique_circles:
if are_circles_similar(circle, u_circle):
is_unique = False
break
if is_unique:
unique_circles.append(circle)
unique_circles = unique_circles[:10]
black_chess_num = 0
white_chess_num = 0
for (x, y, r) in unique_circles:
color = detect_color_in_circle(frame, (x, y, r))
if color == 0:
if black_chess_num <= 4:
black_chess_num += 1
black_chess_center[black_chess_num - 1] = (x, y)
elif color == 1:
if white_chess_num <= 4:
white_chess_num += 1
white_chess_center[white_chess_num - 1] = (x, y)
if black_chess_num == 5 and white_chess_num == 5:
for i in range(3):
for j in range(3):
if chessNum[i][j] == 0:
for (x, y) in black_chess_center:
gx, gy = grid_centers[i][j]
distance = np.sqrt((x - gx) ** 2 + (y - gy) ** 2)
if distance > 50:
chessNum[i][j] = 2
elif chessNum[i][j] == 1:
for (x, y) in white_chess_center:
gx, gy = grid_centers[i][j]
distance = np.sqrt((x - gx) ** 2 + (y - gy) ** 2)
if distance > 50:
chessNum[i][j] = 2
for _ in range(5):
bx, by = black_chess_center[_]
cv2.circle(frame, (bx, by), 10, (0, 0, 255), -1)
for i in range(3):
for j in range(3):
gx, gy = grid_centers[i][j]
if np.sqrt((bx - gx) ** 2 + (by - gy) ** 2) < 50:
chessNum[i][j] = 0
wx, wy = white_chess_center[_]
cv2.circle(frame, (wx, wy), 10, (0, 0, 255), -1)
for i in range(3):
for j in range(3):
gx, gy = grid_centers[i][j]
if np.sqrt((wx - gx) ** 2 + (wy - gy) ** 2) < 50:
chessNum[i][j] = 1
return frame
def main():
global cap, board_size
while True:
ret, frame = cap.read()
if not ret:
break
img_height, img_width = frame.shape[:2]
x, y, w, h = img_width // 5, img_height // 5, img_width // 5 * 3, img_height // 5 * 3
roi = frame[y:y + h, x:x + w]
roi_frame = detect_board_chess(roi)
cv2.imshow('roi_frame', roi_frame)
x, y, w, h = grid_coord[0][0]
board_size = w * h
# print(chessNum)
# print(w)
# print(grid_centers[1][1])
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()