Home > Blockchain >  CV2 Draw ellipse only on masked area
CV2 Draw ellipse only on masked area

Time:09-10

I'm trying to make a circle under the player on soccer field, similar to this:

enter image description here

If I just do a circle around the player's feet, it looks bad:

enter image description here

I'm trying to draw the circle only on the green part of the field (to make it more 3D).

First I masked only the green part on the field, using the following code:

def mask(img):
    ## convert to hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    ## mask of green (36,25,25) ~ (86, 255,255)
    lower = (36, 25, 25)
    upper = (86, 255, 255)
    mask = cv2.inRange(hsv, lower, upper)
    ## slice the green
    imask = mask == 0
    green = np.zeros_like(img, np.uint8)
    green[imask] = img[imask]
    img = green
    return img

This gives the following result:

enter image description here

How can I draw the ellipse only on the green (after the masking - black) part?

P.S. This is the full code:

import cv2
import numpy as np


def mask(img):
    ## convert to hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    ## mask of green (36,25,25) ~ (86, 255,255)
    lower = (36, 25, 25)
    upper = (86, 255, 255)
    mask = cv2.inRange(hsv, lower, upper)
    ## slice the green
    imask = mask == 0
    green = np.zeros_like(img, np.uint8)
    # green.fill(255)
    green[imask] = img[imask]
    img = green
    return img


def player_ellipse(img, player_point):
    axesLength = (45, 20)
    angle = 0
    startAngle = 0
    endAngle = 360
    # Red color in BGR
    color = (0, 0, 255)
    # Line thickness of 5 px
    thickness = 5
    img = cv2.ellipse(img, player_point, axesLength, angle, startAngle, endAngle, color, thickness)
    return img


def main():
    img = cv2.imread('img.png')
    point = (160, 665)

    img = player_ellipse(img, point)
    img = mask(img)

    cv2.imshow("img", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


main()

And this is player without any editing: cccccccc

CodePudding user response:

You are almost there. All that lefts to do is to copy the pixels from the original image (without ellipse) using the founded mask as answered by Micka and Christoph Rackwitz in comments.

Optionally you may apply some morphological operations to make the mask more appealing.

So the steps are:

  1. Draw an ellipse: enter image description here
  2. Extract a mask using green color: enter image description here
  3. [Optional] Apply mask erode: enter image description here
  4. Copy pixels from original image using the mask:

img_with_ellipse[green_mask] = img[green_mask]

enter image description here

Complete example:

import cv2
import numpy as np


def mask(img):
    ## convert to hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    ## mask of green (36,25,25) ~ (86, 255,255)
    lower = (36, 25, 25)
    upper = (86, 255, 255)
    mask = cv2.inRange(hsv, lower, upper)
    mask = cv2.erode(mask, np.ones((3, 3), np.uint8), iterations=5) == 0
    return mask


def player_ellipse(img, player_point):
    axesLength = (45, 20)
    angle = 0
    startAngle = 0
    endAngle = 360
    # Red color in BGR
    color = (0, 0, 255)
    # Line thickness of 5 px
    thickness = 5
    img = cv2.ellipse(
        img.copy(),
        player_point,
        axesLength,
        angle,
        startAngle,
        endAngle,
        color,
        thickness,
    )
    return img


def main():
    img = cv2.imread("img.png")
    point = (160, 665)

    green_mask = mask(img)

    img_with_ellipse = player_ellipse(img, point)
    img_with_ellipse[green_mask] = img[green_mask]

    cv2.imshow("img", img_with_ellipse)
    cv2.waitKey(0)


main()
  • Related