0

I am trying to convert the following matlab code to pyhton :



the dimension for the variable ind is :

ind=1x211420 double ; the matrix in python looks like this : [[962 962 962 962 962 962....]]

How can i write the eIm1=Im[ind] syntax to resolve the error. Thanks in advance.
maya
  • 49
  • 9
  • matlab (x,y) indexing selects a block, and needs `sub2ind` to get its 'diagonal'. Numpy [x,y] selects the 'diagonal', and needs reshaping (possibly with the help `np.ix_`) to select the 'block' – hpaulj May 23 '23 at 22:08
  • `ravel_multi_index` also acts like `sub2ind`. Beware of the 1-n versus 0-n-1 indexing difference between the languages. – hpaulj May 23 '23 at 22:12
  • @hpaulj, is it possible to provide an example for np.ix. also,Thank you for warning me for indexing. – maya May 24 '23 at 16:03
  • I'll have to first run your matlab on a computer with Octave to remind myself of what it's doing. My matlab memory is stale. – hpaulj May 24 '23 at 16:29
  • @maya Can you please respond my answer? I would like to know if my answer solves the issue. – Rotem May 29 '23 at 19:10

1 Answers1

1

There are multiple issues, and the subject is confusing...

Start by fixing the input matrices - for testing the values should cover larger range (especially the indices):

Im = rand(961, 220)*100; % Scale by 100 for testing
x0 = rand(961, 220)*200+1; % Scale X indices by 200 (range about [1, 202])
y0 = rand(961, 220)*900+1; % Scale Y indices by 900 (range about [1, 902])

We better save the input in order to use the same input in MATLAB and in Python:

if exist('input_data.mat', 'file')
    load('input_data.mat');
else
    % Create random data only if data.mat not exist
    Im = rand(961, 220)*100; % Scale by 100 for testing
    x0 = rand(961, 220)*200+1; % Scale X indices by 200 (range about [1, 202])
    y0 = rand(961, 220)*900+1; % Scale Y indices by 900 (range about [1, 902])
    save('input_data.mat', 'Im', 'x0', 'y0', '-v7'); % Save the data to be used as input to Python
end

The arguments ordering of sub2ind function is y, x:

Replace eIm1 = Im(sub2ind(size(Im), floor(re_x0'+1), floor(re_y0'+1))); with:

eIm1 = Im(sub2ind(size(Im), floor(re_y0'+1), floor(re_x0'+1)));

Note:
This part is just for following the conventions (make things less confusing).


In the Python code, read the input_data.mat to NumPy arrays, and reshape:

input_data = scipy.io.loadmat('input_data.mat')  # https://stackoverflow.com/questions/874461/read-mat-files-in-python
Im = input_data['Im']
x0 = input_data['x0']
y0 = input_data['y0']

[a1, b1] = x0.shape  # [a1, b1] = size(x0);
re_x0 = x0.reshape(a1 * b1, 1)  # re_x0 = reshape(x0, a1*b1, 1);
re_y0 = y0.reshape(a1 * b1, 1)  # re_y0 = reshape(y0, a1*b1, 1);

When using np.ravel_multi_index, it is recommended to use NumPy conventions row-major (C-style).
Using NumPy conventions in Python seems appropriate, because we are using NumPy.

  • Remove order='F'
  • Use dims=(b1, a1) - the first dimension applies the X (horizontal) axis, and the second dimension applies Y (vertical) axis.
ind = np.ravel_multi_index((np.int64(np.floor(re_x0.T + 1))-1, np.int64(np.floor(re_y0.T + 1))-1), dims=(b1, a1))

We can't use linear indexing eIm1 = Im[ind] in Python.
We have to represent the 2D array as "long" 1D array.
We may use ravel() method: eIm1 = Im.ravel()[ind].

Since MATLAB array is transposed (eIm1'): Im1 = reshape(eIm1', size(Im));, we also have to transpose Im before ravel():

eIm1 = Im.T.ravel()[ind]

Im1 = eIm1.reshape(a1, b1)  # Reshape eIm1 to 2D array

Comparing Python output with MATLAB output:

output_data = scipy.io.loadmat('output_data.mat')
Im1_matlab = output_data['Im1']

assert np.array_equal(Im1_matlab, Im1)  # The output arrays are exactly equal

Updated MATLAB code:

if exist('input_data.mat', 'file')
    load('input_data.mat');
