在python中调用matlab
在学习图像处理的基础知识,顺道学习python。用python调用matlab实现数字水印的提取与嵌入。
用PyQt5做了GUI,点击按钮调用matlab,实现水印嵌入与提取。
学习过程中发现python与matlab之间的数据转换较麻烦,现记录如下。
API安装
matlab官方提供了python调用的接口。可参考下列链接进行安装。
1.https://ww2.mathworks.cn/help/matlab/matlab_external/install-the-matlab-engine-for-python.html
2.https://ww2.mathworks.cn/help/matlab/matlab_external/get-started-with-matlab-engine-for-python.html
按照官方步骤可很顺滑的完成一系列操作,不在此赘述。后续格式转换问题纠缠数天,现解决如下。
从GUI获取图片
// get picture from QLabel
image1 = self.img1.pixmap().toImage()
1.此时为QImage格式。
QImage转为array
// QImage to array
cover = QImageToCvMat(image1)
cover_object = matlab.uint8(cover.tolist())
QImageToCvMat 为自定义函数,如下(此方法在外网找到,原地址忘了…)。
// QImage to array
def QImageToCvMat(incomingImage):
incomingImage = incomingImage.convertToFormat(QtGui.QImage.Format.Format_RGB888)
width = incomingImage.width()
height = incomingImage.height()
ptr = incomingImage.bits()
ptr.setsize(height * width * 3)
arr = np.frombuffer(ptr, np.uint8).reshape((height, width, 3))
return arr
2.此时为array格式,我的matlab函数中需要输入uint8格式,在此转换,此时终于可传入matlab。
调用matlab自定义函数
- 该.m文件需放在当前工作路径下
- 若输出参数不为1,请定义 nargout,此值默认为1。
// call matlab
from matlab import engine
engine = matlab.engine.start_matlab()
watermrkd_img, recmessage,attack_image, attack_message, PSNR, NCC, MSSIM,PSNR_a, NCC_a, MSSIM_a=engine.dwt(cover_object, message, height,width,var, nargout=10)
3.调用engine,负责matlab程序的启动
matlab输出参数转换到python
// call matlab
watermrkd_img = np.array(watermrkd_img)
4.将输出参数先转换为array格式
array转QImage
//array to QImage,and show on the GUI
jpg3 = qimage2ndarray.array2qimage(watermrkd_img)
watermrkd = QtGui.QPixmap(jpg3)
self.img3.setScaledContents(True) //图片自适应QLabel
self.img3.setPixmap(watermrkd)
array2qimage为自定义方法,如下(此方法在外网找到,原地址忘了…)。
def array2qimage(array, normalize = False):
if _np.ndim(array) == 2:
array = array[...,None]
elif _np.ndim(array) != 3:
raise ValueError("array2qimage can only convert 2D or 3D arrays (got %d dimensions)" % _np.ndim(array))
if array.shape[2] not in (1, 2, 3, 4):
raise ValueError("array2qimage expects the last dimension to contain exactly one (scalar/gray), two (gray+alpha), three (R,G,B), or four (R,G,B,A) channels")
h, w, channels = array.shape
hasAlpha = _np.ma.is_masked(array) or channels in (2, 4)
fmt = _qt.QImage.Format_ARGB32 if hasAlpha else _qt.QImage.Format_RGB32
result = _qt.QImage(w, h, fmt)
array = _normalize255(array, normalize)
if channels >= 3:
rgb_view(result)[:] = array[...,:3]
else:
rgb_view(result)[:] = array[...,:1] # scalar data
alpha = alpha_view(result)
if channels in (2, 4):
alpha[:] = array[...,-1]
else:
alpha[:] = 255
if _np.ma.is_masked(array):
alpha[:] *= _np.logical_not(_np.any(array.mask, axis = -1))
return result
5.此时图片可显示在GUI上。
后记
用此API调用matlab,运行非常慢。
此项目全部代码可见https://github.com/lfreya/Digital-Watermark-use-python-and-matlab