Numpy concatenating along a new dimension - numpy-ndarray

I'm trying to do what this person is doing numpy: extending arrays along a new axis? but I don't want to repeat the same array in the new dimension. I'm generating a new 2D array and want to append it along a 3rd dimension
I've tried using np.stack((a,b), axis=2) but the arrays need to be the same shape. So after it stacks the first two arrays, the shapes on the second iteration are (256, 256, 2) and (256, 256) and I get ValueError: all input arrays must have the same shape
a = something #a has shape (256, 256)
for i in np.arange(0,10):
#calculate b and it also has shape (256,256)
a = np.stack((a,b), axis=2)
print(a.shape) #should give (256, 256, 10)

You can also do this by storing the arrays in a list and using np.stack. Perhaps not as efficient, but I find it easier to read.
import numpy as np
a = np.random.rand(256, 256) # array with shape (256, 256)
c = [a] # put initial array into a list
for i in np.arange(10):
b = np.random.rand(256, 256) # b is also array with shape (256, 256)
c.append(b) # append each new array to the list
# convert the list of arrays to 3D array
final = np.stack(c, axis=2) # axis argument specifies which axis to stack along

You want to concatenate your arrays but along a new third dimension. To get the array dimensions to agree you can make use of None when indexing them. To follow your example above, this would look like:
import numpy as np
a = np.random.rand(256, 256) # something with shape (256, 256)
c = a[ :, :, None] # start out by copying a into c but add in an extra dimension using None
for i in np.arange(10):
b = np.random.rand(256, 256) # b is also something with shape (256, 256)
c = np.concatenate((c, b[ :, :, None]), axis=2) # concatenate it to c, again using None to add in the extra dimension to b, and joining along the new axis.
c.shape # will be (256,256,11) for each of the ten iterations plus the initial copying of a into c.

Related

The fastest way to check all values from the list of coordinates

I have a list of coordinates a = [(1,2),(1,300),(2,3).....]
These values area coordinates of 1000 x 1000 NumPy array.
Let's say I want to sum all the values under these coordinates. Is there a faster way to do it than:
sum([array[i[0],i[1]] for i in a])
Apply a mask to array using a and then sum over the masked array. Example:
# Prepare sample array and indices
a = np.arange(10*10).reshape(10,10)
ind = [(1,0), (2, 4), (2,6), (7,7), (8,9), (9,3)]
# Cast list of coordinates into a form that will work for indexing
indx = np.split(np.array(ind), 2, axis = 1)
# A warning may be raised about not using tuples for indexing. You can use tuple(indx) to avoid that.
np.sum(a[indx])

how to convert bayerrg8 format image to rgb 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.

How to resize an image by adding extra pixels using matlab

I would like to resize a 512X512 image into 363X762 image which will be larger than the original image(of size 512X512). Those extra pixel values must be different values in the range of 0-255.
I tried the following code:
I=imread('photo.jpg'); %photo.jpg is a 512X512 image
B=zeros(363,726);
sizeOfMatrixB=size(B);
display(sizeOfMatrixB);
B(1:262144)=I(1:262144);
imshow(B);
B(262155:263538)=0;
But I think this is a lengthy one and the output is also not as desired. Could anyone suggest me with a better piece of code to perform this. Thank you in advance.
I think that the code you have is actually pretty close to ideal except that you have a lot of hard-coded values in there. Those should really be computed on the fly. We can do that using numel to count the number of elements in B.
B = zeros(363, 726);
%// Assign the first 262144 elements of B to the values in I
%// all of the rest will remain as 0
B(1:numel(I)) = I;
This flexibility is important and the importance is actually demonstrated via the typo in your last line:
B(262155:263538)=0;
%// Should be
B(262144:263538)=0;
Also, you don't need these extra assignments to zero at the end because you initialize the matrix to be all zeros in the first place.
A Side Note
It looks like you are spreading the original image data for each column across multiple columns. I'm guessing this isn't what you want. You probably only want to grab the first 363 rows of I to be placed into B. You can do that this way:
B = zeros(363, 726);
B(1:size(B, 1), 1:size(I, 2)) = I(1:size(B, 1), :);
Update
If you want the other values to be something other than zero, you can initialize your matrix to be that value instead.
value = 2;
B = zeros(363, 726) + value;
B(1:numel(I)) = I;
If you want them to be random integers between 0 and 255, use randi to initialize the matrix.
B = randi([0 255], 363, 726);
B(1:numel(I)) = I;

Generate an HSV image from an `M` by `N` by 3 array in Julia

I have an M by N by 3 array of floating-point reals which I would like to interpret as the HSV channels of an image. I would like to generate and export the image.
According to the function documentation,
colorim(A, [colorspace])
Creates a 2d color image from an AbstractArray, auto-detecting which
of the first or last dimension encodes the color and choosing between
"horizontal-" and "vertical-major" accordingly. colorspace defaults to
"RGB" but could also be e.g. "Lab" or "HSV".
I first tested the RGB case:
using Images
imwrite(colorim(rand(Float64, 200, 200, 3), "RGB"), "Image.PNG")
which produces the following:
However, when I replace "RGB" with "HSV" as per the documentation, I get an error message.
What is the correct syntax to interpret and export an array as HSV data?
using Images, Color
B = permutedims(A, [3,1,2]) # put color first
C = reinterpret(HSV{Float64}, B)
Tim Holy gave part of the answer, namely that the data must first be converted into an Array{HSV{Float64}, 2} using reinterpret. The missing piece is that imwrite does not appear to play nicely with arrays with HSV elements, and conversion into an Array{RGB{Float64}, 2} is necessary using convert, as Tim pointed out in this thread.
Putting this all together:
A = ones(Float64, 3, 200, 200);
A[1, :, :] = 180.0;
B = reinterpret(HSV{Float64}, A);
C = convert(Array{RGB{Float64}}, B);
imwrite(C, "test.png")
giving

How to draw/plot with multiple matrices

Hi I am trying to draw an image.
I have three matrices:
Matrix A:
X coordinates
Matrix B:
Y coordinates
Matrix C:
Image gray scale
For example:
A = [1, 1; B = [1, 2; C = [1, 2;
2, 2] 1, 2] 3, 4]
I will plot a point with value of C(1) at X(1), Y(1).
Value 1 is drawn at (1,1)
Value 2 is drawn at (1,2)
Value 3 is drawn at (2,1)
Value 4 is drawn at (2,2)
Is there a function that I can use to plot this, or do I have to implement this? Any suggestion how to implement this would be appreciated it. Thank you.
Is it a full image? And A, B, and C are 1D, right? If so you could make a 2D array with the values of Matrix C at the corresponding indices, convert it to an image and display the images.
img = zeros(max(max(B)),max(max(A))); %initialize the new matrix
for i = 1:numel(C) %for each element in C
img(B(i),A(i)) = C(i); %fill the matrix one element at a time
end
img = mat2gray(img); %optional. More information in edit
imshow(img); %display the image
This assumes that the minimum index value is 1. If it is 0 instead, you'll have to add 1 to all of the indices.
My matlab is a little rusty but that should work.
edit: Is there any reason why they are two dimensional arrays to start? Regardless, I've updated my answer to work in either case.
edit2: mat2gray will scale your values between 0 and 1. If your values are already grayscale this is unnecessary. If your values range another scale but do not necessarily contain the min and max values, you can specify the min and max. For example if your range is 0 to 255, use mat2gray(img,[0,255]);

Resources