Reputation: 133
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.
Can you suggest me the method that could be used to change the color of the hair into different colors?
Upvotes: 12
Views: 14656
Reputation: 88305
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))
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))
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')
Upvotes: 31