Identificação do campo

A delimitação do campo é feita por meio de ArUcos distribuídos nas 4 extremidades do retângulo que forma a área de jogo. Esses ArUcos são identificados pelo método cv2.aruco.detectMarkers.

Para obter um campo retangular que independa da posição da câmera, é calculada uma matrix M de transformação de perspectiva (pelo método cv2.getPerspectiveTransform) que transpõe os pontos do campo para uma nova referência. Nessa referência os ArUcos são as extremidades de um retângulo e é nela que são feitos todos os cálculos sobre o movimento da bola. 

Por último a imagem é resultante é transformada novamente para a perspectiva original apenas para 

Na imagem e vídeos abaixo é possível perceber esse processo. No vídeo o processo se torna mais visível conforme a posição de um dos ArUcos é alterada, o que também afeta a transformação realizada, mas não o tamanho do campo.

Código que implementa a delimitação do campo

field_delimited = False


# Transformation matrix for the homography

M = None

max_width = None

max_height = None


# Relevant corners for the homography

corners, ids = None, None

top_left_corner = None

bottom_right_corner = None

top_right_corner = None

bottom_left_corner = None


# Configuring the ArUco detector

aruco_dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250)

parameters =  cv2.aruco.DetectorParameters()

detector = cv2.aruco.ArucoDetector(aruco_dict, parameters)


ax.set_title("Identifying the ArUcos", color='gray', fontsize=10)


while not field_delimited:

    succes, frame = cap.read()


    # Undistorting the frame from the camera

    dst = cv2.undistort(frame, cameraMatrix, dist, None, newCameraMatrix)

    frame = dst[roi[1]:roi[1]+roi[3], roi[0]:roi[0]+roi[2]]

    output_frame = dst.copy()

   

    # First we make the image monochromatic

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)


    # Then we detect the arucos

    corners, ids, rejectedImgPoints = detector.detectMarkers(gray)

    frame_markers = cv2.aruco.drawDetectedMarkers(frame.copy(), corners, ids)

    corners = np.array(corners, dtype=int)


    # We now check if the amount of detected ArUcos is the expected one

    # If it is not, the detection failed

    if len(corners) == 4:

        field_delimited = True

        # The top left corner is identified by the Aruco with ID = 0

        top_left_corner_id = np.where(ids == 0)[0]

       

        # The bottom right corner is identified by the Aruco with ID = 2

        bottom_right_corner_id = np.where(ids == 2)[0]


        # The bottom right corner is identified by the Aruco with ID = 3

        top_right_corner_id = np.where(ids == 3)[0]


        # The bottom right corner is identified by the Aruco with ID = 1

        bottom_left_corner_id = np.where(ids == 1)[0]


        top_left_corner = corners[top_left_corner_id][0][0][0]

        bottom_right_corner = corners[bottom_right_corner_id][0][0][0]

        top_right_corner = corners[top_right_corner_id][0][0][0]

        bottom_left_corner = corners[bottom_left_corner_id][0][0][0]


        width_top = np.hypot(

            top_left_corner[0] - top_right_corner[0],

            top_left_corner[1] - top_right_corner[1])

        width_bottom = np.hypot(

            bottom_left_corner[0] - bottom_right_corner[0],

            bottom_left_corner[1] - bottom_right_corner[1])

        max_width = max(int(width_top), int(width_bottom))

       

        height_left = np.hypot(

            top_left_corner[0] - bottom_left_corner[0],

            top_left_corner[1] - bottom_left_corner[1])

        height_right = np.hypot(

            top_right_corner[0] - bottom_right_corner[0],

            top_right_corner[1] - bottom_right_corner[1])

        max_height = max(int(height_left), int(height_right))


        input_pts = np.float32([top_left_corner,

                                bottom_left_corner,

                                bottom_right_corner,

                                top_right_corner])

        output_pts = np.float32([[0, 0],

                                [0, max_height - 1],

                                [max_width - 1, max_height - 1],

                                [max_width - 1, 0]])


        pixel_density = max_height/field_lenght_m

       

        # Compute the perspective transform M

        M = cv2.getPerspectiveTransform(input_pts,output_pts)


    output_frame = cv2.cvtColor(frame_markers, cv2.COLOR_BGR2RGB)


# Compute the perspective transform IM to transforme the image back

_, IM = cv2.invert(M)