WindowsMobile上使用ASIFT实现对视角变化更鲁棒的特征匹配
最近听cv领域的朋友说起asift,后来搜索了一下,发现asift比sift更能适应视角变化,并且开源了(网址:),真的要感谢jean-michel morel和guoshen yu两位大牛的无私奉献,让我这个超菜的业余爱好者也能玩上asift。
my_affine_sift项目提供asift的是基于c++并大量使用了stl,对于有c++经验的开发者来说不难使用。本文主要把asift的源码封装成dll,利用.net/.net cf平台丰富的图像编解码类库,更简便地在windows和windowsmobile平台上使用asift。
ps:由于c#与c++编译的dll之间不能传递stl对象,因此包含stl对象部分的处理都放在在dll内操作了。
先来看看本文代码实现的效果:
asift算法运行起来比较慢,比上次介绍的opencv的surf还慢,因此在移动设备上使用,就必须牺牲点准确率来换取速度了,左图是设定的识别率最低的匹配结果,右图是设定的识别率较低的结果。
本文的代码可以到这里下载:
下面是dll端的asift_dll.cpp的部分源码:
ps:由于不能传递stl对象,因此初始化第一张图片时就把第一张图片的特征点集合和其他长宽数据作为静态数据保存.......int num_of_tilts是控制识别率的参数,等于1时识别率最低。
view plaincopy to clipboardprint?
static int im_x=320;
static int im_y=240;
static vector< vector< keypointslist >> keys1;
std::vector<float> ipixels1;
static int ws1,hs1,w1,h1;
vector< vector< keypointslist >> loadkeypoints(std::vector<float> ipixels,int w,int h,int num_of_tilts,int * out_ws, int *out_hs);
matchingslist matchkeypoints(int num_of_tilts,int ws1,int hs1,int ws2,int hs2,vector< vector< keypointslist >> keys1,vector< vector< keypointslist >> keys2);
/**
* 初始化放大/缩小之后的图像大小
*/
extern "c" __declspec(dllexport) void initzoomsize(int w,int h)
{
im_x=w;
im_y=h;
}
/**
* 计算出图像1的特征点集合,并保存在静态变量
*/
extern "c" __declspec(dllexport) void initimage1(float *iarr,int w,int h,int num_of_tilts)
{
w1=w;
h1=h;
ipixels1=std::vector<float> (iarr, iarr + w * h);
keys1=loadkeypoints(ipixels1,w,h,num_of_tilts,&ws1,&hs1);
}
/**
* 计算出图象2的特征点集合,并与图像1的特征点集合做匹配,返回类似特征的数量
*/
extern "c" __declspec(dllexport) int match2imagefornum(float *iarr2,int w2,int h2,int num_of_tilts2)
{
int ws2, hs2;
std::vector<float> ipixels2(iarr2, iarr2 + w2 * h2);
vector< vector< keypointslist >> keys2=loadkeypoints(ipixels2,w2,h2,num_of_tilts2,&ws2,&hs2);
//// match asift keypoints
matchingslist matchings=matchkeypoints( num_of_tilts2, ws1, hs1, ws2, hs2, keys1, keys2);
return matchings.size();
}
/**
*计算出图象2的特征点集合,并与图像1的特征点集合做匹配,返回两图对比之后的图像像素数组
*/
extern "c" __declspec(dllexport) float * match2imageforimg(float *iarr2,int w2,int h2,int num_of_tilts2,int *outw,int * outh)
{
int ws2, hs2;
std::vector<float> ipixels2(iarr2, iarr2 + w2 * h2);
vector< vector< keypointslist >> keys2=loadkeypoints(ipixels2,w2,h2,num_of_tilts2,&ws2,&hs2);
//// match asift keypoints
matchingslist matchings=matchkeypoints( num_of_tilts2, ws1, hs1, ws2, hs2, keys1, keys2);
///////////////// output image containing line matches (the two images are concatenated one above the other)
int band_w = 10; // insert a black band of width band_w between the two images for better visibility
int wo = max(w1,w2);
int ho = h1+h2+band_w;
float areas = im_x * im_y;
float zoom1 = sqrt((w1 * h1)/areas);
float zoom2 = sqrt((w2* h2)/areas);
float *opixelsasift = new float[wo*ho];
for(int j = 0; j < (int) ho; j++)
for(int i = 0; i < (int) wo; i++) opixelsasift[j*wo+i] = 255;
/////////////////////////////////////////////////////////////////// copy both images to output
for(int j = 0; j < (int) h1; j++)
for(int i = 0; i < (int) w1; i++) opixelsasift[j*wo+i] = ipixels1[j*w1+i];
for(int j = 0; j < (int) h2; j++)
for(int i = 0; i < (int) (int)w2; i++) opixelsasift[(h1 + band_w + j)*wo + i] = ipixels2[j*w2 + i];
//////////////////////////////////////////////////////////////////// draw matches
matchingslist::iterator ptr = matchings.begin();
for(int i=0; i < (int) matchings.size(); i++, ptr++)
{
draw_line(opixelsasift, (int) (zoom1*ptr->first.x), (int) (zoom1*ptr->first.y),
(int) (zoom2*ptr->second.x), (int) (zoom2*ptr->second.y) + h1 + band_w, 255.0f, wo, ho);
}
*outw=wo;
*outh=ho;
return opixelsasift;
}
static int im_x=320;
static int im_y=240;
static vector< vector< keypointslist >> keys1;
std::vector<float> ipixels1;
static int ws1,hs1,w1,h1;
vector< vector< keypointslist >> loadkeypoints(std::vector<float> ipixels,int w,int h,int num_of_tilts,int * out_ws, int *out_hs);
matchingslist matchkeypoints(int num_of_tilts,int ws1,int hs1,int ws2,int hs2,vector< vector< keypointslist >> keys1,vector< vector< keypointslist >> keys2);
/**
* 初始化放大/缩小之后的图像大小
*/
extern "c" __declspec(dllexport) void initzoomsize(int w,int h)
{
im_x=w;
im_y=h;
}
/**
* 计算出图像1的特征点集合,并保存在静态变量
*/
extern "c" __declspec(dllexport) void initimage1(float *iarr,int w,int h,int num_of_tilts)
{
w1=w;
h1=h;
ipixels1=std::vector<float> (iarr, iarr + w * h);