user3043636
user3043636

Reputation: 579

Change a defined colour in an image using Python

I have an image containing a girl's face and I would like to change the colour of her eyes starting from an identified colour using the RGB in python. I have this colour:

rbg_source=[85, 111, 47]

and this colour as the destination

rbg_destination=[72.50445669, 56.82411376, 47.7519902]

reconstruction the image as the original one substituting only the mentioned colours.

Do you have an idea to do that in python?

I have already used the following solution:

 resized_image[np.all(resized_image == (85, 111, 47), axis=-1)] = (72.50445669, 56.82411376, 
 47.7519902)

 # Save result
 cv2.imwrite('result1.png',resized_image)

But it returns a bad image without the expect solution.

Please find below an example image

image

in that image, I would like to change the right eye colour knowing the RGB of that colour i.e. (5, 155, 122)

Upvotes: 0

Views: 1364

Answers (1)

fmw42
fmw42

Reputation: 53174

Here is one way to do that in Python/OpenCV, since I do not have the corresponding RGB colors for the blue and green that you want to use. So I will approximate using baseline blue and green.

  • Read input
  • Convert to HSV and separate channels
  • Specify blue and green hues and get hue difference
  • Threshold on green color range to make a mask
  • Use morphology to clean the mask
  • Add the hue difference to the hue channel and modulo 180
  • Combine the new hue, the old saturation channel and the old value channel that is biased to increase brightness to match the left eye color and convert back to BGR
  • Use the mask to merge the new BGR and the original image
  • Save the results

Input:

enter image description here

import cv2
import numpy as np

# load image with alpha channel
img = cv2.imread('eyes.png')

# convert to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)

# blue is 240 in range 0 to 360; so half in OpenCV
# green is 120 in range 0 to 360; so half in OpenCV
blue_hue = 120
green_hue = 60

# diff hue (blue_hue - green_hue)
diff_hue = blue_hue - green_hue

# create mask for green color in hsv
lower = (30,90,90)
upper = (90,170,180)
mask = cv2.inRange(hsv, lower, upper)
mask = cv2.merge([mask,mask,mask])

# apply morphology to clean mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)

# modify hue channel by adding difference and modulo 180 
hnew = np.mod(h + diff_hue, 180).astype(np.uint8)

# recombine channels and bias value to make brighter
hsv_new = cv2.merge([hnew,s,v+60])

# convert back to bgr
bgr_new = cv2.cvtColor(hsv_new, cv2.COLOR_HSV2BGR)

# blend with original using mask
result = np.where(mask==(255, 255, 255), bgr_new, img)

# save output
cv2.imwrite('eyes_green_mask.png', mask)
cv2.imwrite('eyes_green2blue.png', result)

# Display various images to see the steps
cv2.imshow('mask',mask)
cv2.imshow('bgr_new',bgr_new)
cv2.imshow('result',result)
cv2.waitKey(0)
cv2.destroyAllWindows()
 

Mask

enter image description here

Hue and Value shifted BGR image:

enter image description here

Result:

enter image description here

ADDITION:

If you know the exact blue and green BGR colors, you can convert them each to HSV and get the H,S,V differences. Then use those differences as biases to the H,S,V channels of the input image and use the mask to combine that result with the original as I did above.

Upvotes: 1

Related Questions