How to reshape 1D RGB to 2D RGB image in Matlab? - arrays

Suppose I have 1D RGB array of the following structure:
I = [r1 r2 ... rN; g1 g2 ... gN; b1 b2 ... bN];
where
N = H*W;
ans H and W are height and width of the picture respectively.
How to reshape it to colored image format HxW, which is represented by 3D matrix so that
I2(1,1,1) = r1
I2(1,1,2) = g1
I2(1,1,3) = b1
I2(2,1,1) = r2
I2(2,1,2) = g2
I2(2,1,3) = b2
...
I2(H,W,1) = rN
I2(H,W,2) = gN
I2(H,W,3) = bN
(if I am correct thinking that normal 1D -> 2D reshape works by columns)
UPDATE
This reshaping can be done the following way
R = I(1,:);
R = reshape(R,H,W);
G = I(2,:);
G = reshape(G,H,W);
B = I(3,:);
B = reshape(B,H,W);
I2 = cat(3, R, G, B);
Can it be done shorter, with one reshape call for example?

I think that what you're looking for is: reshape(I', H, W, 3)

Related

Inserting items in an array every nth place in octave / matlab

How can I insert elements in an array (a2) every nth place in (a1)
Example: Logic
a1 = [1,10,2,20,3,30,4,40,5,50];
a2 = [100,200,300,400,500];
n=3 % n would be the position to place the elements found in (a2) every **nth** position in (a1).
*n is the starting position at which the array a2 is inserted into a1*
The new a1 if n=3 after inserting a2 into it would look like
a1 = [1,10,100,2,20,200,3,30,300,4,40,400,5,50,500];
The new a1 if n=2 after inserting a2 into it would look like
a1 = [1,100,10,2,200,20,3,300,30,4,400,40,5,500,50];
The new a1 if n=1 after inserting a2 into it would look like
a1 = [100,1,10,200,2,20,300,3,30,400,4,40,500,5,50];
I tried
a1(1:3:end,:) = a2;
but I get dimensions mismatch error.
Please note this is just an example so I can't just calculate an answer I need to insert the data into the array. n is the starting position at which the array a2 is inserted into a1
First allocate an array of the combined size, then insert both original arrays to required indices. With a2 it is easy, you can just use n:n:end. To get indices for a1 you can subtract the set of a2 indices from the set of all indices:
a1 = [1,10,2,20,3,30,4,40,5,50];
a2 = [100,200,300,400,500];
n = 3;
res = zeros(1,length(a1)+length(a2));
res(n:n:n*length(a2)) = a2;
a1Ind = setdiff(1:length(res), n:n:n*length(a2));
res(a1Ind) = a1;
>> res
res =
1 10 100 2 20 200 3 30 300 4 40 400 5 50 500
Another option is to use circshift to shift the row you want on top
orig_array=[1:5;10:10:50;100:100:500;1000:1000:5000];
row_on_top=3 %row to be on top
[a1_rows a1_cols]=size(orig_array)
a1 = circshift(orig_array, [-mod(row_on_top,a1_rows)+1, 0])
Anew = zeros(1,a1_rows*a1_cols)
for n=1:1:a1_rows
n
insert_idx=[n:a1_rows:a1_cols*a1_rows] %create insert idx
Anew(insert_idx(1:a1_cols))=a1(n,:) %insert only 1:a1_cols values
end
Anew=Anew(:)

Read 3 1xN arrays into a 3xN matrix in matlab

I have 3 arrays in matlab that are 1xN, X Y Z respectively. I need to read these arrays into a 3xN matrix respectively so I get
x1 y1 z1
x2 y2 z2
.. .. ..
xn yn zn
I have currently got the data in a Nx 3 matrix, the wrong way round. The code I have is
X = [];
Y = [];
Z = [];
for ctr = 1:length(A)
X = [X A(ctr,1)];
Y = [Y A(ctr,2)];
Z = [Z A(ctr,3)];
end
M = [X;Y;Z];
Where A is the input data from a 624*600 double cell and M is my desired matrix.
Thanks
I guess you want that:
X = [];
Y = [];
Z = [];
for ctr = 1:length(A)
X(end+1, 1) = A(ctr,1);
Y(end+1, 1) = A(ctr,2);
Z(end+1, 1) = A(ctr,3);
end
M = [X Y Z];
Faster with 1 line code:
M = [A(:, 1) A(:, 2) A(:, 3)];
I just found that you can transpose with Mt = transpose(M); which has the overall intended result but feels like 3 rights to make a left.

MATLAB: ceate a x b matrix (or 2D array) from 2 1Darrays, and populate each cell from another array

