简体   繁体   中英

Masking an Image by Manipulating Pixels through Conditions

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.

You could do something like this:

def set_to_black(T, image):
    # grab the image dimensions
    h = image.shape[0]
    w = image.shape[1]

    # loop over the image, pixel by pixel
    for y in range(0, h):
        for x in range(0, w):
            if (conditional) # I couldn't be bothered to write it all out
            # Set the pixel to black
            image[y, x] = [0, 0, 0, 255]

    # return the thresholded image
    return image

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM