图形绘制是标记和可视化数据的重要方法.
通过在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 =
2 编写drawcanvas.cpp文件
#include
#include
#include
#include "opencv2/opencv.hpp"
#include
#include
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; istartpt = 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; icpt = 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; istartpt = 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;
}
vectorstrings;
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; iif (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; imexPrintf("*%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; istartpt = 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; ifor(int j = 0; j for(int c = 0; c <3; c++)
vals[c] = inVals[c * mat.rows * mat.cols + j * mat.rows + i];
mat.at(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; ifor(int j = 0; j vals = mat.at (i, j);
for(int c = 0; c <3; c++)
outVals[c * mat.rows * mat.cols + j * mat.rows + i] = vals[c];
}
}
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 运行结果