您的位置:首页 > 编程语言 > MATLAB

Matlab中利用mex编译Opencv实现画板绘图功能

2014-10-10 19:24 501 查看
图形绘制是标记和可视化数据的重要方法.

通过在Matlab中集成画板绘图功能, 可为科学计算提供便利.

1 设置Matlab支持Opencv编译

操作系统: 麒麟14.04(基于Ubuntu 14.04)

命令: mex -v

-> mexopts.sh sourced from directory (DIR = $MATLAB/bin)
FILE = /usr/local/MATLAB/R2013a/bin/mexopts.sh
----------------------------------------------------------------
->    MATLAB                = /usr/local/MATLAB/R2013a
->    CC                    = gcc
->    CC flags:
CFLAGS             = -ansi -D_GNU_SOURCE  -fexceptions -I/usr/include/opencv -fPIC -fno-omit-frame-pointer -pthread
CDEBUGFLAGS        = -g
COPTIMFLAGS        = -O -DNDEBUG
CLIBS              = -Wl,-rpath-link,/usr/local/MATLAB/R2013a/bin/glnxa64 -L/usr/local/MATLAB/R2013a/bin/glnxa64 -lmx -lmex -lmat -lm -lstdc++  -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab
arguments          =  -DMX_COMPAT_32
->    CXX                   = g++
->    CXX flags:
CXXFLAGS           = -ansi -D_GNU_SOURCE -std=c++0x -fPIC -fno-omit-frame-pointer -pthread
CXXDEBUGFLAGS      = -g
CXXOPTIMFLAGS      = -O -DNDEBUG
CXXLIBS            = -Wl,-rpath-link,/usr/local/MATLAB/R2013a/bin/glnxa64 -L/usr/local/MATLAB/R2013a/bin/glnxa64 -lmx -lmex -lmat -lm  -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab
arguments          =  -DMX_COMPAT_32
->    FC                    = gfortran
->    FC flags:
FFLAGS             = -fexceptions -fbackslash -fPIC -fno-omit-frame-pointer
FDEBUGFLAGS        = -g
FOPTIMFLAGS        = -O
FLIBS              = -Wl,-rpath-link,/usr/local/MATLAB/R2013a/bin/glnxa64 -L/usr/local/MATLAB/R2013a/bin/glnxa64 -lmx -lmex -lmat -lm
arguments          =  -DMX_COMPAT_32
->    LD                    = gcc
->    Link flags:
LDFLAGS            = -pthread -shared -Wl,--version-script,/usr/local/MATLAB/R2013a/extern/lib/glnxa64/mexFunction.map -Wl,--no-undefined
LDDEBUGFLAGS       = -g
LDOPTIMFLAGS       = -O
LDEXTENSION        = .mexa64
arguments          =
->    LDCXX                 =
->    Link flags:
LDCXXFLAGS         =
LDCXXDEBUGFLAGS    =
LDCXXOPTIMFLAGS    =
LDCXXEXTENSION     =
arguments          =


编辑mexopts.sh文件,可支持mex中编译opencv.(事先要安装Opencv)

2 编写drawcanvas.cpp文件

#include <stdlib.h>
#include <mex.h>
#include <matrix.h>
#include "opencv2/opencv.hpp"
#include <vector>
#include <string>

using namespace cv;

#define max(a, b) ((a) > (b) ? (a) : (b))

const char *commands[] = {"lines", "circles", "rectangles", "texts"};

void drawLines(Mat& mat, int nrhs, const mxArray *prhs[]) {
//linesxy_4_columns, linecolor, linewidth,
if (nrhs != 5) {
mexErrMsgTxt("Error usage for draw lines: drawcanvas(img, cmd, pts_4_column, color, width)\n");
return;
}

double *lines = mxGetPr(prhs[2]);
int lrows = mxGetM(prhs[2]),
lcols = mxGetN(prhs[2]);
if (lcols != 4) {
mexErrMsgTxt("Error parameters for lines: it should be a mat with 4 columns.\n");
return;
}

double *Color = mxGetPr(prhs[3]);
if (mxGetNumberOfElements(prhs[3]) != 3) {
mexErrMsgTxt("Error: line color should be a mat with 3 columns indicating RGB.\n");
return;
}
Scalar color;
color[0] = Color[0];
color[1] = Color[1];
color[2] = Color[2];

int thickness = mxGetScalar(prhs[4]);
int linetype = CV_AA;

CvPoint startpt, endpt;
for(int i = 0; i < lrows; i++) {
startpt = Point(lines[i], lines[i + lrows]);
endpt = Point(lines[i + 2 * lrows], lines[i + 3 * lrows]);
line( mat, startpt, endpt, color, thickness, linetype );
}
}

