Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change the colour of an image using a mask?

I am writing a code to change the color of hair in the facial picture of a person. Doing this I made a model and was able to get a mask of the parts of the hair. But now I am stuck at a problem how to change the color of it.

Below is the output mask and input image passed.

enter image description here enter image description here

Can you suggest me the method that could be used to change the color of the hair into different colors?

like image 474
Pratham Jindal Avatar asked Jul 14 '20 09:07

Pratham Jindal


People also ask

How do you change the color of a part of an image?

Go to the Image menu, then to Adjustments , and choose Replace Color . When the dialog box opens, the first step is to sample the color in the image you want to replace by clicking on it. Now go to the Hue , Saturation , and Lightness controls to set the color you want to use as a replacement.

How do I mask an image?

Quick steps for creating a clipping mask: Select a text or graphic layer to fill with an image. Click Fill with image on the tool palette & choose an image. Select Edit image fill on the Text Tools panel. Adjust the image behind your text or shapes, then click Done.


1 Answers

Since they both have the same shape, you can mask the image of the face using mask image. We first need to perform binary thresholding on it, so it can be used as a b&w mask. Then we can perform boolean indexing based on whether a value is 0 or 255, and assign a new color, such as green?

import cv2
mask = cv2.imread('eBB2Q.jpg')
face = cv2.imread('luraB.jpg')

_, mask = cv2.threshold(mask, thresh=180, maxval=255, type=cv2.THRESH_BINARY)
# copy where we'll assign the new values
green_hair = np.copy(face)
# boolean indexing and assignment based on mask
green_hair[(mask==255).all(-1)] = [0,255,0]

fig, ax = plt.subplots(1,2,figsize=(12,6))
ax[0].imshow(cv2.cvtColor(face, cv2.COLOR_BGR2RGB))
ax[1].imshow(cv2.cvtColor(green_hair, cv2.COLOR_BGR2RGB))

enter image description here

Now we can combine the new image with the original using cv2.addWeighted, which will return the weighted sum of both images, hence we'll only see a difference on the masked region:

green_hair_w = cv2.addWeighted(green_hair, 0.3, face, 0.7, 0, green_hair)

fig, ax = plt.subplots(1,2,figsize=(12,6))
ax[0].imshow(cv2.cvtColor(face, cv2.COLOR_BGR2RGB))
ax[1].imshow(cv2.cvtColor(green_hair_w, cv2.COLOR_BGR2RGB))

enter image description here

Note that you can set the weights in the weighted sum via the alpha and beta parameters, depending on how much you want the new colour to predominate. Note that, as mentioned earlier the new image will be obtained from the weighted sum dst = src1*alpha + src2*beta + gamma. Let's try with another colour and setting the weights as a convex combination with alpha values ranging from say 0.5 and 0.9:

green_hair = np.copy(face)
# boolean indexing and assignment based on mask
green_hair[(mask==255).all(-1)] = [0,0,255]
fig, axes = plt.subplots(2,2,figsize=(8,8))
for ax, alpha in zip(axes.flatten(), np.linspace(.6, .95, 4)):
    green_hair_w = cv2.addWeighted(green_hair, 1-alpha, face, alpha, 0, green_hair_w)
    ax.imshow(cv2.cvtColor(green_hair_w, cv2.COLOR_BGR2RGB))
    ax.axis('off')

enter image description here

like image 178
yatu Avatar answered Oct 09 '22 20:10

yatu