Find points of 4 corners

hi guys
The below code segment enables

user to select 4 corners of penalty area with right click
then he can select a place in field to draw a line of offside, same with right click
then close with press enter with my app user should select 4 corners of penalty area (manually)
I need a correct suggest to app do it automatically (find points of 4 corners of penalty area) (I think it need to find intersection points of white Lines)
you can find the image 35.jpg at here


thanks

this is code

import cv2
import numpy as np

pts_src = np.array(
    [
        [87.5, 12.84],  # Top Left
        [104, 12.84],  # Top Right
        [104, 53.16],  # Bottom Right
        [87.5, 53.16]  # Bottom Left
    ], dtype=float
)


def mouse_handler(event, x, y, flags, data):
    if event == cv2.EVENT_RBUTTONDOWN:
        if len(data['points']) < data['max_points']:
            cv2.circle(data['im'], (x, y), 1, (0, 0, 255), 2, 5)
            cv2.imshow("Image", data['im'])
            data['points'].append([x, y])


def get_points(im, max_points):
    # Set up data to send to mouse handler
    data = {}
    data['im'] = im.copy()
    data['points'] = []
    data['max_points'] = max_points

    # Set the callback function for any mouse event
    cv2.imshow("Image", im)
    cv2.setMouseCallback("Image", mouse_handler, data)
    cv2.waitKey(0)
    cv2.setMouseCallback("Image", lambda *args: None)

    # Convert array to np.array
    points = np.vstack(data['points']).astype(float)

    return points


def blend_overlay_with_field(src_img, overlay, transparency):
    hsv = cv2.cvtColor(src_img, code=cv2.COLOR_BGR2HSV)

    # green range
    lower_green = np.array([35, 10, 60])
    upper_green = np.array([65, 255, 255])

    # layer masks
    field_mask = cv2.inRange(hsv, lower_green, upper_green)
    player_mask = cv2.bitwise_not(field_mask)
    # player_mask = cv2.morphologyEx(player_mask, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)))

    # extract layers from original image
    field_layer = cv2.bitwise_and(src_img, src_img, mask=field_mask)
    player_layer = cv2.bitwise_and(src_img, src_img, mask=player_mask)

    # creates line that is blank where the players are
    overlay_layer = cv2.bitwise_and(overlay, overlay, mask=field_mask)
    # overlay_layer = cv2.GaussianBlur(overlay_layer,(3,3),cv2.BORDER_DEFAULT)
    field_layer = cv2.addWeighted(field_layer, 1, overlay_layer, transparency, 0)
    final = field_layer + player_layer

    return final


if __name__ == '__main__':
    im_dst = cv2.imread('images/35.jpg')
    clean_img = im_dst.copy()

    # Get four corners of the penalty area
    print('Click on the four corners of the penalty area and then press [ENTER]')
    pts_dst = get_points(im_dst, 4)
    print(pts_dst)

    # Calculate Homography between source and destination points
    h, status = cv2.findHomography(pts_src, pts_dst)
    h_inv = np.linalg.inv(h)
    # print(h)

    # Get offside player point (field image)
    print('Click on the offside player and then press [ENTER]')
    player_im = get_points(im_dst, 1)[0]
    print(player_im)

    # Get corresponding offside player point in real world
    player_rw = cv2.perspectiveTransform(player_im.reshape(1, 1, -1), h_inv)[0][0]
    # print(player_rw)
    # print(player_rww)

    # Get the two line points in the real world line (same x, y is the field bounds)
    line_point_1_rw = player_rw.copy()
    line_point_1_rw[1] = 0
    line_point_2_rw = player_rw.copy()
    line_point_2_rw[1] = 67

    # print(line_point_1_rw)
    # print(line_point_2_rw)

    # Get corresponding second point in the image
    line_point_1_im = cv2.perspectiveTransform(line_point_1_rw.reshape(1, 1, -1), h)[0][0]
    line_point_2_im = cv2.perspectiveTransform(line_point_2_rw.reshape(1, 1, -1), h)[0][0]

    # print(line_point_1_im)
    # print(line_point_2_im)

    # Draw line
    height, width, channels = clean_img.shape
    blank_image = np.zeros((height, width, 3), np.uint8)
    overlay_img = blank_image
    cv2.line(overlay_img, tuple(line_point_1_im.astype(int)), tuple(line_point_2_im.astype(int)),
             (255, 0, 255), 2, cv2.LINE_AA)
    final = blend_overlay_with_field(clean_img, overlay_img, 0.5)

    # Display image.
    cv2.imshow("Image", final)
    cv2.waitKey(0)

related:

Yes, payam_mohammadi asked it in stackoverflow too, no answers yet.

1 Like

A robust solution would be to use an aerial view of the football field and compute the homography matrix between the two images based on SIFT or SURF descriptors (see this tutorial or another one).

Then, project the positions of the corners of the penalty area from the aerial view (that you already know) to your image using the homography matrix.

This should be more simple and robust than trying to guess from detected lines or corners.

2 Likes

you can use a drawing to match against but it’s not ideal. a drawing will have a lot fewer features to match so this can easily fail to produce a good matching or a homography.

I’d recommend calibrating the camera, taking a full picture once, aligning that manually to a model field (by moving four control points), and then matching against the image rather than the drawing.

this is what you can hope to achieve. I did this by manually moving four control points. you see the lines curving… the camera’s distortion wasn’t calibrated/removed.

1 Like

thanks
it seems to be useful
i am new in opencv
can you help me more to write codes?

can you help me more to write codes?
i don’t how can i use homography between my image that you change it and this below image:

No, we cannot help you to write code. Or solve your homework/project/etc.
We can give you advice if you have some OpenCV related questions.

Anyway, I linked 2 tutorials in my previous post, where you’ll find some code for computing homography.

2 Likes