void drawCircles(Mat& mat, int nrhs, const mxArray *prhs[]) {
//linesxy_4_columns, linecolor, linewidth,
if (nrhs != 5) {
mexErrMsgTxt("Error usage for draw circles: drawcanvas(img, cmd, circle_mat[x y r;], color, line_thickness)\n");
return;
}

double *circles = mxGetPr(prhs[2]);
int crows = mxGetM(prhs[2]),
ccols = mxGetN(prhs[2]);
if (ccols != 3) {
mexErrMsgTxt("Error parameters for circles: it should be a mat with 3 columns[cx cy r;].\n");
return;
}

double *Color = mxGetPr(prhs[3]);
if (mxGetNumberOfElements(prhs[3]) != 3) {
mexErrMsgTxt("Error: circle color should be a mat with 3 columns indicating RGB.\n");
return;
}
Scalar color;
color[0] = Color[0];
color[1] = Color[1];
color[2] = Color[2];

int thickness = mxGetScalar(prhs[4]);
int linetype = CV_AA;

CvPoint cpt;
double radius;
for(int i = 0; i < crows; i++) {
cpt = Point(circles[i + crows], circles[i]);
radius = circles[i + 2 * crows];
circle( mat, cpt, (int)radius, color, thickness, linetype, 0);
}
}

void drawRectanges(Mat& mat, int nrhs, const mxArray *prhs[]) {
//linesxy_4_columns, linecolor, linewidth,
if (nrhs != 5) {
mexErrMsgTxt("Error usage for draw lines: drawcanvas(img, cmd, rects_4_column, color, width)\n");
return;
}

double *rects = mxGetPr(prhs[2]);
int lrows = mxGetM(prhs[2]),
lcols = mxGetN(prhs[2]);
if (lcols != 4) {
mexErrMsgTxt("Error parameters for lines: it should be a mat with 4 columns.\n");
return;
}

double *Color = mxGetPr(prhs[3]);
if (mxGetNumberOfElements(prhs[3]) != 3) {
mexErrMsgTxt("Error: line color should be a mat with 3 columns indicating RGB.\n");
return;
}
Scalar color;
color[0] = Color[0];
color[1] = Color[1];
color[2] = Color[2];

int thickness = mxGetScalar(prhs[4]);
int linetype = CV_AA;

CvPoint startpt, endpt;
for(int i = 0; i < lrows; i++) {
startpt = Point(rects[i], rects[i + lrows]);
endpt = Point(rects[i + 2 * lrows], rects[i + 3 * lrows]);
rectangle( mat, startpt, endpt, color, thickness, linetype );
}
}

void drawTexts(Mat& mat, int nrhs, const mxArray *prhs[]) {
//linesxy_4_columns, linecolor, linewidth,
if (nrhs != 7) {
mexErrMsgTxt("Error usage for draw texts: drawcanvas(img, cmd, sliced_text_with_#, points, fontScale, thickness, color)\n");
return;
}

vector<string> strings;
unsigned char *ptr0 = (unsigned char *)mxGetPr(prhs[2]), *ptr1 = ptr0;
char *buf = mxArrayToString(prhs[2]);   //注意:Matlab的字符串类型如何转换为C的字符串类型
int len = strlen(buf);
char tmp[256];
int cnt = 0;
for(int i = 0; i < len; i++) {
if (buf[i] == '#') {
strings.push_back(string(tmp));
//mexPrintf("%s\n", strings[strings.size()-1].c_str());
cnt = 0;
}
else {
if (cnt < 255) {
tmp[cnt++] = buf[i];
tmp[cnt] = '\0';
}
}
}
if (cnt > 0)
strings.push_back(string(tmp));
if (buf)
mxFree(buf);

//debug
/*
for(int i = 0; i < strings.size(); i++)
mexPrintf("*%s\n", strings[i].c_str());
return;
*/
double *points = (double *)mxGetPr(prhs[3]);
int prows = mxGetM(prhs[3]), pcols = mxGetN(prhs[3]);
if (prows != strings.size()) {
mexErrMsgTxt("Error: the numbers of parsed text and pointers are not equal.\n");
return;
}

int fontFace =  FONT_HERSHEY_PLAIN;
int fontScale = mxGetScalar(prhs[4]);
int thickness = max(1, mxGetScalar(prhs[5]));
int linetype = CV_AA;

if (fontScale <= 0) {
mexErrMsgTxt("Error: fontsize is less than or equal to 0.\n");
return;
}

double *Color = mxGetPr(prhs[6]);
if (mxGetNumberOfElements(prhs[6]) != 3) {
mexErrMsgTxt("Error: text color should be a mat with 3 columns indicating RGB.\n");
return;
}
Scalar color;
color[0] = Color[0];
color[1] = Color[1];
color[2] = Color[2];

CvPoint startpt;
string str;
Size sz;

int baseLine = 0;
for(int i = 0; i < prows; i++) {
startpt = Point(points[i], points[i + prows]);
str = strings[i];
//sz = getTextSize(str, fontFace, fontScale, thickness, &baseLine);
putText( mat, str.c_str(), startpt, fontFace, fontScale, color, thickness, linetype );
}
}

