WindowsMobile上使用ASIFT实现对视角变化更鲁棒的特征匹配

晨曦之光 发布于 2012/03/14 18:57
阅读 169
收藏 0

本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

        最近听CV领域的朋友说起ASIFT,后来搜索了一下,发现ASIFT比SIFT更能适应视角变化,并且开源了(网址:http://www.ipol.im/pub/algo/my_affine_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还慢,因此在移动设备上使用,就必须牺牲点准确率来换取速度了,左图是设定的识别率最低的匹配结果,右图是设定的识别率较低的结果。

本文的代码可以到这里下载:http://www.pudn.com/downloads312/sourcecode/windows/csharp/detail1387079.html

下面是DLL端的ASIFT_Dll.cpp的部分源码:

PS:由于不能传递STL对象,因此初始化第一张图片时就把第一张图片的特征点集合和其他长宽数据作为静态数据保存.......int num_of_tilts是控制识别率的参数,等于1时识别率最低。

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;
}

以下是C#端的部分源码,在C#端把图像(jpg/bmp/png等)转为灰度图(8bit的数组),然后传给DLL计算特征点,最后再把两幅图的特征点做匹配,并把匹配结果绘制出来:

        private void btnMatch_Click(object sender, EventArgs e)
        {
            initZoomSize(160, 240);
            Bitmap image1 = new Bitmap(getAppDir() + "//adam1.png");
            float[] grayImg1 = ImgToGray(image1);
            initImage1(grayImg1, image1.Width, image1.Height, 2);
            this.Text = " Image1 OK,please wait......";
            Bitmap image2 = new Bitmap(getAppDir() + "//adam2.png");
            float[] grayImg2 = ImgToGray(image2);
            
            int width = 0, height = 0;
            IntPtr result = Match2ImageForImg(grayImg2, image2.Width, image2.Height, 2, ref width, ref height);
            Bitmap resultImg = IntPtrToImg(result, width, height);
            this.pictureBox1.Image = resultImg;
            this.Text = "finish";
        }


原文链接:http://blog.csdn.net/hellogv/article/details/6087937
加载中
返回顶部
顶部