HSV color thresholding sounds great for this situation. The idea is to convert the image into HSV format then define a lower and upper range. This will allow us to segment desired objects in the image onto a mask where sections to keep are in white and areas to throw away in black.
The idea is to get two images: one representing the colored sections and another representing the inversed grayscale sections we want to keep. Then we simply combine them together to get our result.
Input image:
Using this HSV lower/upper range, we can segment green from the image
lower = np.array([35, 90, 35])
upper = np.array([179, 255, 255])
Colored ->
Gray ->
Combined result
If instead you wanted only light green, you could adjust the threshold range to remove dark green
lower = np.array([35, 90, 88])
upper = np.array([179, 255, 255])
Colored ->
Gray ->
Combined result
Here's the result for yellow
lower = np.array([0, 0, 128])
upper = np.array([29, 255, 255])
Code
import numpy as np
import cv2
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.merge([gray, gray, gray])
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([35, 90, 88])
upper = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
colored_output = cv2.bitwise_and(image, image, mask=mask)
gray_output = cv2.bitwise_and(gray, gray, mask=255-mask)
result = cv2.add(colored_output, gray_output)
cv2.imshow('colored_output', colored_output)
cv2.imshow('gray_output', gray_output)
cv2.imshow('result', result)
cv2.waitKey()
To determine the HSV lower/upper ranges, you can use this HSV thresholder script with sliders so you don't need to guess and check. Just change the image path
import cv2
import numpy as np
def nothing(x):
pass
# Load image
image = cv2.imread('1.jpg')
# Create a window
cv2.namedWindow('image')
# Create trackbars for color change
# Hue is from 0-179 for Opencv
cv2.createTrackbar('HMin', 'image', 0, 179, nothing)
cv2.createTrackbar('SMin', 'image', 0, 255, nothing)
cv2.createTrackbar('VMin', 'image', 0, 255, nothing)
cv2.createTrackbar('HMax', 'image', 0, 179, nothing)
cv2.createTrackbar('SMax', 'image', 0, 255, nothing)
cv2.createTrackbar('VMax', 'image', 0, 255, nothing)
# Set default value for Max HSV trackbars
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)
# Initialize HSV min/max values
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0
while(1):
# Get current positions of all trackbars
hMin = cv2.getTrackbarPos('HMin', 'image')
sMin = cv2.getTrackbarPos('SMin', 'image')
vMin = cv2.getTrackbarPos('VMin', 'image')
hMax = cv2.getTrackbarPos('HMax', 'image')
sMax = cv2.getTrackbarPos('SMax', 'image')
vMax = cv2.getTrackbarPos('VMax', 'image')
# Set minimum and maximum HSV values to display
lower = np.array([hMin, sMin, vMin])
upper = np.array([hMax, sMax, vMax])
# Convert to HSV format and color threshold
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(image, image, mask=mask)
# Print if there is a change in HSV value
if((phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
phMin = hMin
psMin = sMin
pvMin = vMin
phMax = hMax
psMax = sMax
pvMax = vMax
# Display result image
cv2.imshow('image', result)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()