else
    % Create random data only if data.mat not exist
    Im = rand(961, 220)*100; % Scale by 100 for testing
    x0 = rand(961, 220)*200+1; % Scale X indices by 200 (range about [1, 202])
    y0 = rand(961, 220)*900+1; % Scale Y indices by 900 (range about [1, 902])
    save('input_data.mat', 'Im', 'x0', 'y0', '-v7'); % Save the data to be used as input to Python
end

[a1, b1] = size(x0);
re_x0 = reshape(x0, a1*b1, 1);
re_y0 = reshape(y0, a1*b1, 1);
% eIm1 = Im(sub2ind(size(Im), floor(re_x0'+1), floor(re_y0'+1)));
% The correct order in MATLAB sub2ind is: y, x
eIm1 = Im(sub2ind(size(Im), floor(re_y0'+1), floor(re_x0'+1)));
Im1 = reshape(eIm1', size(Im));

save('output_data.mat', 'Im1', '-v7'); % Save the output to be used as reference for testing in Python

Updated Python code:

import numpy as np
import scipy.io

#Im = np.random.rand(961, 220) + 1
#x0 = np.random.rand(961, 220) + 1
#y0 = np.random.rand(961, 220) + 1

# Read the data from mat file (we want to have the same data as in MATLAB).
input_data = scipy.io.loadmat('input_data.mat')  # https://stackoverflow.com/questions/874461/read-mat-files-in-python
Im = input_data['Im']
x0 = input_data['x0']
y0 = input_data['y0']

[a1, b1] = x0.shape  # [a1, b1] = size(x0);
re_x0 = x0.reshape(a1 * b1, 1)  # re_x0 = reshape(x0, a1*b1, 1);
re_y0 = y0.reshape(a1 * b1, 1)  # re_y0 = reshape(y0, a1*b1, 1);

# eIm1 = Im(sub2ind(size(Im), floor(re_y0'+1), floor(re_x0'+1)));
#ind = np.ravel_multi_index((np.int64(np.floor(re_x0.T + 1))-1, np.int64(np.floor(re_y0.T + 1))-1), dims=Im.shape, order='F')

# Use dims=(b1, a1) - the first dimension applies the X (horizontal) axis, and the second dimension applies Y (vertical) axis.
# Don't use order='F', because we want the indices in NumPy conventions row-major (C-style).
ind = np.ravel_multi_index((np.int64(np.floor(re_x0.T + 1))-1, np.int64(np.floor(re_y0.T + 1))-1), dims=(b1, a1))

# eIm1 = Im(...);
#eIm1 = Im[ind]
#eIm1 = Im.ravel()[ind]  # Represent Im as 1D array using ravel() method. The elements order is row-major (C-style).
eIm1 = Im.T.ravel()[ind]  # We also have to transpose Im for matching MATLAB eIm1'

# Im1 = reshape(eIm1', size(Im));
Im1 = eIm1.reshape(a1, b1)  # Reshape eIm1 to 2D array


# Compare the result to MATLAB output.
################################################################################
output_data = scipy.io.loadmat('output_data.mat')
Im1_matlab = output_data['Im1']

assert np.array_equal(Im1_matlab, Im1)  # The output arrays are exactly equal
Rotem
  • 30,366
  • 4
  • 32
  • 65
  • thank you for all the information provided. They are very useful. However, I am still facing some problems with my Python script. – maya Jun 01 '23 at 15:40
  • What kind of problems? Did you try executing my code sample **as is** in MATLAB and Python. The code verifies that the MATLAB and Python results are identical `assert np.array_equal(Im1_matlab, Im1)`. – Rotem Jun 01 '23 at 15:52
  • Hello Rotem, my problem is with loading .mat file. When i am loading the file with command ans=load('Im2_with_tstart.mat'); it gives me a dimension of 961 by 220 for three different field values(Im,x0,y0). However, when i am using the same.mat file in python using this command data= loadmat('Im2_with_tstart.mat') Im=data['Im0'] ; it's giving me a dimension of 2275 by 250. which is not same as matlab – maya Jun 02 '23 at 19:28
  • Are you saying that you are executing the MATLAB code, and the Python code from my answer, and it's not working? Example: In MATLAB: `Im = rand(961, 220)*100;save('input_data.mat', 'Im', '-v7');`. In Python: `input_data = scipy.io.loadmat('input_data.mat');Im = input_data['Im'];print(Im.shape)`. And the shape is not `(961, 220)`? (Note that the working folder assumed to be the same). What is your version of Python? What is your version of `scipy`? `print(scipy.__version__)` Which Operating System are you using? – Rotem Jun 02 '23 at 20:44
  • Hello Rotem, I have posted my answer. Thank you so much for your solution it really helped me to get my script working. – maya Jun 05 '23 at 16:30