Я работаю над отслеживанием объектов, используя вычитание фона в opencv. Я взял образец футбольного видео, и моя цель — отследить игроков и отфильтровать более крупные отметки на поле. Из-за нестатической камеры большие линии также определяются как движущиеся, как на этом изображении:
Я использовал преобразование Хафа для обнаружения линий и после установки соответствующих пороговых значений смог отфильтровать линию на полпути, и изображение выглядело так:
Теперь я обеспокоен фильтрацией этих двух дуг.
Вопрос 1. Как я могу это сделать? Как я могу использовать разницу в «свойствах» арки (длинной и тонкой) и плеера (компактного шарика)?
Более того, функция преобразования Хафа иногда сообщает о множестве ложных срабатываний (обнаружение высокого тонкого игрока в виде прямой линии или даже подключение двух игроков для отображения более длинной линии).
Вопрос 2. Каким образом можно указать максимальную толщину линии «для обнаружения» и поддерживать строгие стандарты для обнаружения линий «только»?
Благодарю.
У меня был старый сценарий, лежащий вокруг для аналогичной функции. К сожалению, это Python и не использует функцию преобразования Хафа. Тем не менее, вы можете найти это полезным.
get_blobs
является важной функцией в то время как __main__
Это пример использования.
import cv2
def get_blobs(thresh, maxblobs, maxmu03, iterations=1):
"""Return a 2-tuple list of the locations of large white blobs.
`thresh` is a black and white threshold image.
No more than `maxblobs` will be returned.
Moments with a mu03 larger than `maxmu03` are ignored.
Before sampling for blobs, the image will be eroded `iterations` times.
"""# Kernel specifies an erosion on direct pixel neighbours.
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
# Remove noise and thin lines by eroding/dilating blobs.
thresh = cv2.erode(thresh, kernel, iterations=iterations)
thresh = cv2.dilate(thresh, kernel, iterations=iterations-1)
# Calculate the centers of the contours.
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
moments = map(cv2.moments, contours)
# Filter out the moments that are too tall.
moments = filter(lambda k: abs(k['mu03']) <= maxmu03, moments)
# Select the largest moments.
moments = sorted(moments, key=lambda k: k['m00'], reverse=True)[:maxblobs]
# Return the centers of the moments.
return [(m['m10'] / m['m00'], m['m01'] / m['m00']) for m in moments if m['m00'] != 0]
if __name__ == '__main__':
# Load an image and mark the 14 largest blobs.
image = cv2.imread('input.png')
bwImage = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
trackers = get_blobs(bwImage, 14, 50000, 3)
for tracker in trackers:
cv2.circle(image, tuple(int(x) for x in tracker), 3, (0, 0, 255), -1)
cv2.imwrite('output.png', image)
Начиная с вашего первого изображения:
Алгоритм использует эрозия отделить капли от линий.
Моменты затем используются для фильтрации высоких и маленьких капель. Моменты также используются, чтобы найти центр каждого шарика.
get_blobs
возвращает список кортежей из 2-х игроков. Вы можете видеть их нарисованными на последнем изображении.
В настоящее время сценарий действительно грязный. Не стесняйтесь использовать это непосредственно, но я отправил это главным образом, чтобы дать вам некоторые идеи.