/////////////////////////////////////////////////////////////////////////
//简述:用MATLAB获取圆周模板,自定义封装susan的特征提取函数(GetUSAN),实现对图像的SUSAN特征检测,
// 关于SUSAN特征的原理请参考:https://blog.csdn.net/kezunhai/article/details/11269793。
//作者:Ephemeroptera
//地点:安徽大学
//最后修改时间:2018-11-20
//联系QQ:605686962
/////////////////////////////////////////////////////////////////////////
#include
#include
#include "engine.h"
#include"susan.h"
using namespace cv;
using namespace std;
int Multmax(int n, ...); // 定义多个变量的最大值提取
int main()
{
const uchar radius = 3;//本例选取半径为3即(7x7)的圆周模板
/*-----------------------------------进入MATLAB工作空间--------------------------------------------*/
Engine *ep = NULL; //申明引擎指针
if (!(ep = engOpen(""))) { //指向matlab工作空间
fprintf(stderr, "\nCan't start MATLAB engine\n");
return EXIT_FAILURE;
}
//在matlab引擎中执行matlab命令
engEvalString(ep, "template=fspecial('disk',3);%取7x7的圆周模板");
engEvalString(ep, "template(template>min(template(template>0)))=1; %模板二值化");
engEvalString(ep, "template(template<1)=0;");
engEvalString(ep, "[x,y]=find(template==1)%获取偏移地址");
//取出matlab工作空间中变量
mxArray* x = engGetVariable(ep, "x");
mxArray* y = engGetVariable(ep, "y");
//保存入c++向量中
std::vector offset;
double* p = mxGetPr(x); //实部指针
double* q = mxGetPr(y);
size_t offsetNum = mxGetNumberOfElements(x); //统计偏移地址个数个数
while (offsetNum > 0) //保存入向量中
{
offset.push_back(Point2i((int)*p++-radius-1, (int)*q++-radius-1));
--offsetNum;
}
cout << "圆周模板的偏移向量是:" << offset << endl;
/*-----------------------------------对图像的掩模处理--------------------------------------------*/
Mat RGB = imread("man.jpg"); //读取图片(RGB)
imshow("Original IMG", RGB);
Mat GRAY(RGB.size(), CV_8UC1);
cvtColor(RGB, GRAY, CV_BGR2GRAY); //灰度化(GRAY)
Mat USAN = Mat::zeros(RGB.size(), CV_8UC1);//定义USAN记录掩模滑动中USAN的值
GetUSAN(USAN, GRAY, offset, radius, 30,1/4.0); //空域处理,susan检测;这里是作者自己写的susan特征提取函数,
//有需要的同学可点击(https://download.csdn.net/download/ephemeroptera/10796926)下载
Mat BIN = USAN > 0; //USAN二值化
imshow("SUSAN to EDGE", BIN);
/*-----------------------------------角点检测(非极大值抑制)--------------------------------------------*/
std::vector corners; //定义角点
//对USAN遍历寻找极大值
for (int i = 1; i <= USAN.rows - 2; ++i)
for (int j = 1; j <= USAN.cols - 2; ++j)
{
// 该值大于8邻域值则判定为极大值
if (*USAN.ptr(i,j) > Multmax(8, *USAN.ptr(i - 1, j - 1), *USAN.ptr(i + 1, j + 1),
*USAN.ptr(i - 1, j + 1), *USAN.ptr(i + 1, j - 1),
*USAN.ptr(i, j - 1), *USAN.ptr(i, j + 1),
*USAN.ptr(i - 1, j), *USAN.ptr(i + 1, j)))
{
corners.push_back(Point2i(i, j)); //收纳极大值(corners)
circle(RGB,Point(j,i), 1, Scalar(0, 0, 255), -1);//标记SUSAN特征
}
}
namedWindow("SUSAN to CORNERS", WINDOW_NORMAL);
imshow("SUSAN to CORNERS", RGB);
waitKey(0);
return 0;
}
int Multmax(int n, ...) // 定参 n 表示后面变参数量,定界用,输入时切勿搞错
{
va_list ap; // 定义一个 va_list 指针来访问参数表
va_start(ap, n); // 初始化 ap,让它指向第一个变参
int maximum = -0x7FFFFFFF; // 这是一个最小的整数
int temp;
for (int i = 0; i < n; i++)
{
temp = va_arg(ap, int); // 获取一个 int 型参数,并且 ap 指向下一个参数
if (maximum < temp)
maximum = temp;
}
va_end(ap); // 善后工作,关闭 ap
return maximum;
}
附上生成结果: