I'm processing images using opencv and part of my problem requires that I iterate over the image by its colors and only display colors which match certain ranges of colors. How can I find the maximum and minimum bgr values?
CodePudding user response:
Here is one way to do that in Python/OpenCV/Numpy. Threshold on the color you want. Then use Numpy to get the min and max colors of each channel.
Input:
import cv2
import numpy as np
# load image
img = cv2.imread('mandril3.jpg')
# create mask for red
lower=np.array((20,40,215))
upper=np.array((100,120,255))
mask = cv2.inRange(img, lower, upper)
# mask the image for viewing
result = img.copy()
result[mask!=255] = (0,0,0)
# separate channels
b,g,r = cv2.split(img)
# compute min and max ranges of red
bmin = np.amin(b[np.where(mask == 255)])
bmax = np.amax(b[np.where(mask == 255)])
gmin = np.amin(g[np.where(mask == 255)])
gmax = np.amax(g[np.where(mask == 255)])
rmin = np.amin(r[np.where(mask == 255)])
rmax = np.amax(r[np.where(mask == 255)])
print("min red:", bmin, gmin, rmin)
print("max red:", bmax, gmax, rmax)
# save results
cv2.imwrite("mandril3_nose_mask.jpg", mask)
cv2.imwrite("mandril3_nose.jpg", result)
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Min and Max Colors of the Red Nose:
min red: 20 53 215
max red: 100 120 255
Mask:
Masked Image:
CodePudding user response:
Here is a more proper way to do that in Python/OpenCV. We basically find the color where the average of R,G,B channels after masking for red is the smallest and the color where the average of R,G,B after masking for red is largest.
- Read the input
- Select color -- in this case red
- Threshold the image for the color as a mask
- Separate channels
- Get the average image of the 3 channels
- Find the min and max values in the average image
- Create a mask for the min values
- Create a mask for the max values
- Combine the original mask with the min mask
- combine the original mask with the max mask
- Get the coordinates for all pixels where the combined mask and min mask is white.
- Find the color corresponding to the first coordinate found if more than one
- Get the coordinates for all pixels where the combined mask and max mask is white.
- Find the color corresponding to the first coordinate found if more than one
Input:
import cv2
import numpy as np
# load image
img = cv2.imread('mandril3.jpg')
# create mask for red
lower=np.array((20,40,215))
upper=np.array((100,120,255))
mask = cv2.inRange(img, lower, upper)
# mask the image for viewing
result = img.copy()
result[mask!=255] = (0,0,0)
# separate channels
b,g,r = cv2.split(img)
# get average of channels
ave = cv2.add(b,g,r)/3
ave = ave.astype(np.uint8)
# get min and max for ave
ave_min = np.amin(ave[np.where(mask==255)])
ave_max = np.amax(ave[np.where(mask==255)])
# form min and max masks from ave
mask_min = ave.copy()
mask_min[ave==ave_min] = 255
mask_min[ave!=ave_min] = 0
mask_max = ave.copy()
mask_max[ave==ave_max] = 255
mask_max[ave!=ave_max] = 0
# combine min mask with red mask
red_mask_min = cv2.bitwise_and(mask, mask_min)
# combine max mask with red mask
red_mask_max = cv2.bitwise_and(mask, mask_max)
# get coordinates where masks are white and corresponding color - take first one
min_list = np.argwhere(red_mask_min==255)
min_count = len(min_list)
if min_count != 0:
min_coord = min_list[0]
y=min_coord[0]
x=min_coord[1]
min_color = img[y:y 1, x:x 1][0][0]
print("min_red:", min_color)
max_list = np.argwhere(red_mask_max==255)
max_count = len(max_list)
if max_count != 0:
max_coord = max_list[0]
y=max_coord[0]
x=max_coord[1]
max_color = img[y:y 1, x:x 1][0][0]
print("max_red:", max_color)
# save results
cv2.imwrite("mandril3_nose_mask.jpg", mask)
cv2.imwrite("mandril3_nose.jpg", result)
# show images
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.imshow("ave", ave)
cv2.imshow("red_mask_min", red_mask_min)
cv2.imshow("red_mask_max", red_mask_max)
cv2.waitKey(0)
cv2.destroyAllWindows()
Red Mask:
Masked Image:
Results:
min_red: [ 22 57 244]
max_red: [ 99 120 242]