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