admin管理员组

文章数量:1124559

I have this part of my MATLAB script where im trying to run a python code:

%%% MATLAB %%%
system(sprintf('python "%s" "%s" "%s"', 'Merge_CT_MRI_targets.py', num2str(OriginalPatients(index_target)), num2str(target_list(index_target))));
disp('test1')

This is the python script:

### PYTHON ###
import itk
import numpy as np
import os
import time

MRI_target = itk.imread("MRI_"+target+"_"+originalPatient+".nii", itk.F)

However, it looks like the variables aren't being properly called in the python script:

% matlab command window %
Traceback (most recent call last): 
  File "Merge_CT_MRI_targets.py", line 23, in <module> 
    MRI_target = itk.imread("MRI_"+target+"_"+originalPatient+".nii", itk.F) 
                                   ^^^^^^ 
NameError: name 'target' is not defined 

Any help is appreciated. I previously tried using pyrunfile but it also brings an error.

I have this part of my MATLAB script where im trying to run a python code:

%%% MATLAB %%%
system(sprintf('python "%s" "%s" "%s"', 'Merge_CT_MRI_targets.py', num2str(OriginalPatients(index_target)), num2str(target_list(index_target))));
disp('test1')

This is the python script:

### PYTHON ###
import itk
import numpy as np
import os
import time

MRI_target = itk.imread("MRI_"+target+"_"+originalPatient+".nii", itk.F)

However, it looks like the variables aren't being properly called in the python script:

% matlab command window %
Traceback (most recent call last): 
  File "Merge_CT_MRI_targets.py", line 23, in <module> 
    MRI_target = itk.imread("MRI_"+target+"_"+originalPatient+".nii", itk.F) 
                                   ^^^^^^ 
NameError: name 'target' is not defined 

Any help is appreciated. I previously tried using pyrunfile but it also brings an error.

Share Improve this question edited 2 days ago simon 4,8281 gold badge15 silver badges28 bronze badges asked 2 days ago Vanhanen_Vanhanen_ 1059 bronze badges 5
  • 3 Is that your complete Python script? Then the error shouldn't be too surprising: The variables target and originalPatient have not been defined in the Python script. Where should they come from? – simon Commented 2 days ago
  • 3 'variables' passed on the commandline to python need to be read into python variables , use the sys module. variable1=sys.argv[1] , variableN= sys.argv[n] etc – ticktalk Commented 2 days ago
  • 2 I guess what you are missing is that you need to parse the command line arguments that you produce when you call system(). Python does not "magically" assign them to appropriate variables, but instead provides them via the sys.argv list. Try import sys and print(sys.argv) in your Python script to see if that gets you any further. Also see here for more doc on sys.argv. – simon Commented 2 days ago
  • 1 @ticktalk I guess you were a bit faster than me there :D – simon Commented 2 days ago
  • 1 @simon, c'est la vie, but that's teamwork :-) – ticktalk Commented 2 days ago
Add a comment  | 

1 Answer 1

Reset to default 0

Note: I tried this with Octave, since I don't have a MATLAB license.

As already hinted at in the comments, your communication between your MATLAB script and your Python script is missing two essential aspects:

  • The handling of the inputs to the Python script within the Python script.
  • The handling of the results from the Python script within the MATLAB script.

Handling the inputs to the Python script

This is the easier part:

  • Calling system('python script.py argA argB') from MATLAB results in calling the Python script script.py with command line arguments argA and argB.
  • From withing the called Python script script.py, the command line arguments are available via sys.argv, which is a list of strings.

Let's assume you have a Python script script.py with the following contents:

### Contents of 'script.py' ###
import sys
print(sys.argv)

Call this script from the command line via the following call:

$ python script.py argA argB

Then your output will look as follows:

['script.py', 'argA', 'argB']

As you can see, all command line arguments are available as strings, prepended by the name (or Path) of the called script itself. You can now actually make use of them from within your script; for example, convert them to numbers for calculations or, as in your case, use them as a name for a file to be loaded.

Handling the outputs of the Python script

This is the more tricky part, and I am not sure if mine is the best solution:

Once you have done all the data processing in your Python script, you somehow need to get the results back to MATLAB. A very straightforward approach would be printing the results within the Python script and then capturing the outputs as part of the return value of the system() call in your MATLAB script.

Let's assume you still have the Python script script.py, with the same contents as above. Additionally now, let's assume we have a MATLAB script script.m with the following contents:

%%% Contents of 'script.m' %%%
[status, output] = system('python script.py argA argB');
sprintf('From python: %s', output)

Call this script from the command line via the following call (again, I am using Octave here):

$ octave script.m

Then your output will look as follows:

ans = From python: ['script.py', 'argA', 'argB']

As you can see, we got the same output, but this time from the MATLAB script (and only from the MATLAB script). The MATLAB script captured the Python output in the output variable, then processed it (by prepending 'From python: '), and printed it again.

Putting it all together into a (somewhat) more useful example

We can use the same approach to pass not only strings but actual data. For this case we might want to write raw bytes to the output from within our Python script, then parse them from within our MATLAB script and convert them to a corresponding MATLAB object.

The following example …

  • (in MATLAB) sends a number n to Python as a command line argument;
  • (in Python) creates an n×n square matrix containing the values 0,1,…,n²-2,n²-1 as a 2D Numpy array, then prints the raw bytes of the corresponding float64 values;
  • (in MATLAB) captures the raw bytes and converts them to the corresponding 2D MATLAB array of double values.

Python script script.py:

### Contents of 'script.py' ###
import sys
import numpy as np

# Convert 1st argument to integer, then create square matrix of doubles with it
num = int(sys.argv[1])
data = np.arange(num*num, dtype=np.float64).reshape(num, num)
# Write resulting bytes to stdout
sys.stdout.buffer.write(data.tobytes())

MATLAB script script.m:

%%% Contents of 'script.m' %%%
rows_cols = 3;
[status, res] = system(sprintf('python script.py %d', rows_cols));
numpy_data = reshape(typecast(uint8(res), 'double'), [rows_cols, rows_cols])'

Command line call of Octave and corresponding output:

$ octave script.m
numpy_data =

   0   1   2
   3   4   5
   6   7   8

As you can see, the 2D array was successfully reinstantiated as the MATLAB array numpy_data.

In reality, this might be trickier, of course: For example, if the Python script produces more outputs other than only the raw data that we are actually interested in, we need to filter out the parts that we are interested in (on the MATLAB side) or suppress all unrelated outputs (on the Python side). Also, getting the numbers of bytes, shapes, and orders of dimensions correct might not always be as straightforward as in the given example (note, for example, that here we needed to transpose the final MATLAB result).

本文标签: Inputting variables when running python code in MATLAB using systemStack Overflow