Reshaping an outputted 1 dimensional numpy array into a 2/3 dimensional array - arrays

So I'm using an image's pixel data, applying some calculations to it, which gives me a resulting array whose shape is unknown until the calculations are done to it.
I'm having trouble reshaping the outputted array into a 2-dimensional or 3-dimensional array
Here is an example
from PIL import Image
img = Image.open('C:\Users\Amit\Desktop\sample_pic.jpeg').convert("RGB")
pixels =np.array(img)
print(pixels.shape) # (477L, 887L, 3L) PIL seems to switch height and width because original dimensions are 877 x 477
flat = pixels.flatten()
print (flat.shape) # (1269297L,)
filter1= np.array([1,1,0])
pixels2 = np.array([])
for i in range(0, len(flat),2):
pixels2 =np.append(pixels2,np.sum((flat[i:i+3] * filter1)))
The loop at the end is just doing some calculations to the flattened array, and outputting a new array whose shape I don't know till the output
print pixels2.shape
#(634649L,)
So I'm trying to reshape the outputted array into dimensions fit for a picture.
I tried the code
pixels2.reshape(800,-1)
but I got the error
pixels2.reshape(800,-1)
ValueError: total size of new array must be unchanged
same with
pixels.reshape(800,-1,3)
ValueError: total size of new array must be unchanged
I was hoping that adding the (-1) would automatically find the appropriate second dimension but that doesn't seem to be the case. I'm not bound to the number 800 as one of the dimensions but I'm looking for the first two dimensions to be above 300 so (300+, 300+, 3)
Thanks.
Update:
adding one more element to the pixels2 array, makes it a (634650L,) array which is divisible by 3. ( I found it by trial and error)
But finding the other two dimensions involves a lot of trial and error as well it seems. (800, -1, 3) doesn't work.

Related

Matlab- Create cell confusion matrix