string transClassID(mxClassID id) {
switch (id) {
case mxLOGICAL_CLASS: return "mxLOGICAL_CLASS";
case mxDOUBLE_CLASS: return "mxDOUBLE_CLASS";
case mxSINGLE_CLASS: return "mxSINGLE_CLASS";
case mxINT8_CLASS: return "mxINT8_CLASS";
case mxUINT8_CLASS: return "mxUINT8_CLASS";
case mxINT16_CLASS: return "mxINT16_CLASS";
case mxUINT16_CLASS: return "mxUINT16_CLASS";
case mxINT32_CLASS: return "mxINT32_CLASS";
case mxUINT32_CLASS: return "mxUINT32_CLASS";
case mxINT64_CLASS: return "mxINT64_CLASS";
case mxUINT64_CLASS: return "mxUINT64_CLASS";
default: return "unknown";
}
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
mxClassID classID = mxGetClassID(prhs[0]);
//mexPrintf("%d --> %s\n", classID, transClassID(classID).c_str());
if (classID != mxINT8_CLASS && classID != mxUINT8_CLASS) {
mexErrMsgTxt("Error: input image should be uint8 type with 3 channels.\n");
return;
}

char buf[256];
int cmdidx = -1;

mxGetString(prhs[1], buf, 255);
for(int i = 0; i < 4; i++) {
if (strcmp(buf, commands[i]) == 0)
{
cmdidx = i;
break;
}
}

if (cmdidx == -1)
{
mexErrMsgTxt("Error: command can not be recognized correctly.\n");
return;
}

const int *dims = mxGetDimensions(prhs[0]);
int height = dims[0], width = dims[1], channels = dims[2];
//mexPrintf("%d %d %d\n", height, width, channels);

if (channels != 3) {
mexErrMsgTxt("Error: input image should be of 3 channels.\n");
return;
}
if (height <= 0 || width <= 0) {
mexErrMsgTxt("Error: Wrong canvas sizes information.\n");
return;
}

//转换Matlab图像到Opencv图像
Mat mat = Mat::zeros(height, width, CV_8UC3);
char *inVals = (char *)mxGetPr(prhs[0]);
Vec3b vals;
for(int i = 0; i < mat.rows; i++)
for(int j = 0; j < mat.cols; j++) {
for(int c = 0; c < 3; c++)
vals[c] = inVals[c * mat.rows * mat.cols + j * mat.rows + i];
mat.at<Vec3b>(i, j) = vals;
}

switch(cmdidx) {
case 0: drawLines(mat, nrhs, prhs); break;
case 1: drawCircles(mat, nrhs, prhs); break;
case 2: drawRectanges(mat, nrhs, prhs); break;
case 3: drawTexts(mat, nrhs, prhs); break;
default: return;
};

nlhs = 1;
plhs[0] = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL);
char *outVals = (char *)mxGetPr(plhs[0]);

//转换Opencv图像到matlab图像
for(int i = 0; i < mat.rows; i++)
for(int j = 0; j < mat.cols; j++) {
vals = mat.at<Vec3b>(i, j);
for(int c = 0; c < 3; c++)
outVals[c * mat.rows * mat.cols + j * mat.rows + i] = vals[c];
}
}


3 Matlab测试程序

mex drawcanvas.cpp;

img = im2uint8(zeros(500, 500, 3));
close all;

tic;
%绘制线
%drawcanvas(img, cmd, pts_4_column, color, width)
img = drawcanvas(img, 'lines', rand(300, 4) * 500, [255 0 255], 1);

%绘制圆
%drawcanvas(img, cmd, circle_mat[x y r;], color, line_thickness)
xy = rand(30, 2) * 450 + 50;
r = rand(30, 1) .* (30 + rand(30, 1) * 100);
circles = [xy r];
img = drawcanvas(img, 'circles', circles, [0 0 255], 2);
%绘制实心圆--thickness=-1
img = drawcanvas(img, 'circles', [200 200 50], [0 255 255], -1);

%绘制矩形
%drawcanvas(img, cmd, rects_4_column, color, width)
img = drawcanvas(img, 'rectangles', rand(30, 4) * 200 + 100, [255 0 0], 1);

%绘制英文字符数组,用#分割不同数组
%drawcanvas(img, cmd, sliced_text_with_#\\n, points, fontScale, thickness, color)
img = drawcanvas(img, 'texts', 'Hello#world', [30 200; 200 250], 4, 4, [0 255 0]);
toc

imshow(img);

imwrite(img, 'canvas.png', 'png');


4 运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: