首页 > 代码库 > Matlab中利用mex编译Opencv实现画板绘图功能

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

图形绘制是标记和可视化数据的重要方法.

通过在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 运行结果


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