I want to detect only green objects from an image captured in a natural environment. How to define it? Because in here I want to pass the threshold value let's say 'x', by using this x I want to get only green colour objects in to one colour (white) others are must appear in another colour (black). Please guide me to do this.
To detect colors in images, the first thing you need to do is define the upper and lower limits for your pixel values. Once you have defined your upper and lower limits, you then make a call to the cv2. inRange method which returns a mask, specifying which pixels fall into your specified upper and lower range.
Thresholding is a technique in OpenCV, which is the assignment of pixel values in relation to the threshold value provided. In thresholding, each pixel value is compared with the threshold value. If the pixel value is smaller than the threshold, it is set to 0, otherwise, it is set to a maximum value (generally 255).
What Are Color Spaces? In the most common color space, RGB (Red Green Blue), colors are represented in terms of their red, green, and blue components. In more technical terms, RGB describes a color as a tuple of three components.
Update:
I make a HSV
colormap. It's more easy and accurate
to find the color range using this map than before.
And maybe I should change use (40, 40,40) ~ (70, 255,255) in hsv
to find the green
.
Original answer:
HSV
color-space,cv2.inRange(hsv, hsv_lower, hsv_higher)
to get the green mask. We use the range (in hsv)
: (36,0,0) ~ (86,255,255)
for this sunflower
.
The source image:
The masked green regions:
More steps:
The core source code:
import cv2
import numpy as np
## Read
img = cv2.imread("sunflower.jpg")
## convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
## mask of green (36,25,25) ~ (86, 255,255)
# mask = cv2.inRange(hsv, (36, 25, 25), (86, 255,255))
mask = cv2.inRange(hsv, (36, 25, 25), (70, 255,255))
## slice the green
imask = mask>0
green = np.zeros_like(img, np.uint8)
green[imask] = img[imask]
## save
cv2.imwrite("green.png", green)
Similar:
Applying a threshold to detect green color can be performed quite easily using LAB color space.
The LAB color space also has 3 channels but unlike its RGB counterpart (where all 3 are color channels), in LAB there are 2 color channels and 1 brightness channel:
Observing the following diagram:
The green and red color are represented on the extremes of the A-channel. Applying a suitable threshold on either of these extremes on this channel can segment either green or red color.
The following images are in the order:
1. Original image -->> 2. A-channel of LAB converted image
3. Threshold -->> 4. Mask on the original image
Sample 1:
Sample 2:
Sample 3:
The code just has few lines:
# read image in BGR
img = cv2.imread('image_path')
# convert to LAB space
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
# store the a-channel
a_channel = lab[:,:,1]
# Automate threshold using Otsu method
th = cv2.threshold(a_channel,127,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1]
# Mask the result with the original image
masked = cv2.bitwise_and(img, img, mask = th)
The method above will work perfectly if green color appears distinctly. But applying an automated threshold might not always work, especially when there various shades of green in the same image.
In such cases, one set the threshold manually on the A-channel.
img = cv2.imread('flower.jpg')
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
a_channel = lab[:,:,1]
# manually set threshold value
th = cv2.threshold(a_channel, 105, 255, cv2.THRESH_BINARY_INV)
# perform masking
masked = cv2.bitwise_and(img, img, mask = th)
Threshold image Masked image
You can use a simple HSV color thresholder script to determine the lower/upper color ranges using trackbars for any image on the disk. Simply change the image path in cv2.imread()
. Example to isolate green:
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()
HSV lower/upper color threshold ranges
(hMin = 52 , sMin = 0, vMin = 55), (hMax = 104 , sMax = 255, vMax = 255)
Once you have determined your lower
and upper
HSV color ranges, you can segment your desired colors like this:
import numpy as np
import cv2
image = cv2.imread('1.png')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([52, 0, 55])
upper = np.array([104, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(image, image, mask=mask)
cv2.imshow('result', result)
cv2.waitKey()
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