Итак, что я пытаюсь сделать, так это; с помощью веб-камеры сделайте снимок и из этого снимка извлеките положение шахматных фигур на доске и запишите их на матрицу или в список, это не имеет большого значения, потому что после этого мне просто нужно проверить движение, которое было сделанный.
Я просмотрел некоторые учебники и документацию, но я потерялся, лучшее, что я мог получить, это этот ответ, но я даже не могу получить сетку: Возможно, это из-за самой платы или даже из-за эффекта рыбьего глаза веб-камеры, которую я использую.
Это код, о котором идет речь:
import cv2
import numpy as np
def main():
im = cv2.imread('opencv_frame_0.png')
#im = cv2.resize(im, (640, 480))
#edge = cv2.imread('edge.png', 0)
edge = cv2.Canny(im, 60, 160, apertureSize=3)
lines = cv2.HoughLines(edge, 1, np.pi/180, 100, 100, 50)
for rho, theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(im, (x1, y1), (x2, y2), (0, 0, 255), 2)
# TODO: filter the lines by color and line distance
cv2.imshow('image', im)
cv2.imshow('edge', edge)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
В любом случае, даже если я смогу понять, почему cv2.HoughLines
не делает то, что я хочу, я понятия не имею, как решить проблему, получить координаты фигур на доске, какие места пусты, а в каких есть фигура.
Это оригинальное изображение из показанных выше.
Кроме того, матрица, которую я ожидал получить, была похожа на показанную в документации библиотеки chess python:
r . b q k b . r
p p p p . Q p p
. . n . . n . .
. . . . p . . .
. . B . P . . .
. . . . . . . .
P P P P . P P P
R N B . K . N R
ОБНОВЛЯТЬ
Итак, воспользовавшись советом @stateMachine, я переключился на определение цвета. Что у меня есть сейчас, используя это изображение:
Я определяю каждый угол с помощью cv2.goodFeaturesToTrack
, вот результат:
Теперь я пытаюсь получить координаты средней точки каждой клетки на шахматной доске. И, поскольку синие точки (показаны на изображении выше), заданные cv2, расположены не по порядку, я не могу напрямую использовать 4 из них и просто найти среднюю точку, например: [[254, 606], [387, 465], [519, 187], [314, 262], [172, 132], [315, 329], [179, 405], [523, 395], [246, 334], [112, 475], [519, 256], [383, 327], [382, 193], [392, 534], [596, 531], [461, 601], [238, 130], [175, 198], [452, 327], [458, 533], [525, 461], [181, 471], [40, 339], [594, 460], [381, 260], [175, 336], [43, 477], [448, 191], [454, 394], [173, 264], [518, 118], [521, 323], [245, 262], [387, 396], [245, 404], [251, 540], [42, 408], [182, 543], [36, 204], [45, 614], [590, 322], [453, 258], [45, 545], [456, 466], [307, 125], [109, 338], [600, 597], [321, 537], [592, 392], [111, 545], [106, 203], [392, 603], [107, 266], [242, 198], [38, 269], [446, 53], [585, 185], [588, 253], [114, 610], [531, 599], [99, 65], [108, 407], [309, 55], [377, 54], [33, 135], [380, 122], [30, 67], [530, 530], [449, 123], [169, 64], [182, 608], [584, 117], [250, 472], [317, 400], [313, 193], [236, 62], [103, 132], [589, 47], [515, 51], [319, 466], [321, 604]]
Итак, мой текущий подход заключается в том, чтобы найти координаты верхнего левого, правого и нижнего левого и правого углов и просто разделить расстояния, чтобы я мог пересекать линии и находить больше точек:
Теперь моя проблема; если камера не направлена прямо сверху, точки посередине на самом деле не посередине, причина в том, что из-за перспективы некоторые квадраты больше других, поэтому разделение не является надежным.
Что мне нужно сделать сейчас, так это найти 4 точки из списка, показанного выше, которые принадлежат одному и тому же квадрату, и с ними найти среднюю точку между ними, вместо того, чтобы просто выполнять деление, которое использует 4 угла доски.
Код, используемый для поиска углов (изображение только с синими точками):
import cv2
import numpy as np
def main():
frame = cv2.imread("chessboard.jpg")
cv2.namedWindow("Frame", cv2.WINDOW_NORMAL)
corners = []
corners = find_chessboard(frame)
print(corners)
cv2.waitKey(0)
cv2.destroyAllWindows()
return True
def find_chessboard(frame):
img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(img, 81, 0.01, 10)
corners = np.int0(corners)
corners_coordinates = [[]]*len(corners)
i = 0
for corner in corners:
x, y = corner.ravel()
corners_coordinates[i] = [x, y]
i = i+1
cv2.circle(frame, (x, y), 5, (255, 0, 0), -1)
cv2.imshow("Frame", frame)
return corners_coordinates
if __name__ is "__main__":
main()
Вам приходится иметь дело с хлипкой шахматной доской ручной работы, как на вашем изображении? Если это так, то нельзя ожидать, что метод, предполагающий, что линии сетки представляют собой чистые прямые линии, будет работать хорошо.
Почему изображение искажено? Было бы разумно сначала отменить «рыбий глаз» с помощью калибровки, так будет намного проще работать с плоской доской. После устранения искажений сфотографируйте доску без каких-либо шахматных фигур. Найдите четыре угла доски и соберите прямоугольник. Вы знаете, сколько квадратов составляет одну «ширину доски», и вы можете приблизительно определить расположение каждого квадрата. Затем вы можете проанализировать каждый «квадрат» и определить, присутствует ли фигура. Может подойти простой порог HSV. Теперь будет сложно распознать/классифицировать эти ярлыки, потому что персонажи даже не ориентированы должным образом.
Почему бы вам не использовать цветные точки для кодирования каждой части и вместо этого обнаружить это? Что-то вроде Pawns -> ярлык с большой зеленой красивой точкой. Слоны -> красная точка, кони -> синяя точка и т. д.
@fana хорошо, у меня нет лучшей / другой шахматной доски, поэтому я пытаюсь работать с ней.
@stateMachine искаженное изображение передается точно так же веб-камерой, которую я использую, поэтому я рассматривал возможность использования вместо этого своего мобильного телефона. Спасибо за подсказку, согласен, что работать с цветными точками будет проще, чем с буквами, если я правильно помню, opencv может давать координаты контуров, поэтому, если я смогу получить их из цветных точек вместо этого, я попробую это позже, правильно сейчас я работаю над оставшейся частью задания. Спасибо!
Хорошо, это сработало, после этого легко найти квадрат, в котором цвета находятся с помощью c2v.findContours
, cv2.contourArea()
и cv2.moments()
.
corners = find_chessboard(frame)
corners = sorted(corners, key=lambda k: [k[1], k[0]])
corners2 = []
for i in range(10):
corners2 = corners2 + sorted(corners[i*9:(i+1)*9], key=lambda k: [k[0]])
Используйте
cv2.HoughLinesP
вместоcv2.HoughLines