3

I successfully changed a range of colors in an image to a single other color. I would like to make it more realistic by changing the colors to match the distribution of a swatch or, at the very least, a narrow band of random hues.

Some brown-looking grass

enter image description here

changed to very artificial green-looking grass

enter image description here

My code:

import cv2 as cv
import os
import numpy as np
import random

# Load the image and convert to HSV colourspace
image = cv.imread('brown_grass.jpg') 
hsv=cv.cvtColor(image,cv.COLOR_BGR2HSV)

# Define lower and uppper limits of what we call "brown"
brown_lo=np.array([18,0,0])
brown_hi=np.array([28,255,255])

# Mask image to only select browns
mask=cv.inRange(hsv,brown_lo,brown_hi)

# Change image to green where we found brown
image[mask>0]=(74,183,125) # how do change it to a nice realistic texture swatch?
cv.imwrite('result.jpg',image)

(Thanks to I want to change the colors in image with python from specific color range to another color for the first part of the solution)

metalaureate
  • 7,572
  • 9
  • 54
  • 93
  • 2
    You probably want to do a Hue rotation on the selected pixels. Look up the difference in degrees between brown and green hues and add that to the brown ones. Maybe also increase the saturation to liven them up too. – Mark Setchell Jan 17 '19 at 21:08
  • @MarkSetchell that sounds brilliant. I'm struggling with numpy to figure out how to do that. – metalaureate Jan 17 '19 at 22:00
  • @MarkSetchell this kinda worked `image[mask>0]=np.multiply(image[mask>0], (1,1.2,1))` but is not as good as whart you suggest. – metalaureate Jan 17 '19 at 22:08
  • @MarkSetchell I was overcomplicating things: `hsv[mask>0]=hsv[mask>0]+(15,20,10) image2=cv.cvtColor(hsv,cv.COLOR_HSV2BGR)` works great. Feel free to post the answer and I will accept. – metalaureate Jan 18 '19 at 04:13
  • 2
    Sorry, it was too late here last night to work out and test the specifics of the code. As you've done it, go ahead and post it and grab the points. Well done! – Mark Setchell Jan 18 '19 at 07:39

1 Answers1

3

Thanks to @MarkSetchell for the idea; the way to shade the masked area in a more natural way is to exploit the fact that brown and green are adjacent on the HSV color model, and add the delta between them, plus a boost for saturation and value.

hsv[mask>0]=hsv[mask>0]+(25,30,10) #  add an HSV vector
image2=cv.cvtColor(hsv,cv.COLOR_HSV2BGR) # convert image back into RGB color space
cv.imwrite('result.jpg', image2)

Exaggerating the effect here:

enter image description here

metalaureate
  • 7,572
  • 9
  • 54
  • 93