I have an image with a subject and a mostly white background. I am trying to create an alpha mask around the subject. Due to image compression artifacts, the white background is not entirely made up of (255,255,255) values for rgb values. I am trying to convert values such as (252,253,252) to (255,255,255).
My logic is as follows:
- If rgb values are within 2 of each other
- If minimum rgb value is greater than 244
- Then set those rgb values to (255,255,255)
Here is my inefficient code
image = cv2.imread('image.png') #400,400,3 in shape
for c_idx, column in enumerate(image):
for r_idx, row in enumerate(column):
if min(row) > 244 and max(row)-min(row)<=2:
image[c_idx, r_idx] = [255,255,255]
I've attempted to make it more efficient by vectorizing with np.where. I've gotten it to check for the second condition but not the first condition.
image = cv2.imread('image.png') #400,400,3 in shape
image2 = np.where(image>=244), 255, image)
I have used this algorithm, but the blending doesn't bring values down all of the way and I end up with integer overflows on the edges of the subject.
CodePudding user response:
I think this ought to work
MAX_DIFF = 2
pxl_min = image.min(axis=0)
pxl_range = image.max(axis=0) - image.min(axis=0)
img2 = np.where(((pxl_min >= 244) & (pxl_range <= MAX_DIFF)), 255, image)
CodePudding user response:
Another solution that is similar in efficiency but slightly less efficient than the accepted solution (@Damian S.).
r = arr[:,:,0]
g = arr[:,:,1]
b = arr[:,:,2]
mask=(r g b>=744) & (np.maximum.reduce([r,g,b])-np.minimum.reduce([r,g,b]) <= 2)
arr[mask]=255
I compared the efficiency of this solution on arrays of 1000x1000x3 and the accepted one with 1,000 iterations and averaging the time to complete:
@Damian: Average: 0.0081s
My answer: Average: 0.0117