准備知識 之 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;
}