how to convert bayerrg8 format image to rgb image - scikit-image

I've got a camera that provides images in Bayer RG8 format.
I'm using skimage for processing images, but I could not find away to convert the Bayer RG8 format to standard RGB (to display on screen).
Is there any way to do this with skimage?
I did find a reference to opencv conversion, but I'm trying to avoid including opencv in my app (unless it is absolutely necessary).

As you have not provided any input data, I took the greyscale image from here and made it into a raw Bayer8 file with GBRG ordering using ImageMagick as follows:
magick mandi.png -trim -depth 8 gray:bayer.bin
which gives me an 1013x672 pixel file of 680,736 bytes.
Then I read it like this and made it into an image that skimage can understand like this:
#!/usr/bin/env python3
import numpy as np
from skimage.io import imsave
# Width and height of Bayer image, not original which is w/2 x h/2
w, h = 1013, 672
ow, oh = w//2, h//2
# Load in Bayer8 image, assumed raw 8-bit GBRG
bayer = np.fromfile('bayer.bin', dtype=np.uint8).reshape((h,w))
# Pick up raw uint8 samples
R = bayer[1::2, 0::2] # rows 1,3,5,7 columns 0,2,4,6
B = bayer[0::2, 1::2] # rows 0,2,4,6 columns 1,3,5,7
G0 = bayer[0::2, 0::2] # rows 0,2,4,6 columns 0,2,4,6
G1 = bayer[1::2, 1::2] # rows 1,3,5,7 columns 1,3,5,7
# Chop any left-over edges and average the 2 Green values
R = R[:oh,:ow]
B = B[:oh,:ow]
G = G0[:oh,:ow]//2 + G1[:oh,:ow]//2
# Formulate image by stacking R, G and B and save
out = np.dstack((R,G,B))
imsave('result.png',out)
And get this:
Copyright Mathworks, Inc.
Of course, there are more sophisticated methods of interpolating, but this is the most basic and you are welcome to take it and improve it!
Ok, I had some time and I tried to do a 2d-interpolation of the missing values in the Bayer array. I am not 100% confident of my answer, but I think it should be pretty close.
Basically, I copy the original Bayer array at full resolution, and overwrite all green and blue samples with np.Nan and call that Red. Then I do a 2d-interpolation to replace the Nans.
Same again for green and blue, that gives this:
#!/usr/bin/env python3
import numpy as np
from skimage.io import imsave
from scipy.interpolate import griddata
def interp2d(im):
"""Interpolate in 2d array, replacing NaNs with interpolated values"""
x, y = np.indices(im.shape)
im[np.isnan(im)] = griddata(
(x[~np.isnan(im)], y[~np.isnan(im)]),
im[~np.isnan(im)],
(x[np.isnan(im)], y[np.isnan(im)]))
im = np.nan_to_num(im)
return np.clip((im),0,255)
# Width and height of Bayer image
w, h = 1013, 672
# Calculate output width and height as multiples of 4
ow = (w//4) * 4
oh = (h//4) * 4
# Load in Bayer8 image, assumed raw 8-bit GBRG, reshape and make sides multiple of 4
bayer = np.fromfile('bayer.bin', dtype=np.uint8).reshape((h,w)).astype(np.float)[:oh, :ow]
# In following code you'll see "cell" which is the basic repeating 2x2 cell of a Bayer matrix
#
# cell = G B
# R G
#
# Set everything not Red in bayer array to Nan, then replace Nans with interpolation
cell = np.array([[np.NaN, np.NaN],
[1.0 , np.NaN]])
R = bayer*np.tile(cell,(oh//2,ow//2))
R = interp2d(R).astype(np.uint8)
# Set everything not Green in bayer array to Nan, then replace Nans with interpolation
cell = np.array([[1.0 , np.NaN],
[np.NaN, 1.0 ]])
G = bayer*np.tile(cell,(oh//2,ow//2))
G = interp2d(G).astype(np.uint8)
# Set everything not Blue in bayer array to Nan, then replace Nans with interpolation
cell = np.array([[np.NaN, 1.0 ],
[np.NaN, np.NaN]])
B = bayer*np.tile(cell,(oh//2,ow//2))
B = interp2d(B).astype(np.uint8)
# Form image by stacking R, G and B and save
imsave('result.png',np.dstack((R,G,B)))
Keywords: Python, bayer, bayer8, debayer, de-bayer, de-mosaic, de-mosaicking, image, raw, CFA, skimage, scikit-image, image processing.

Related

How to convert a numpy array to greyscale image?

I am trying to convert an 8-by-8 numpy array of binary format (0 represents black and 1 represents white). This is what I run:
from PIL import Image
data = im.fromarray(array) # array is an 8*8 binary numpy
data.save('dummy_pic.png')
But in the output I get a fully black square. Could anyone give me a hand please?
Black square is probably very dark gray, because you may have np.array with uint8 datatype, which has range of 0-255, not 0-1 like binary array. Try changing array datatype to bool, or scale values to 0-255 range.
Here is code snippet in which binary array is generated and displayed. If you scale by smaller value, circle will become slightly darker.
from PIL import Image
import numpy as np
# Generating binary array which represents circle
radius = 0.9
size = 100
x,y = np.meshgrid(np.linspace(-1,1,size),np.linspace(-1,1,size))
f = np.vectorize(lambda x,y: ( 1.0 if x*x + y*y < radius*radius else 0.0))
array = f(x,y)
# Solution 1:
# convert np.array to bool datatype
array = (array).astype(np.bool)
# Solution 2:
# scale values to uint8 maximum 255
array = ((array) * 255).astype(np.uint8)
img = Image.fromarray(array)
display(img)
Result: White circle

Why is the whole picture turning red?

We’ve been trying to fix this program for hours, yet nothing seems to work, we just can’t figure out what the problem is. It is supposed to make the whole picture black white, besides the red pixels. (https://imgur.com/a/gxRm3N1 should look like that afterwards)
Here is the result after the using the program, the whole picture is turning red:
https://imgur.com/a/yWYVoIx
How can I fix this?
from image_helper import *
img = load_rgb_image("ara.jpg")
w, h = img.size
pixels = load_rgb_pixels("ara.jpg")
#img.show()
for i in range(w*h):
r,g,b = pixels[i]
new_r = 2*r
new_g = g // 2
new_b = b + 10
pixels[i] = (new_r, new_g, new_b)
new_img = new_rgb_image(w, h, pixels)
new_img.show()
There is an excellent solution implemented in MATLAB.
I was tempting to translate the code from MATLAB to Python (using OpenCV).
Convert the image to HSV color space.
Select "non-red" pixels. In HSV color space, the first channel is the hue - there is a range of hue for pixels that considered to be red.
Set the selected pixel saturation channel to 0. (Pixels with zero saturation are gray).
Convert the image back from HSV to BGR color space.
Here is the Python code (conversation of the original MATLAB code):
import cv2
# The following code is a Python conversion to the following MATLAB code:
# Original MATLAB code: https://stackoverflow.com/questions/4063965/how-can-i-convert-an-rgb-image-to-grayscale-but-keep-one-color
img = cv2.imread('roses.jpg') # Load image.
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Convert the image to HSV color space.
h = hsv[:, :, 0] # Note: in OpenCV hue range is [0,179]) The original MATLAB code is 360.*hsvImage(:, :, 1), when hue range is [0, 1].
s = hsv[:, :, 1] # Get the saturation plane.
non_red_idx = (h > 20//2) & (h < 340//2) # Select "non-red" pixels (divide the original MATLAB values by 2 due to the range differences).
s[non_red_idx] = 0 # Set the selected pixel saturations to 0.
hsv[:, :, 1] = s # Update the saturation plane.
new_img = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) # Convert the image back to BGR space
# Show images for testing:
cv2.imshow('img', img)
cv2.imshow('new_img', new_img)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.imwrite('new_img.jpg', new_img)
Result:
Notes:
For the method used for selecting the color range, refer to the original post.
The reference post has a simpler solution, using simple for loop (with inferior results), that more resembles your code.
Consider using this code as reference.

How to convert 2D array into RGB image in python?

I want to convert each 2D array into RGB image and return this RGB image to another function how can I do that. I tried to do that by PIL and plt but it didn't work with me.I am trying for more than 2 weeks to find how I can do it.
Any help would be appreciated.
for c in [cD5,cD4,cD3,cD2,cD1]:
x = np.linspace(0, 3844, len(c))
f = interp1d(x, c)
result.append(f(common_x))
normalized_result = preprocessing.normalize(result)
I think this is solved here, remember if you want a RGB image you need 3 channels and that means a matrix with shape (NxMx3).
Convert 2d array to collored image in python
Cheers!
Edit:
This is an example of how you can stack your 2D arrays into a 3D one with the shape you need.
import numpy as np
#some random arrays i just created for test
r = np.array([3,3,3])
g = np.array([6,6,6])
b = np.array([9,9,9])
bl = np.array([12,12,12])
#create the stacked arrays
stacked = np.dstack((r,g,b,bl))
#check the shape
print(np.shape(stacked))

How can I achieve PIL colorize functionality?

Using PIL, I can transform an image's color by first converting it to grayscale and then applying the colorize transform. Is there a way to do the same with scikit-image?
The difference with e.g. the question at Color rotation in HSV using scikit-image is that there the black stays black while in PIL colorize function, I can define both where I want black and white mapped to.
I think you want something like this to avoid any dependency on PIL/Pillow:
#!/usr/bin/env python3
import numpy as np
from PIL import Image
def colorize(im,black,white):
"""Do equivalent of PIL's "colorize()" function"""
# Pick up low and high end of the ranges for R, G and B
Rlo, Glo, Blo = black
Rhi, Ghi, Bhi = white
# Make new, empty Red, Green and Blue channels which we'll fill & merge to RGB later
R = np.zeros(im.shape, dtype=np.float)
G = np.zeros(im.shape, dtype=np.float)
B = np.zeros(im.shape, dtype=np.float)
R = im/255 * (Rhi-Rlo) + Rlo
G = im/255 * (Ghi-Glo) + Glo
B = im/255 * (Bhi-Blo) + Blo
return (np.dstack((R,G,B))).astype(np.uint8)
# Create black-white left-right gradient image, 256 pixels wide and 100 pixels tall
grad = np.repeat(np.arange(256,dtype=np.uint8).reshape(1,-1), 100, axis=0)
Image.fromarray(grad).save('start.png')
# Colorize from green to magenta
result = colorize(grad, [0,255,0], [255,0,255])
# Save result - using PIL because I don't know skimage that well
Image.fromarray(result).save('result.png')
That will turn this:
into this:
Note that this is the equivalent of ImageMagick's -level-colors BLACK,WHITE operator which you can do in Terminal like this:
convert input.png -level-colors lime,magenta result.png
That converts this:
into this:
Keywords: Python, PIL, Pillow, image, image processing, colorize, colorise, colourise, colourize, level colors, skimage, scikit-image.

Convert matlab.graphics.primitive.Image (output of imagesc) to rgb array

I'm using the MATLAB function
imagesc(my_gray_valued_image)
to visualize my_gray_valued_image: [1024x1024] double array with values from 0.0 - 1.0 (gray values) using colormaps like jet.
I want to store the output as a RGB image ([1024x1024x3] double array). However the output of the function is a Image object (matlab.graphics.primitive.Image) that contains the original array (Image.CData) but doesn't allow to extract the colorscaled image.
Following a similar (although confusingly cluttered) question (How to convert an indexed image to rgb image in MATLAB?) I tried the following, but that gave me a plain blue image:
RGB = ind2rgb(my_gray_valued_image, jet);
imshow(RGB);
here for arbitrary colormap:
im = rand(5); % input [0-1] image
figure;
h = imagesc(im); % imagesc handle
title('imagesc output')
cdata = h.CData; % get image data (if you don't have variable 'im')
cm = colormap(h.Parent); % get axes colormap
n = size(cm,1); % number of colors in colormap
c = linspace(h.Parent.CLim(1),h.Parent.CLim(2),n); % intensity range
ind = reshape(interp1(c,1:n,im(:),'nearest'),size(im)); % indexed image
rgb = ind2rgb(ind,cm); % rgb image
figure;
imshow(rgb,'InitialMagnification','fit');
title('rgb image')
You can use ind2rgb to convert an intensity image into RGB using a colormap of your choice; but make sure that the range of the input is from 1 to the number of colors in the colormap. This is because ind2rgb maps value 1 to the first color, 2 to the second etc.
im = rand(5,5); % example intensity image
cmap = jet(256); % desired colormap
result = ind2rgb(ceil(size(cmap,1)*im), cmap);
The reason why you are getting a blue image is that ind2rgb clips the values of the input image to the range from 1 to the number of colors in the colormap. So, if the input image has values between 0 and 1 they are all mapped to 1, that is, to the first color in the colormap.

Resources