I have the following cell matrix, which will be used as a confusion matrix:
confusion=cell(25,25);
Then, I have two other cell arrays, on which each line contains predicted labels (array output) and another cell matrix containing the real labels (array groundtruth).
whos output
Name Size Bytes Class Attributes
output 702250x1 80943902 cell
whos groundtruth
Name Size Bytes Class Attributes
groundtruth 702250x1 84270000 cell
Then, I created the following script to create the confusion matrix
function confusion=write_confusion_matrix(predict, groundtruth)
confusion=cell(25,25);
for i=1:size(predict,1)
confusion{groundtruth{i},predict{i}}=confusion{groundtruth{i}, predict{i}}+1;
end
end
But when I run it in matlab I have the following error:
Index exceeds matrix dimensions.
Error in write_confusion_matrix (line 4)
confusion{groundtruth{i},predict{i}}=confusion{groundtruth{i}, predict{i}}+1;
I was curious to print output's and groundtruth's values to see what was happening
output{1}
ans =
2
groundtruth{1}
ans =
1
So, nothing seems to be wrong with the values, so what is wrong here? is the confusion matrix's indexing right in the code?
The error occurs in a for loop. Checking the first iteration of the loop is not sufficient in this case. Index exceeds matrix dimensions means there exists an i in the range of 1:size(output,1) for which either groundtruth{i} or output{i} is greater than 25.
You can find out which one has at least one element bigger than the range:
% 0 means no, there is none above 25. 1 means yes, there exists at least one:
hasoutlier = any(cellfun(#(x) x > 25, groundtruth)) % similar for 'output'
Or you can count them:
outliercount = sum(cellfun(#(x) x > 25, groundtruth))
Maybe you also want to find these elements:
outlierindex = find(cellfun(#(x) x > 25, groundtruth))
By the way, I am wondering why are you working with cell arrays in this case? Why not numeric arrays?

Matlab: Change elements in 3D array using given conditions

I have a 3 dimensional array (10x3x3) in Matlab and I want to change any value greater than 999 to Inf. However, I only want this to apply to (:,:,2:3) of this array.
All the help I have found online seems to only apply to the whole array, or 1 column of a 2D array. I can't work out how to apply this to a 3D array.
I have tried the following code, but it becomes a 69x3x3 array after I run it, and I don't really get why. I tried to copy the code from someone using a 2D array, so I just think I don't really understand what the code is doing.
A(A(:,:,2)>999,2)=Inf;
A(A(:,:,3)>999,3)=Inf;
One approach with logical indexing -
mask = A>999; %// get the 3D mask
mask(:,:,1) = 0; %// set all elements in the first 3D slice to zeros,
%// to neglect their effect when we mask the entire input array with it
A(mask) = Inf %// finally mask and set them to Infs
Another with linear indexing -
idx = find(A>999); %// Find linear indices that match the criteria
valid_idx = idx(idx>size(A,1)*size(A,2)) %// Select indices from 2nd 3D slice onwards
A(valid_idx)=Inf %// Set to Infs
Or yet another with linear indexing, almost same as the previous one with the valid index being calculated in one step and thus enabling us a one-liner -
A(find(A(:,:,2:3)>999) + size(A,1)*size(A,2))=Inf

How can I extract a 1 dimentional row from a multidimentional matrix

I currently have a 3 dimensional matrix and I want to extract a single row (into the third dimension) from it by index (say matrix(2,1,:)). I initially anticipated that the result of this would be a 1 dimensional matrix however what I got was a 1 by 1 by n matrix. Usually this wouldn't be a problem but some of the functions I'm using don't like 3D matrices. For example see the problem replicated below:
threeDeeMatrix=rand(3,3,3);
oneDeeAttempt=threeDeeMatrix(1,1,:);
norm(oneDeeAttempt)
Which returns the error message:
Error using norm
Input must be 2-D.
This is because oneDeeAttempt is
oneDeeAttempt(:,:,1) =
0.8400
oneDeeAttempt(:,:,2) =
0.0700
oneDeeAttempt(:,:,3) =
0.7663
rather than [0.8400 0.0700 0.7663]
How can I strip these extra dimensions? The only solution I can come up with is to use a loop to manually copy the values but that seems a little excessive.
Using permute to rearrange the matrix
The solution (which I found in the final stages of asking this) is to use permute which rearranges the order of the dimensions (similar to a=a' for 2D matrices). Once the unit dimensions are last they are stripped from the matrix and it becomes 1 dimensional.
oneDee=permute(oneDeeAttempt,[3 1 2]) %rearrange so the previous third dimension is now the first
%the matrix is now 3 by 1 by 1 which becomes 3
Using squeeze to remove leading singleton dimensions
As pointed out by Luis Mendo squeeze will very simply remove these leading singleton dimensions without having to worry about which dimensions are non singleton
oneDee=squeeze(oneDeeAttempt);

Matlab access vectors from a multi-dimensional array

I have a 4D matrix of size 300x200x3x20 where 300x200 is the size of one video frame, 3 is the number of channels (Red-Green-Blue channels) and 20 is the number of frames.
I want to extract all the color vectors from this matrix and store them in a 2D array of size 3x1,200,000 (300 x 200 x 20 = 1,200,000) where each row represents a component of the RGB color space and each column contain the RGB values of one pixel in the original matrix.
Besides, I want to carry out pixel-wise operations on this data such as extracting visual features but I cannot find a way to effectively access vectors along the third dimension.
How could I efficiently do these, possible without using loops?
Try this code -
IN = your_4D_data;
OUT = reshape(permute(IN,[3 1 2 4]),3,numel(IN)/3);
help reshape says:
B = reshape(A,m,n,p,...) or B = reshape(A,[m n p ...]) returns an n-dimensional array with the same elements as A but reshaped to have the size m-by-n-by-p-by-.... The product of the specified dimensions, m*n*p*..., must be the same as numel(A).
is this what you are looking for?
also, you can adress pixels like this: Matrix(i,j,:,k) which gives you the 3 colorchanels of pixel i,j in frame k.

adding numpy vector to a numpy multi-dimensional array

I have a loop that adds elements to a 1d array:
for i in range(0, 1000):
fvector[0, i] = function_value
after the loop finishes, I have a 1 x 1000 vector that I want to store in a multi-dimensional array fmatrix, which is 50 x 1000. I managed to do this using a loop and copying each element individually - but it is very slow. I've then tried to use slice to copy the whole vector in one go after the loop and then be ready to copy next vector at the next column. How do I make it go to the next column? I've tried:
s=slice([i], None)
fmatrix[s] = fvector
and various combinations for s, but I get error messages about setting an array element with a sequence, or invalid syntax.
I know this should be straight forward but I'm very new to python, numpy and arrays :-(
Try this. Allocate the matrix, here zero-initialized for effect:
>>> import numpy as np
>>> fmatrix = np.zeros((50, 1000))
Then index into it to obtain fvector:
>>> fvector = fmatrix[0]
Then assign to fvector's elements:
>>> for i in xrange(1000):
... fvector[i] = i
If you now inspect fmatrix[0], the first row of fmatrix, you'll find that it has been assigned to in the previous loop. That's because the NumPy row indexing creates fvector as a view on fmatrix's first row. This saves you a copy.
fvector has shape (1,1000). That's a 2D array, even if one axis has length 1.
You can slice it down to a 1D array with fvector[0,:]. This gives the first row.
fmatrix has shape (50,1000). You can slice it down to a 1D array with fmatrix[i,:]. This gives the ith row.
So to assign the values in the first row of fvector to the ith row of fmatrix:
fmatrix[i,:] = fvector[0,:]
Perhaps however there is no need for fvector to be a 2D array? Perhaps just make it a 1D array to begin with:
fvector = np.empty(1000)
for i in range(0, 1000):
fvector[i] = function_value
and then you could do the assignment with
fmatrix[i,:] = fvector

Resources