I have one picture read with OpenCV lib in Python. Im wondering, how can I change background color to white. I just want to have persons from the image and white background.
For example:
I want to change to this:
How can I do such thing:
import numpy as np
import cv2
my_image = r'C:\Users\Pc\Desktop\preklapanje4.jpg'
my_image = cv2.imread(my_image, 1)
cv2.imshow('img',my_image)
cv2.waitKey(0)
Step 1: First of all, import the library OpenCV. Step 2: Now, import the image from your computer. Step 3: Then, read the image in OpenCV. Step 4: Then, convert the image background to gray image background.
In this image, you need to flood fill in several regions, since all the background green color is not connected.
import cv2
import numpy as np
# load image and get dimensions
img = cv2.imread("soccer.jpg")
h, w, c = img.shape
# create zeros mask 2 pixels larger in each dimension
mask = np.zeros([h + 2, w + 2], np.uint8)
# do floodfill
result = img.copy()
cv2.floodFill(result, mask, (0,0), (255,255,255), (3,151,65), (3,151,65), flags=8)
cv2.floodFill(result, mask, (38,313), (255,255,255), (3,151,65), (3,151,65), flags=8)
cv2.floodFill(result, mask, (363,345), (255,255,255), (3,151,65), (3,151,65), flags=8)
cv2.floodFill(result, mask, (619,342), (255,255,255), (3,151,65), (3,151,65), flags=8)
# write result to disk
cv2.imwrite("soccer_floodfill.jpg", result)
# display it
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Input:
Result:
Adjust the low and high color ranges as desired to get rid of more of the green.
See floodfill
ADDITION:
Here is the code for doing inRange thresholding in HSV as suggested from my comments. But note that global thresholding has affected some of the near-white in the shirt to make it pure white. Some of that could be removed by doing some large size morphology close or from filling the smaller contours with white.
import cv2
import numpy as np
import skimage.exposure
# load image and get dimensions
img = cv2.imread("soccer.jpg")
# convert to hsv
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
# threshold using inRange
range1 = (20,80,80)
range2 = (90,255,255)
mask = cv2.inRange(hsv,range1,range2)
mask = 255 - mask
# apply morphology opening to mask
kernel = np.ones((3,3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# antialias mask
mask = cv2.GaussianBlur(mask, (0,0), sigmaX=3, sigmaY=3, borderType = cv2.BORDER_DEFAULT)
mask = skimage.exposure.rescale_intensity(mask, in_range=(127.5,255), out_range=(0,255))
result = img.copy()
result[mask==0] = (255,255,255)
# write result to disk
cv2.imwrite("soccer_mask.png", mask)
cv2.imwrite("soccer_green2white.jpg", result)
# display it
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Mask:
Result:
ADDITION2:
Here is another way that I have found to be effective in doing green screen removal. Convert to LAB. Then negate the A and multiply it by B. Then do inRange() thresholding on that to create a mask. Then use the mask to make the green into white. It keeps the near-white in the shirts from being forced to pure white, better than the earlier method. But unfortunately leaves a bit of green behind.
import cv2
import numpy as np
import skimage.exposure
# load image and get dimensions
img = cv2.imread("soccer.jpg")
# convert to hsv
lab = cv2.cvtColor(img,cv2.COLOR_BGR2LAB)
L = lab[:,:,0]
A = lab[:,:,1]
B = lab[:,:,2]
# negate A
A = (255 - A)
# multiply negated A by B
nAB = 255 * (A/255) * (B/255)
nAB = np.clip((nAB), 0, 255)
nAB = np.uint8(nAB)
# threshold using inRange
range1 = 100
range2 = 160
mask = cv2.inRange(nAB,range1,range2)
mask = 255 - mask
# apply morphology opening to mask
kernel = np.ones((3,3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# antialias mask
mask = cv2.GaussianBlur(mask, (0,0), sigmaX=3, sigmaY=3, borderType = cv2.BORDER_DEFAULT)
mask = skimage.exposure.rescale_intensity(mask, in_range=(127.5,255), out_range=(0,255))
# put white where ever the mask is zero
result = img.copy()
result[mask==0] = (255,255,255)
# write result to disk
cv2.imwrite("soccer_green2white_inrange_lab.jpg", result)
# display it
cv2.imshow("nAB", nAB)
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With