I have read an image in python using RGBA color space. The size of an image is 640 by 960 and is stored to an array called img_array . Now each element in the array contains [R,G,B,A], say for example [21,34,53,255]. I want to filter my image pixels by turning pixels into black [0,0,0,255] which does not satisfy the conditional below.
R > 95 and G > 40 and B > 20 and R > G and R > B and | R - G | > 15 and A > 15
How will I do it in python? All I know is to set pixels to black which is not within the lower and upper boundaries using cv2.inrange(). Below is my sample code:
#import the necessary packages
import imutils
import numpy as np
import argparse
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image",help = "path to the image file")
args = vars(ap.parse_args())
#read image with alpha channel
img_array = cv2.imread(args["image"], -1)
rgba_lower_bound = np.array([0, 59, 59,2], dtype = "uint8")
rgba_upper_bound = np.array([20, 255, 255,255], dtype = "uint8")
skinMask = cv2.inRange(img_array, rgb_lower_bound, rgb_upper_bound)
skin = cv2.bitwise_and(img_array, img_array, mask = skinMask)
cv2.imshow("images", skin)
Please help me with this.
Assuming R, G, B, A
are all numpy arrays with the same shape, created by something like:
R, G, B, A = cv2.split(img_array)
simply create a mask using the same conditionals; since they're numpy
arrays, use &
instead of and
:
mask = (R > 95) & (G > 40) & (B > 20) & (R > G) & (R > B) & (abs(R - G) > 15) & (A > 15)
Then to set everything not satisfying the condition to black:
img_array[~mask] = [0, 0, 0, 255]
Note here the mask
will be two-channel, and will be broadcasted to all the channels in img_array
. Also note ~
inverts a numpy boolean array, so this is indexing by wherever mask
is False
, which is what you want.
Some more info on transparency: if the alpha channel is 0, that means fully transparent, and if it's 255 (for a unsigned 8-bit image), that means opaque. If you want the image to be transparent at those locations instead of black, you can just invert the mask, turn it into a uint8
array, and then merge it back into one image, like so:
R, G, B, A = cv2.split(img_array)
mask = (R > 95) & (G > 40) & (B > 20) & (R > G) & (R > B) & (abs(R - G) > 15) & (A > 15)
new_A = 255*(~mask).astype(np.uint8)
new_img_array = cv2.merge([R, G, B, new_A])
This way you're not losing any of the color information in R, G, B should you want to keep it.