C++调用Matlab引擎 图像读写与处理 (知识+代码篇)

准备知识 之 Matlab Engine

执行命令

/* Execute matlab statement */
int engEvalString(Engine* ep, const char* string);

让engine执行string中的命令,命令格式为matlab命令。

在这里主要用到的有:

x = imread(filename)
figure
imshow(x)
imwrite(x, filename)

功能依次为
读入filename中的内容到x中
打开一个图形窗口
显示读入的图像x
将x写入到filename中

注意:1) 表示filename的字符串中两边是单引号
    2) 为了避免转义字符的影响,最好在路径中都用双斜杠'\\'
例如:'F:\\picture\\background\\0.png'

    engEvalString(ep, "x = imread('F:\\picture\\background\\0.png')");
    engEvalString(ep, "figure");
    engEvalString(ep, "imshow(x)");
    engEvalString(ep, "imwrite(x, 'F:\\picture\\background\\1.png')");

变量交互

get

/* Get a variable with the specified name from MATLAB's workspace */
mxArray *engGetVariable(Engine *ep, const char *name);

获取name变量中的内容到数组中。

在这里主要用在从文件中读取图像后。

例:

    engEvalString(ep, "x = imread('F:\\picture\\background\\0.png')");
    mxArray* pic = engGetVariable(ep, "x");

put

/* Put a variable into MATLAB's workspace with the specified name */
int engPutVariable(Engine *ep, const char *var_name, const mxArray *ap);

将数组ap中的内容放到变量中以待后续调用engine执行命令。

在这里主要用在准备将图像数据写入到文件中前。

    engPutVariable(ep, "y", pic);
    engEvalString(ep, "imwrite(y, 'F:\\picture\\background\\1.png')");

打开关闭

/* Start matlab process */
Engine *engOpen(const char *startcmd);
/* Close down matlab server */
int engClose(Engine *ep);

作为准备工作和结束工作。

准备知识 之 图像

数据及数据类型

mxArray*:从engine中获得的图像数据类型

mwSize:图像的维度数及每一维度的大小的数据类型

uint8_t:存放图像信息的矩阵的数据类型

函数及具体使用

图像的基本参数

//  获取数组的维数
size_t mxGetNumberOfDimensions_730(const mxArray *pa);
//  获取数组每一维的大小
const size_t *mxGetDimensions_730(const mxArray *pa);

假设我们不知道存放图片的数组是三维的,那么通用写法为:

    mwSize dims = mxGetNumberOfDimensions(pic);
    mwSize* dim = new mwSize[dims];
    memcpy(dim, mxGetDimensions(pic), dims * sizeof(mwSize));

即可获得这个数组的维数以及每一维的大小。

而事实上我们是知道这个数组是三维哒~

并且最后一维大小为3,存放的就是RGB值。

所以只需要如下这样这样

    mwSize row, col;
    memcpy(&row, mxGetDimensions(pic), sizeof(mwSize));
    memcpy(&col, mxGetDimensions(pic) + 1, sizeof(mwSize));

即可获得图像的行和列

图像的内容数据

数据类型

首先一个问题是,存放图像内容数据的那个矩阵,是什么数据类型呢

//  获取数组中数据的类型
mxClassID mxGetClassID(const mxArray *pa);

再查看mxClassID的定义:

typedef enum {
    mxUNKNOWN_CLASS = 0,
    mxCELL_CLASS,
    mxSTRUCT_CLASS,
    mxLOGICAL_CLASS,
    mxCHAR_CLASS,
    mxVOID_CLASS,
    mxDOUBLE_CLASS,
    mxSINGLE_CLASS,
    mxINT8_CLASS,
    mxUINT8_CLASS,
    …………………………………………
} mxClassID;

调用mxGetClassID的返回值为9,由上述定义可知,是uint8_t类型的。

存储方式

ATTENTION

数据并不是我们想当然的按val[row][col][3]这样的三维数组存储的!

在matlab里面,你可以看到它的显示依次是val(:,:,1), val(:,:,2), val(:,:,3)

什么意思呢?就是先是R分量,再是G分量,最后是B分量

——来自在玄学到怀疑人生之后,认真的比对了我读出来的RGB和它显示的值的差别之后,终于找到了真理之门的钥匙的,我
——不用感谢我,我的名字叫救命怀(溜

首地址

现在万事俱备,只欠东风,只需要知道数组的起始地址,图像内容就尽在掌握之中了。

//  获取指向数组起始位置的指针
void *mxGetData(const mxArray *pa);

// 将图像中的数据读入到一个RGB**数组中

    uint8_t* p = (uint8_t*)mxGetData(pic);
    for (int i = 0; i < row; ++i) for (int j = 0; j < col; ++j) pix[i][j].r = *(p++);
    for (int i = 0; i < row; ++i) for (int j = 0; j < col; ++j) pix[i][j].g = *(p++);
    for (int i = 0; i < row; ++i) for (int j = 0; j < col; ++j) pix[i][j].b = *(p++);

自然,有了首地址,修改图像内容也是易如反掌了

完整代码

说完整代码什么的...其实就是一个把上面几个功能简单地拼到一起的小的演示程序_(:з」∠)_

能跑,有效果,对于这样一篇文章来说就足够了(吧

基础的东西有了,于其上的拓展也应该很好操作了

注释就不写了,上面一步一步说过来感觉已经挺完整了_(:з」∠)_

/*
AUTHOR: kahlua
DATE: 2017.12.7
ENVIRONMENT: VS 2015 x64
*/

#include <iostream>
#include "engine.h"
#include <stdio.h>
using namespace std;
struct RGB {
    uint8_t r;
    uint8_t g;
    uint8_t b;
    void print() { cout << (int)r << " " << (int)g << " " << (int)b << endl; }
};
int main() {
    Engine* ep = engOpen(NULL);
    if (!ep) {
        cout << "Unable to start Matlab engine!\n";
        return -1;
    }

    engEvalString(ep, "x = imread('F:\\picture\\background\\0.png')");
    engEvalString(ep, "figure");
    engEvalString(ep, "imshow(x)");

    mxArray* pic = engGetVariable(ep, "x");

    if (!pic) {
        cout << "No such picture!\n";
        return -1;
    }

    mwSize row, col;
    memcpy(&row, mxGetDimensions(pic), sizeof(mwSize));
    memcpy(&col, mxGetDimensions(pic) + 1, sizeof(mwSize));
    cout << row << " " << col << endl;

    RGB** pix = new RGB*[row];
    for (int i = 0; i < row; ++i) pix[i] = new RGB[col];

    uint8_t* p = (uint8_t*)mxGetData(pic);
    for (int i = 0; i < row; ++i) for (int j = 0; j < col; ++j) pix[i][j].r = *(p++);
    for (int i = 0; i < row; ++i) for (int j = 0; j < col; ++j) pix[i][j].g = *(p++);
    for (int i = 0; i < row; ++i) for (int j = 0; j < col; ++j) pix[i][j].b = *(p++);

    engPutVariable(ep, "y", pic);
    engEvalString(ep, "imwrite(y, 'F:\\picture\\background\\1.png')");

    return 0;
}

转载于:https://www.cnblogs.com/kkkkahlua/p/8000717.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值