Как разделить контур в форме снеговика на два круга

#python #opencv #contour

#python #opencv #контур

Вопрос:

Проблема

Я обрабатываю запись с экрана iPhone автоматического воспроизведения игры под названием китайские шахматы (я нажимаю кнопку Play один раз, она автоматически повторяет все ходы). Запись на экране выполняется с частотой 30 кадров в секунду, и удобно, что каждую секунду (30 кадров) выполняется новый ход.

Например, 120-й кадр выглядит следующим образом: введите описание изображения здесь

через 30 кадров (1 секунду) 150-й кадр выглядит следующим образом: введите описание изображения здесь

Я хочу определять каждое сыгранное движение, сравнивая предыдущий кадр с текущим кадром. Мой код работает, если фигура перемещается более чем на один квадрат, но если она перемещает только один квадрат (как в этом примере выше), 2 контура сливаются вместе (выглядит как снеговик): введите описание изображения здесь (Пожалуйста, игнорируйте прямоугольники)

Это то, чего я на самом деле хочу: введите описание изображения здесь

Два отдельных круглых контура, обозначающих исходный квадрат фигуры и новый квадрат фигуры.

Обратите внимание, что из-за тени и белого кольца контур для нового квадрата больше, чем исходный квадрат Это важно, потому что это позволяет мне идентифицировать контуры с помощью cv2.contourArea

Код

 #previous_frame and current_frame are frames from cv2.VideoCapture()
imageA = previous_frame #the original square
imageB = current_frame #the new square

grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

# Structural Similarity Index (SSIM)
(score, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")

thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #I am using openCV4

cnts.sort(key=cv2.contourArea, reverse=True) #sort by decreasing order of size
cv2.drawContours(imageB, cnts, 0, (0,0,255), 10) #new coordinate is the largest contour, hence index 0
cv2.drawContours(imageA, cnts, 1, (0,0,255), 10) #original is second largest, hence index 1
  

Я пробовал использовать approxPolyDP и minEnclosingCircle , но безуспешно.

Комментарии:

1. Вы можете взглянуть на алгоритм водораздела , он кажется идеальным кандидатом для вашей проблемы…

2. @SebastianLiendo Я просмотрел документацию, и это действительно кажется идеальным алгоритмом, но пример показал вариант использования для одного изображения. В моем случае, применил бы я алгоритм к изображению diff или к изображению thresh ? (Я предполагаю, что это пороговое значение, но сравнивая код порогового значения в примере с моим, он немного отличается …)

3. Да, вам пришлось бы его немного адаптировать. Но, насколько я понимаю, вы учитываете разницу между двумя изображениями. Оттуда вы можете бинаризовать изображение diff, используя какой-то порог. Вот откуда берется контур снеговика, и из этого бинаризованного изображения вы можете затем использовать алгоритм водораздела. Не могли бы вы, возможно, загрузить изображение порога, чтобы мы могли проверить, чем он отличается?

4. Мне все еще трудно понять проблему. » путем сравнения предыдущего кадра с текущим кадром » может быть не очень хорошим выбором во многих случаях. Вы можете попробовать использовать соответствие шаблону , потому что ваши образцы кажутся подходящими для его использования

5. @YunusTemurlenk Приношу свои извинения, я не имел в виду «сравнение предыдущего кадра с текущим» , я хотел сказать «сравнение предыдущего хода с текущим ходом «. Поскольку каждый ход разделен 30 кадрами, например, если игра длится 40 ходов, будет проведено всего около 40 сравнений. Я пробовал сопоставление с шаблоном, но это не делало того, что мне было нужно.