I am using MATLAB.
So I have 3 arrays; say a,b,c. a and b represent distances, and c represents a variable with a specific value at the point (a,b).
I have been trying to create a matrix which comprises of (b x a) cells, and the populate it with the values of c, in order to then image, heatmap it etc.
However the issue I have having is that there are many repeating values of a and b; a stays fixed and it then iterates across all values of b, then moves onto the next value of a, and so forth. The range of a and b is fixed and always iterate across equally spaced values though.
Below is the code I have created for this. So for it seems to not to work and I am out of ideas.
z_true_len = length(unique(a)); %number of z distances
r_true_len = length(unique(b)); %number of r disatances
data_matrix = zeros(r_true_len,z_true_len); %create r x z matrix, full of 0s
z_past = 0;
r_past = 0;
z_count = 1;
r_count = 1;
for count = 1: length(a)
z_current = a(count);
if z_past ~= z_current
data_matrix(1:z_count) = c(count);
z_past = z_current;
z_count = z_count + 1;
r_count = 1;
else
data_matrix(r_count:z_count) = c(count);
r_count = r_count + 1;
end
end
data_matrix
Any help would be appriciated
I included a mapping of the a and b arrays into a space of integers:
% Data
a = [ 0.5 0.5 2.5 0.5 2.5 2.5 4.5 4.5 4.5 2.5 4.5 0.5];
b = [-35 -25 -25 -15 -45 -35 -35 -45 -15 -15 -25 -45];
c = [2 1 -2 4 6 4 6 8 4 1 -5 2];
% Mapping from real to integers
a_unique = sort(unique(a));
b_unique = sort(unique(b));
a_idx = zeros(size(a));
b_idx = zeros(size(b));
for ii = 1:numel(a_unique),
a_idx(a_unique(ii)==a) = ii;
end
for ii = 1:numel(b_unique),
b_idx(b_unique(ii)==b) = ii;
end
% Create matrix
data_matrix = zeros(numel(b_unique),numel(a_unique));
for count = 1:length(a_idx),
data_matrix(b_idx(count),a_idx(count)) = c(count);
end
% Plot
figure;
imagesc(data_matrix);
You basically need to define data_matrix with the appropriate dimensions, and then fill values in using linear indexing (see sub2ind):
m = max(b); %// number of rows in result
n = max(a); %// number of columns in result
data_matrix = NaN(m,n); %// define result matrix with appropriate dimensions
data_matrix(sub2ind([m n], b, a)) = c; %// fill values using indexing
If a and b don't always contain integers: first transform into "integer labels" with the third output of unique, and then proceed as above:
[~, ~, bb] = unique(b); %// get integer labels for b
[~, ~, aa] = unique(a); %// get integer labels for a
m = max(bb); %// number of rows in result
n = max(aa); %// number of columns in result
data_matrix = NaN(m,n); %// define result matrix with appropriate dimensions
data_matrix(sub2ind([m n], bb, aa)) = c; %// fill values using indexing

Three dimensional matrix, Cartesian product

I have three vectors a, b and c. The value of a_i depends is the sum of the Cartesian product of all the values of the vectors b and c, which again is multiplied by a factor of the three dimensional matrix w:
How do I write that in Matlab?
Let b, c be column vectors. The simplest way is to collapse w to a two dimensional matrix, then multiply by b as follows:
w2 = sum(bsxfun(#times,w,shiftdim(c,-2)),3);
a = w2 * b;
Here I test it for random data, for syntax errors:
n = 10;
w = randn(n,n,n);
b = randn(n,1);
c = randn(n,1);
w2 = sum(bsxfun(#times,w,shiftdim(c,-2)),3);
a = w2 * b;
% using loops:
aalt = zeros(n,1);
for ii=1:n
for jj=1:n
for kk=1:n
aalt(ii,1) = aalt(ii,1) + w(ii,jj,kk) * b(jj) * c(kk);
end
end
end
% up to roundoff error:
max(abs(aalt - a))
a = sum(sum(bsxfun(#times, w, shiftdim(bsxfun(#times, b(:), c(:).'), -1)), 3), 2)
Or replace the inner bsxfun by matrix multiplication:
a = sum(sum(bsxfun(#times, w, reshape(b(:)*c(:).',[1 numel(b) numel(c)])), 3), 2)

Multiplication of two arrays with dimension=5 in a vectorize way

I have a three dimensional domain in MATLAB. For each point in the domain I have defined three arrays of size (NX,NY,NZ) at each point of the domain:
A1; % size(A1) = [NX NY NZ]
A2; % size(A2) = [NX NY NZ]
A3; % size(A3) = [NX NY NZ]
For each element, I am trying to construct an array which holds the value of A1, A2, and A3. Would the following be a good candidate for having a 1×3 vector at each point?
B = [A1(:) A2(:) A3(:)];
B = reshape(B, [size(A1) 1 3]);
If the 1×3 array is named C, I am trying to find C'*C at each point.
C = [A1(i,j,k) A2(i,j,k) A3(i,j,k)]; % size(C) = [1 3]
D = C'*C; % size(D) = [3 3]
My ultimate goal is to find the array D with size 3×3 for all the points in the domain in a vectorize fashion? In fact, the output which consists of array D for each point will have the size [NX NY NZ 3 3]. Could someone help me?
Basically we concatenate A1, A2 and A3 along the 4th and 5th dimensions separately that leaves singleton dimensions in the 5th and 4th dimensions respectively, which are then used by bsxfun [Apply element-by-element binary operation to two arrays with singleton expansion enable] to expand as 3x3 matrices along the 4th-5th dimensions for matrix multiplication result from each triplet of [A1(i,j,k),A2(i,j,k),A3(i,j,k)].
D = bsxfun(#times,cat(4,A1,A2,A3),cat(5,A1,A2,A3));

Resources