Search code examples
arraysimagemultidimensional-arrayoctavergb

Reshaping long vertical RGB image array into layered horizontal sections in Octave


I'm trying to reshape a long vertical image array (multidimensional RGB array) into layered horizontal sections in Octave.

I have a very long vertical image array (32734x1x3). How can I reshape the image array so I turn the long vertical image into a layered horizontal image array of 52x640x3 while the rest of the array is filled in with 0's to make it "square-ish"

I was looking at reshape but couldn't figure out how to reshape an array in multiple dimensions while also creating the layered horizontal sections.

Simple Example: What space is left over in the array is filled in with zero's.

img 1

My logic/test was:

a=[1:32734]';

num_cols_wanted=640
num_of_rows_calc=ceil(size(a,1)/num_cols_wanted) %use ceil to get whole number rounded up
num_cells_to_add=mod(size(a,1),num_cols_wanted) %extra cells needed to even array out

b = zeros(num_of_rows_calc, num_cols_wanted); %preallocate 

b=reshape(a,[num_of_rows_calc,num_cols_wanted]); %place reshaped a array into preallocated b array

At the end of the test script I'm having issues reshaping the original array a into the larger preallocated array b. I get an error can't reshape 32734x1

PS: I'm using Octave 5.2


Solution

  • When using reshape, the number of input elements must be equal to the number of the output (reshaped) elements.

    In your case: length(a) must be equal to num_of_rows_calc*num_cols_wanted.


    Executing b = zeros(...) and then b = reshape(...) just overwrites the value of b (filling b with zeros doesn't help).


    • You may fill b with zeros (create a "long" vector), and copy a elements to the beginning of a:

       b = zeros(num_of_rows_calc*num_cols_wanted, 1);
       b(1:length(a)) = a;
      
    • After having b with correct number of element, we can reshape b:

        b = reshape(b, [num_cols_wanted, num_of_rows_calc])';
      

      Note: reshaping a vector in OCTAVE orders the elements by columns (top to bottom) first.
      For ordering by rows, we may reshape to cols x rows and transpose the result.


    Complete code sample:

    %a=[1:32734]';
    a = (1:10)';
    
    num_cols_wanted=3; %640;
    num_of_rows_calc=ceil(size(a,1)/num_cols_wanted); %use ceil to get whole number rounded up
    num_cells_to_add=mod(size(a,1),num_cols_wanted); %extra cells needed to even array out
    
    b = zeros(num_of_rows_calc*num_cols_wanted, 1); %Create a vector of zeros with desired number of elements.
    
    b(1:length(a)) = a; %Copy a into the b - keeping the zeros at the end of b (we could also add zero padding at the end of a).
    
    %Reshape to num_cols_wanted x num_of_rows_calc and transpose, because OCTAVE ordering is "column major".
    b = reshape(b, [num_cols_wanted, num_of_rows_calc])'; %reshape b array into preallocated b array
    

    Result:

    b =
    
        1    2    3
        4    5    6
        7    8    9
       10    0    0
    

    Example for 3D output:

    a = cat(3, (1:10)', (21:30)', (31:40)');
    
    a = squeeze(a); % Remove redunded dimentsion
    
    num_cols_wanted=4;%640;
    num_of_rows_calc=ceil(size(a,1)/num_cols_wanted); %use ceil to get whole number rounded up
    num_cells_to_add=mod(size(a,1),num_cols_wanted); %extra cells needed to even array out
    
    b = zeros(num_of_rows_calc*num_cols_wanted, 3); %Create 3 columns matrix of zeros with desired number of elements.
    
    b(1:length(a), :) = a; %Copy a into the b - keeping the zeros at the end of b (we could also add zero padding at the end of a).
    
    %Reshape to 3 x num_cols_wanted x num_of_rows_calc and permute, because OCTAVE ordering is "column major".
    b = reshape(b, [num_cols_wanted, num_of_rows_calc, 3]); %reshape b array into preallocated b array
    b = permute(b, [2, 1, 3]);