從 Python 調用 MATLAB 函數的三種方法


0. 實驗環境

  • Ubuntu 16.04
  • Matlab R2015b

1. 借助於 mlab 庫

安裝方法非常簡單,只需一行命令 sudo pip install mlab 即可。

import numpy as np
from PIL import Image
from mlab.releases import latest_release as matlab

image = Image.open('1.jpg')
image = np.array(image)
h, w = image.shape
print(image.shape) # (413, 295)

在上面的代碼中,我們先讀入一個圖片,然后將其轉化為一個 Numpy 數組。接下來,假如我們想通過調用 MATLAB 的 imresize 函數來對這幅圖像進行 4 倍上采樣,那么我們要做的就是將這個 Numpy 數組傳遞到 MATLAB 中,然后調用相應的函數,最后再將結果返回到 Python 中。

但是,MATLAB 並不支持將 Python 中的 Numpy 數組直接映射為矩陣,具體映射方式可參考 從 Python 將數據傳遞到 MATLAB。所以,我們需要先將數組轉化為列表,然后通過 matlab.double(initializer=None, size=None, is_complex=False) 構造函數 在 Python 中創建 MATLAB 數組,最后再調整到原來圖片的大小。這時候,我們就可以調用 MATLAB 的函數得到我們想要的結果了。

image = image.reshape(-1, 1)
image = image.tolist()
image = matlab.double(image)
image = matlab.reshape(image, (h, w))
resized_image = matlab.imresize(image, 4, 'bicubic')
print(resized_image.shape) # (1652, 1180)

如果我們想要調用自定義函數,比如下面這樣的 m 文件。

function c = add(a, b)
	c = a + b;
end

那么只需要傳遞相應的參數進去即可,這里 Python 中的浮點數會映射為 MATLAB 中的 double 類型。

result = matlab.add(2.0, 3.0)
print(result) # 5.0

但是,目前在我這邊發現 mlab 不支持 Python 3,安裝后會提示 ImportError: No module named 'mlabwrap' 之類的錯誤,暫時還沒找到解決方案。

2. 借助於 MATLAB 自帶的引擎 API

首先,需要 安裝用於 Python 的 MATLAB 引擎 API。比如,在我的工作環境下,需要進入到 MATLAB 對應的安裝路徑 /usr/local/MATLAB/R2015b/extern/engines/python,然后運行命令 sudo python setup.py install 即可。

由於我的 MATLAB 版本還比較低,目前只支持到 Python 3.4,更高的版本則會報錯 OSError: MATLAB Engine for Python supports Python version 2.7, 3.3 and 3.4, but your version of Python is 3.5

>>> import matlab.engine
>>> eng = matlab.engine.start_matlab()
>>> import numpy as np
>>> image = np.random.randn(30, 30)
>>> image.shape
(30, 30)
>>> resized_image = eng.imresize(image, 4, 'bicubic')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/matlab/engine/matlabengine.py", line 79, in __call__
    out=_stdout, err=_stderr)
TypeError: unsupported Python data type: numpy.ndarray
>>> image = image.reshape(-1, 1)
>>> image = image.tolist()
>>> image = matlab.double(image)
>>> image.reshape((30, 30))
>>> resize_image = eng.imresize(image, 4, 'bicubic')
>>> resize_image.size
(120, 120)

>>> eng.add(2.0, 3.0)
5.0
>>>

用法和第一種類似,但是在我這邊測試發現只能運行在交互模式下,直接運行對應的 py 文件則會報錯。

senius@HP:~/Downloads$ python2 test1.py 
Traceback (most recent call last):
  File "test1.py", line 3, in <module>
    import matlab.engine
  File "/usr/local/lib/python2.7/dist-packages/matlab/engine/__init__.py", line 60, in <module>
    raise EnvironmentError('The installation of MATLAB Engine for Python is '
EnvironmentError: The installation of MATLAB Engine for Python is corrupted.  
Please reinstall it or contact MathWorks Technical Support for assistance.

上面兩種方法都只能進行一些簡單的調用,而且還需要在 Python 和 MATLAB 之間進行數據轉化,非常不方便,下面介紹的第三種方法則非常簡單有效。

3. 借助於 transplant 庫

transplant 庫支持 Python 3.4-3.7,安裝方法非常簡單 sudo pip3 install transplant。Python 中的列表會轉化為 MATLAB 中的元胞數組,Numpy 數組會轉化為 MATLAB 中的矩陣,更多詳細信息可參閱 github教程。同樣地,我們可以這樣對圖像進行上采樣。

>>> import transplant
>>> import numpy as np
>>> matlab = transplant.Matlab(jvm=False, desktop=False)

                            < M A T L A B (R) >
                  Copyright 1984-2015 The MathWorks, Inc.
                   R2015b (8.6.0.267246) 64-bit (glnxa64)
                              August 20, 2015

 
For online documentation, see http://www.mathworks.com/support
For product information, visit www.mathworks.com.
 
>>> image = np.random.randn(30, 30)
>>> image.shape
(30, 30)
>>> resized_image = matlab.imresize(image, 4, 'bicubic')
>>> resized_image[0]
array([[ 0.78619134,  0.7167187 ,  0.57147529, ..., -0.1314248 ,
        -0.19615895, -0.22226921],
       [ 0.69992414,  0.63668882,  0.50463212, ..., -0.10023177,
        -0.16053713, -0.18483134],
       [ 0.51579787,  0.46606682,  0.36253926, ..., -0.01897913,
        -0.07015085, -0.09065985],
       ...,
       [ 0.27508006,  0.27579099,  0.28756401, ..., -0.70385557,
        -0.80006309, -0.84680474],
       [ 0.23260259,  0.23527929,  0.25076149, ..., -0.75840955,
        -0.80315767, -0.82872907],
       [ 0.21943022,  0.2228168 ,  0.2396492 , ..., -0.78075353,
        -0.80353953, -0.8200766 ]])
>>> resized_image[0].shape
(120, 120)
>>>

針對如下所示的多個自定義函數存在互相調用的復雜情況,transplant 也可以輕松勝任。

比如,我們需要通過 Python 調用 NGmeet_DeNoising( N_Img, O_Img, nSig ) 這個函數,它有三個輸入,N_Img 為長×寬×波段的三維噪聲高光譜圖像,O_Img 為對應的干凈圖像,而 nSig 為噪聲等級。那么只需在 Python 中將兩個 Numpy 數組和一個整數傳給對應的函數即可。

clean = np.load('GT_crop.npy')
h, w, b = clean.shape
sigma = 25
noisy = clean + np.random.randn(h, w, b) * sigma / 255
print(cal_psnr(clean, noisy)) # 20.1707
c = matlab.NGmeet_DeNoising(255.0*noisy, 255.0*clean, sigma)
print(c.shape, c.dtype) # (200, 200, 191) float64
print(matlab.mpsnr(c/255, clean)) # 34.5712

如果報如下的錯誤,則因為 par_nSig 是將 Python 中的 sigma=25 轉化為了 MATLAB 中的 int64,而 int64 數據不能與 double 類數據相乘。而解決辦法也很簡單,double(par_nSig) 將其數據轉化為 double 類型即可。

獲取更多精彩,請關注「seniusen」!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM