Create gradient image in numpy for LUT (Look Up Tables)
Question:
What I’m trying to achieve: lookup tables to create duotone effect also called false color.
Say I have two colours: pure red and pure green provided in hex format ff0000
and 00ff00
respectively. We know its essentially (255, 0, 0)
and (0, 255, 0)
. I need to create a 256×1 gradient image in numpy with red and green at both ends of the gradient.
I would strongly prefer to limit the dependancies to numpy
and cv2
.
Below is a code that works for me just fine, however all the rgb
values are already hardcoded and I need to compute LUT gradient map dynamically for any given left and right colors (LUT tables truncated for brevity):
lut = np.zeros((256, 1, 3), dtype=np.uint8)
lut[:, 0, 0] = [250,248,246,244,242,240,238,236,234,232,230, ...]
lut[:, 0, 1] = [109,107,105,103,101,99,97,95,93,91,89,87,85, ...]
lut[:, 0, 2] = [127,127,127,127,127,127,127,127,127,127,127, ...]
im_color = cv2.LUT(image, lut)
Answers:
From here modifying to give numpy arrays
def hex_to_rgb(hex):
hex = hex.lstrip('#')
hlen = len(hex)
return np.array([int(hex[i:i+hlen//3], 16) for i in range(0, hlen, hlen//3)])
Then the numpy
part:
def gradient(hex1, hex2):
np1 = hex_to_rgb(hex1)
np2 = hex_to_rgb(hex2)
return np.linspace(np1[:, None], np2[:, None], 256, dtype = int)
I know the question has been answered, but just want to ask the author if the code for duotone effect can be shared. I have a brute-forth solution that updates an image pixel by pixel, it works but is really inefficient. So I’m looking for a more efficient algorithm, and found this post inspiring, but haven’t figured out a working solution using the clues. @Pono, it’d be great if you can share the code to create a duotone image using any 2 colors.
Never mind, I figured it out, and share the code below in case someone else looks for the same thing.
def gradient1d(rbg1, rbg2):
bgr1 = np.array((rbg1[2], rbg1[1], rbg1[0]))
bgr2 = np.array((rbg2[2], rbg2[1], rbg2[0]))
return np.linspace(bgr2, bgr1, 256, dtype = int)
def duotone(image, color1, color2):
img = image.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
table = gradient1d(color1, color2)
result = np.zeros((*gray.shape,3), dtype=np.uint8)
np.take(table, gray, axis=0, out=result)
return result
What I’m trying to achieve: lookup tables to create duotone effect also called false color.
Say I have two colours: pure red and pure green provided in hex format ff0000
and 00ff00
respectively. We know its essentially (255, 0, 0)
and (0, 255, 0)
. I need to create a 256×1 gradient image in numpy with red and green at both ends of the gradient.
I would strongly prefer to limit the dependancies to numpy
and cv2
.
Below is a code that works for me just fine, however all the rgb
values are already hardcoded and I need to compute LUT gradient map dynamically for any given left and right colors (LUT tables truncated for brevity):
lut = np.zeros((256, 1, 3), dtype=np.uint8)
lut[:, 0, 0] = [250,248,246,244,242,240,238,236,234,232,230, ...]
lut[:, 0, 1] = [109,107,105,103,101,99,97,95,93,91,89,87,85, ...]
lut[:, 0, 2] = [127,127,127,127,127,127,127,127,127,127,127, ...]
im_color = cv2.LUT(image, lut)
From here modifying to give numpy arrays
def hex_to_rgb(hex):
hex = hex.lstrip('#')
hlen = len(hex)
return np.array([int(hex[i:i+hlen//3], 16) for i in range(0, hlen, hlen//3)])
Then the numpy
part:
def gradient(hex1, hex2):
np1 = hex_to_rgb(hex1)
np2 = hex_to_rgb(hex2)
return np.linspace(np1[:, None], np2[:, None], 256, dtype = int)
I know the question has been answered, but just want to ask the author if the code for duotone effect can be shared. I have a brute-forth solution that updates an image pixel by pixel, it works but is really inefficient. So I’m looking for a more efficient algorithm, and found this post inspiring, but haven’t figured out a working solution using the clues. @Pono, it’d be great if you can share the code to create a duotone image using any 2 colors.
Never mind, I figured it out, and share the code below in case someone else looks for the same thing.
def gradient1d(rbg1, rbg2):
bgr1 = np.array((rbg1[2], rbg1[1], rbg1[0]))
bgr2 = np.array((rbg2[2], rbg2[1], rbg2[0]))
return np.linspace(bgr2, bgr1, 256, dtype = int)
def duotone(image, color1, color2):
img = image.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
table = gradient1d(color1, color2)
result = np.zeros((*gray.shape,3), dtype=np.uint8)
np.take(table, gray, axis=0, out=result)
return result