How does one convert a grayscale image to RGB in OpenCV (Python)?
I am promoting my comment to an answer:
The easy way is:
You could draw in the original 'frame' itself instead of using gray image.
The hard way (method you were trying to implement):
backtorgb = cv2.cvtColor(gray,cv2.COLOR_GRAY2RGB)
is the correct syntax.
How can I convert an RGB image into grayscale in Python?
How about doing it with Pillow:
from PIL import Image
img = Image.open('image.png').convert('L')
img.save('greyscale.png')
If an alpha (transparency) channel is present in the input image and should be preserved, use mode LA
:
img = Image.open('image.png').convert('LA')
Using matplotlib and the formula
Y' = 0.2989 R + 0.5870 G + 0.1140 B
you could do:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])
img = mpimg.imread('image.png')
gray = rgb2gray(img)
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()
Converting a grayscale image to rgb damages image
Correct me if I am wrong but I suspect the values in X[0]
are in the range 0,255. In
img = X[0].astype('float32') #cv2 needs float32 or uint8 for handling images
rgb_image = cv2.cvtColor(img,cv2.COLOR_GRAY2RGB)
plt.imshow(rgb_image)
try replacing the first line with.
img = X[0]/255
This makes the values not only float32
but also between 0 and 1.
Combine 3 grayscale images to 1 natural color image in Python
You have several problems in your code:
Firstly, you need to import modules:
import numpy as np
import cv2
Secondly, you are using ugly, manifest constants instead of the nice, legible, maintainable ones that OpenCV provides for free and also you are needlessly wrapping the Numpy array you get from cv2.imread()
into a Numpy array.
Finally, you are not checking for errors.
So, rather than:
r_np = np.array(cv2.imread(red, 0))
consider:
r_np = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)
assert r_np is not None, "ERROR: Error reading red image"
Convert grayscale 2D numpy array to RGB image
It seems to me that there are 3 aspects to your question:
- creating a colormap, or LUT "Lookup Table"
- scaling your pixels to a standard range
- applying a colormap to an image without
matplotlib
.
So, to create a colormap, we need a list of 256 RGB values in which
we can lookup any greyscale value and find the colour we want to show it as. I understand you can't use matplotlib
in production, but you can grab a colormap or two from there on some other machine and copy it to your production machine. So, let's do that. We'll take the viridis
colormap:
#!/usr/bin/env python3
import numpy as np
from matplotlib import cm
# Get 256 entries from "viridis" or any other Matplotlib colormap
colmap = cm.get_cmap('viridis', 256)
# Make a Numpy array of the 256 RGB values
# Each line corresponds to an RGB colour for a greyscale level
np.savetxt('cmap.csv', (colmap.colors[...,0:3]*255).astype(np.uint8), fmt='%d', delimiter=',')
If we look at that file "cmap.csv"
, it has 256 lines and starts like this:
68,1,84
68,2,85
68,3,87
69,5,88
69,6,90
69,8,91
70,9,92
...
...
That means anywhere we see 0
in the greyscale image, we actually colour the pixel rgb(68,1,86)
. Anywhere we see 1
in the greyscale it maps to rgb(68,2,85)
. Presumably you can copy that file to your production machine and you can choose any one of Matplotlib
s colormaps.
Regarding scaling, you have posted an 8-bit PNG image with a range of 0..117 rather than a 16-bit TIFF image with a range of 17..317, so that is not most helpful. Also, you have not said how you plan to read a TIFF on a system that doesn't have OpenCV or matplotlib, so I don't know whether you have PIL/Pillow or plan to use tifffile.
Instead then, I will create a dummy 32x32 image with a range of 17..317 like this:
grey = np.random.randint(17,318, (32,32))
That looks like this:
array([[244, 75, 237, ..., 154, 190, 70],
[286, 247, 158, ..., 150, 267, 124],
[170, 305, 237, ..., 126, 111, 236],
...,
[163, 292, 184, ..., 24, 253, 177],
[314, 34, 36, ..., 87, 316, 182],
[258, 153, 278, ..., 189, 57, 196]])
If we now want to scale that from the range 17..317 into the range 0..255, we can use:
rescaled = ((grey.astype(float) - grey.min())*255/(grey.max() - grey.min())).astype(np.uint8)
which gives us this:
array([[192, 49, 187, ..., 116, 147, 45],
[228, 195, 119, ..., 113, 212, 90],
[130, 244, 187, ..., 92, 79, 186],
...,
[124, 233, 141, ..., 5, 200, 136],
[252, 14, 16, ..., 59, 254, 140],
[204, 115, 221, ..., 146, 34, 152]], dtype=uint8)
Looking up can be done by loading the CSV file containing our colourmap, and taking the corresponding elements from the colormap as indexed by your greyscale values in the range 0...255:
#!/usr/bin/env python3
import numpy as np
from PIL import Image
# Load image as greyscale and make into Numpy array
grey = np.array(Image.open('TdoGc.png').convert('L'))
# Load RGB LUT from CSV file
lut = np.loadtxt('cmap.csv', dtype=np.uint8, delimiter=',')
# Make output image, same height and width as grey image, but 3-channel RGB
result = np.zeros((*grey.shape,3), dtype=np.uint8)
# Take entries from RGB LUT according to greyscale values in image
np.take(lut, grey, axis=0, out=result)
# Save result
Image.fromarray(result).save('result.png')
If you scale your greyscale image to the full range after reading, using this line:
grey = ((grey.astype(float) - grey.min())*255/(grey.max() - grey.min())).astype(np.uint8)
You will get this:
If you want to visualise your colormap, change the line above that looks like this:
grey = np.array(Image.open('TdoGc.png').convert('L'))
into this so that it generates a gradient (ramp) image:
grey = np.repeat(np.arange(256,dtype=np.uint8).reshape(1,-1), 100, axis=0)
Then you can see your colourmap:
A quick hack to handle segmented linear colormaps that don't have a class variable enumerating the colours. So you can make the cmap.csv
file from the autumn
colourmap like this:
import numpy as np
from matplotlib import cm
# Get "autumn" colourmap
colmap = cm.get_cmap('autumn')
# Save 256 RGB entries as CSV - one for each of grey levels 0..255
np.savetxt('cmap.csv', np.array([colmap(i/255)[:3] for i in range(256)]) * 255, fmt="%d", delimiter=',')
Related Topics
Windowserror: [Error 126] the Specified Module Could Not Be Found
_Tkinter.Tclerror: No Display Name and No $Display Environment Variable
Pandas - Calculate Average of Columns With Condition Based on Values in Other Columns
Tf.Data.Dataset: How to Get the Dataset Size (Number of Elements in an Epoch)
Python - How to Fix "Valueerror: Not Enough Values to Unpack (Expected 2, Got 1)"
Best Way to Identify and Extract Dates from Text Python
Index Out of Bounds Error:Python
Sum of Square Differences (Ssd) in Numpy/Scipy
How to Remove Carriage Return in a Dataframe
Incorrect Column Alignment When Printing Table in Python Using Tab Characters
Use Tqdm Progress Bar With Pandas
How to Read from S3 in Pyspark Running in Local Mode
Adding Months to a Pandas Object in Python
Python - Converting a List of 2 Digit String Numbers to a List of 2 Digit Integers
Test a Function Called Twice in Python