[Qt][Matlab]混编设置/Qt读取并显示三维张量mat/高光谱处理系统

0、背景

帮我室友做一个高光谱处理系统。
要求:

  1. GUI界面。
  2. 读取Matlab 的mat类型数据,具体为高光谱,三维张量
  3. 在GUI界面显示当前张量,超分辨算法处理后的张量,进行对比。

思路:

  1. Qt 进行GUI编程。
  2. 加载Matlab的库 ,以读取mat类型数据。

麻烦:

  1. 环境搭建。
  2. 网上很多教程写的不清晰,尤其是mat的读取,有些是自己在Qt中创建二维mxArray,不是直接读取从Matlab中保存下来的mat文件,实用性不高。
  3. 没有三维张量等mat的读取示例。

1、Qt下载

在Qt官网下载,需要账号,下载开源版,否则要用钱买。

2、Matlab下载

百度Matlab破解版安装教程,安装。

3、Qt环境配置

(1)设置环境变量。
此电脑 -> 高级系统设置 -> 环境变量 -> 系统变量,Path -> 添加E:\Matlab\bin\win64 -> 确定。
Note:路径是你自己Matlab安装的路径。下面的图片看不清点开来看。
在这里插入图片描述

(2)设置Qt的依赖文件。
设置你的项目的 .pro文件,在最后一行加上下面这几行代码,添加mat的依赖库。

INCLUDEPATH += E:/Matlab/extern/include/
LIBS += -LE:/Matlab/extern/lib/win64/microsoft/ -llibeng
LIBS += -LE:/Matlab/extern/lib/win64/microsoft/ -llibmx
LIBS += -LE:/Matlab/extern/lib/win64/microsoft/ -llibmat

其中,注意你自己的Matlab安装位置,像我是安装在E:/Matlab/,不要搞错了。

(3)设置头文件。
程序中依赖的部分头文件如下:

 #include< stdio.h> 
 #include< stdlib.h> 
 #include"mat.h"
 #include"matrix.h"

4、mat的读取

(1)mat的格式
我这里用到的高光谱是一个小的切片,因此尺寸较小,存储为mat格式,且是一个三维张量,如下图,Img数据,维度为 38 × 38 × 103 38 \times 38 \times 103 38×38×103,即宽38,高38,通道103。数据类型为single,数据类型很重要。
在这里插入图片描述

(2)Matlab的API,很重要。

1. matOpen:打开.mat文件。如果想打开文件“data.mat”,则MATFile pMF = matOpen(“data.mat”,”r”);

2. matClose:关闭*.mat文件。如果想关闭文件“data.mat”,则matClose(pMF);

3. mxArray类型:Matlab底层存放数据的数组,具体怎么存放的,还需自己去琢磨;

4. matGetVariable:获取变量,对应于上图中的“Img”。如果想获取变量“Img”,则mxArray* pArray = matGetVariable(pMF,”Img”);

5. matGetPr:获取变量的实部数据。如果想获取变量“pArray ”的实部,则double* pAReal = mxGetPr(pArray);
   类似的还有float* pAReal=mxGetSingles(Array),需要根据mat存储的类型来读取。

6. mxGetNumberOfDimensions:返回变量的维度。如果想获取变量“pArray”的维度,则int D = mxGetNumberOfDimensions(pArray)

7. mxGetM:获取变量的行数。如果想获取变量“Img”的行数,则 int M = mxGetM(Img);此时M = 388. mxGetN:获取变量在mxArray中的列数。

(3)代码,注释写的很详细。

void MainWindow::getInputMat(int Frame)   //将输入数据mat加载到内存中
{
	//m_InputPath下存储了文件夹里所有的高光谱,我们读取第Frame帧
    QString MatPath=m_InputPath[Frame];
    MATFile *Mat=matOpen(MatPath.toLatin1().data(),"r");  //读取mat
    if(Mat==NULL)
        return;
    mxArray *Array=matGetVariable(Mat,"Img");   //绑定数据,由(1)可以看到数据包名字为"Img"
    int DimNum=mxGetNumberOfDimensions(Array);  //获取张量维度的数目,这里是三维张量,因此DimNum=3
    auto MatSize=mxGetDimensions(Array);        //获取每个维度的大小,是个数组
    //std::cout<<MatSize[0]<<","<<MatSize[1]<<","<<MatSize[2]<<std::endl;   //输出:38,38,103
    m_InputTensorWidth=MatSize[0];  //记录输入张量的尺寸
    m_InputTensorHeight=MatSize[1];
    m_InputTensorChanel=MatSize[2];
    //判断数据类型,可以不要,我写出来是让大家一定要注意数据类型,调用对应的函数,否则读出来是错的
    bool isDouble=mxIsDouble(Array);     //false
    bool isComplex=mxIsComplex(Array);   //false
    bool isChar=mxIsChar(Array);         //false
    bool isSingle=mxIsSingle(Array);     //true,在(1)中已经强调了数据类型
    bool isEmpty=mxIsEmpty(Array);       //false


    //读取数据
    int Cnt=0;
    auto pr=mxGetSingles(Array);//根据数据类型single,调用该函数,很重要

    for(int k=0;k<m_InputTensorChanel;k++) //通道
    {
        for(int j=0;j<m_InputTensorHeight;j++) //高度
        {
            for(int i=0;i<m_InputTensorWidth;i++)  //宽度
            {
                double value=pr[Cnt++];
      //m_InputTensor是自己创建的一个m_InputTensorWidth x m_InputTensorHeight x m_InputTensorChanel三维的vector,
                m_InputTensor[i][j][k]=value;  //至此就将mat里面的数据读进来了
            }
        }
    }
    matClose(Mat);
}

以上各变量值的截图:
在这里插入图片描述

5、mat的显示

我们使用一个QLabel来显示高光谱,每次都选择好要显示的通道。

//选出第Frame帧,并展示其Chanel通道,高光谱数据存在三维数组Tensor中
void MainWindow::showInputImg(int Frame,int Chanel,std::vector<std::vector<std::vector<int>>> &Tensor,QLabel* label)    //更新图片
{
	//m_InputPath下存储了文件夹里所有的高光谱,我们选出第Frame帧,并展示其Chanel通道
    if(Frame>=0 & Frame<m_InputPath.size() && Chanel>=0 && Chanel<m_InputTensorChanel)
    {
        //获取当前通道的图像
        QImage *Img=new QImage(m_InputTensorWidth,m_InputTensorHeight,QImage::Format_ARGB32);
        for(int y=0;y<m_InputTensorHeight;y++)
        {
            for(int x=0;x<m_InputTensorWidth;x++)
            {
                int Value=Tensor[y][x][Chanel];
                Img->setPixel(x,y,qRgb(Value,Value,Value));
            }
        }
        //缩放到展示的窗口大小
        QImage *ImgScaled=new QImage();
        *ImgScaled=Img->scaled(label->width(),label->height());  //  ,Qt::KeepAspectRatio
        //展示图片
        label->setPixmap(QPixmap::fromImage(*ImgScaled));
        //析构
        delete Img;
        delete ImgScaled;
    }else{
        return;
    }
}

效果如下:
在这里插入图片描述

6、参考链接

[1] SnailTyan:Matlab/C++混合编程之mxArray的访问
[2] 尘埃飞舞:QT Creator使用matlab库文件读取.mat文件数据
[3] it_xiangqiang:QT的QImage类的使用

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值