zoukankan      html  css  js  c++  java
  • 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!
    ";
    		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!
    ";
    		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;
    }
    
  • 相关阅读:
    弹性盒模型:flex多行多列两端对齐,列不满左对齐
    小程序之程序构造器App()
    微信小程序之执行环境
    微信小程序之 ECMAScript
    小程序~WeUI下载使用
    补充拓展:CSS权重值叠加
    微信小程序~模板template引用
    小程序~列表渲染~key
    一个完整URL的组成
    CSS的BEM规范学习
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/8000717.html
Copyright © 2011-2022 走看看