關於VisualSFM中的.sift和.mat文件詳細信息(包括讀、存等)

windows  VS2013實測可以,我自己改了一些東西,以便能運行

在項目|屬性|配置屬性|C/C++|預處理器|預處理定義中加入 _CRT_SECURE_NO_DEPRECATE

頭文件:

points.h

////////////////////////////////////////////////////////////////////////////
//	File:		points.h
//	Author:		Changchang Wu ([email protected])
//	Description : 
//
//  Copyright (c) 2011  Changchang Wu ([email protected])
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation; either
//  Version 3 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
////////////////////////////////////////////////////////////////////////////////



#ifndef POINTS_H_INCLUDED
#define POINTS_H_INCLUDED
#pragma once



template <class T> class Points;
//#define USE_MEM_COLLECT


template <class T>
class Points
{
	typedef T (*TV2)[2];
	typedef T (*TV3)[3];
	typedef T (*TV5)[5];
	typedef T (*TV128)[128];
protected:
	T *		_data;
	T **	_matrix;
	int		_width;
	int		_height; 
	bool	_subset;
private:
	void init(int width, int height)
	{
		_subset	=	0;
		if( width >0 && height >0 )
		{
			_matrix =	(T**) malloc(sizeof(T)*width*height+sizeof(T*)*height);
            if(_matrix)
            {
			    _data	=	(T* ) (_matrix+height);
			    T* temp =	_data;
			    for( int i =0 ; i < height; _matrix[i++]=temp, temp+=width);
		        _width	=	width;
		        _height	=	height;
            }else
            {
                _width = _height = 0;
			    _data = NULL;
            }
		}else
		{
            _width = _height = 0;
			_data = NULL;
			_matrix = NULL;
		}
	}

public:
	Points()
	{
		_data = NULL;
		_matrix = NULL;
		_height = 0;
		_width  = 0;
		_subset = 0;
	}
	Points(const Points<T> &ref)
	{
		init(ref.width(), ref.height());
		copy_from(ref, 0, 0);
	}
	Points(int width,  int height)
	{
		init(width, height);
	}
	Points(int width, int height, T v)
	{
		init(width, height);
		fill(v);
	}
	Points(T** sup, int ndim, int num)
	{
		_subset	=	true;
		_width	=	ndim;
		_height	=	num;
		_data	=	NULL;
		if(num>0 && ndim>0)
		{
			_matrix =  (T**) malloc(sizeof(T*)*num);
			for (int i = 0; i < num; i++) _matrix[i]= sup[i];
		}else
		{
			_matrix = NULL;
		}		
	}
    void setx(int width, int height, T* data)
    {
        release();
        _subset = 1;
        _width = width;
        _height = height;
        _data = data;
        _matrix = (T**) malloc(sizeof(T*) * height);
        for(int i = 0; i < height; i++, data += width) _matrix[i] = data;
    }
	

	template <class POINTS>
	Points(POINTS&   sup, int index [], int num)
	{
		_subset	=	true;
		_width	=	sup.width();
		_height	=	num;
		_data	=	sup.data();
		if(num>0 && _width>0)
		{
			_matrix =  (T**) malloc(sizeof(T*)*num);
			for (int i = 0; i < num; i++) _matrix[i]=sup[index[i]];
		}else
		{
			_matrix  = NULL;
		}
	}

	
private:
	void release()
	{
		if(_matrix)	free(_matrix);
	}
public:
	void resize(int width, int height)
	{
		if(width == _width && height ==_height) return;
		release();
        init(width, height);
	}
	void resize(int width, int height, T v)
	{
		resize(width, height);
		fill(v);
	}
	void expand(int width, int height)
	{
		//make sure size are 
		if(width < _width || height < _height) return;
		if(width ==_width && height ==_height && _subset ==0) return;
		T* newdata, **newmatrix, *temp;
		int i;
		newmatrix =	(T**) malloc(sizeof(T)*width*height+sizeof(T*)*height);
		temp = newdata	=	(T* ) (newmatrix+height);

		for( i =0 ; i < height;i++, temp+=width)
		{
			newmatrix[i]=temp;
		}
		for( i = 0; i< _height;  i++)
		{
			memcpy(newmatrix[i], _matrix[i], _width*sizeof(T));
		}
		release();
		_subset		=	0;
		_width		=	width;
		_height		=	height;
		_matrix		= newmatrix;
		_data		= newdata;
	}


	void expand(int width, int height, T v)
	{
		//make sure size are 
		if(width < _width || height < _height) return;
		if(width ==_width && height ==_height && _subset ==0) return;
		T* newdata, **newmatrix, *temp;
		int i, j;
		newmatrix =	(T**) malloc(sizeof(T)*width*height+sizeof(T*)*height);
		temp = newdata	=	(T* ) (newmatrix+height);

		for( i =0 ; i < height;i++, temp+=width)
		{
			newmatrix[i]=temp;
		}
		for( i = 0; i< _height;  i++)
		{
			memcpy(newmatrix[i], _matrix[i], _width*sizeof(T));
            for(j = _width; j < width; ++j) newmatrix[i][j] = v;
		}
        for(; i < height; i++)
        {
            for(j = 0; j < width; ++j) newmatrix[i][j] = v;
        }
		release();
		_subset		=	0;
		_width		=	width;
		_height		=	height;
		_matrix		= newmatrix;
		_data		= newdata;
	}

    void copy_from(const Points<T>& src, int dx, int dy)
    {
        int nw = min(src.width() , width() - dx);
        int nh = min(src.height(), height() - dy);
        /////////////////////////////////////////////
        for(int i = 0; i < nh; ++i)
        {
            for(int j = 0; j < nw; ++j)
            {
                _matrix[i + dy][j + dx] = src._matrix[i][j];
            }
        }
    }

	void swap(Points<T>& temp)
	{
		T *		data = _data;
		T **	matrix = _matrix;
		int		width = _width;
		int		height = _height; 
		bool	subset = _subset;
		_data	= temp._data;
		_matrix = temp._matrix;
		_width  = temp._width;
		_height = temp._height;
		_subset = temp._subset;
		temp._data = data;
		temp._matrix = matrix;
		temp._width = width;
		temp._height = height;
		temp._subset = subset;
	}

    void make_sub_from(Points<T>& src, int dx, int dy)
    {
        int nw = min(src.width() - dx , width());
        int nh = min(src.height()- dy, height() );
        /////////////////////////////////////////////
        for(int i = 0; i < nh; ++i)
        {
            for(int j = 0; j < nw; ++j)
            {
                _matrix[i][j] = src._matrix[i + dy][j + dx];
            }
        }
    }
	void shrink(int width, int height)
	{
		//make sure size are 
		if(width > _width || height > _height) return;
		if(width ==_width && height ==_height) return;
		T* newdata, **newmatrix, *temp;
		int i;
		newmatrix =	(T**) malloc(sizeof(T)*width*height+sizeof(T*)*height);
		temp = newdata	=	(T* ) (newmatrix+height);

		for( i =0 ; i < height;i++, temp+=width)
		{
			newmatrix[i]=temp;
		}
		for( i = 0; i< height;  i++)
		{
			memcpy(newmatrix[i], _matrix[i], width*sizeof(T));
		}
		release();
		_subset		=	0;
		_width		=	width;
		_height		=	height;
		_matrix		= newmatrix;
		_data		= newdata;
	}
	~Points()
	{
		release();
	}
	T* data()
	{
		return _data;
	}
	T* end()
	{
		return _data + _width * _height;
	}
	int invalid()
	{
		return _width == 0 || _height == 0;
	}
	int bsize()
	{
		return _width*_height*sizeof(T);
	}
	int width() const
	{
		return _width;
	}
	int height() const
	{
		return _height;
	}
	int ndim() const
	{
		return _width;
	}
	int npoint() const
	{
		return _height;
	}
	T* operator[](int i) 
	{
		return _matrix[i];
	}
	T* operator[](int i) const
	{
		return _matrix[i];
	}
	Points<T>& operator = (const Points<T>& ref)
	{
		resize(ref.width(), ref.height());
		if(_width > 0 && _height > 0)
		{
			if(ref._subset)
			{
				for(int i = 0; i < _height; ++i)
				{
					memcpy(_matrix[i], ref._matrix[i], _width * sizeof(T));
				}
			}else
			{
				memcpy(_data, ref._data, bsize());
			}
		}
		return * this; 
	}
	void own_data()
	{
		if(_subset)expand(_width, _height);
	}
	operator T** const () const
	{
		return _matrix;
	}
	operator T** () 
	{
		return _matrix;
	}
	operator TV2()
	{
#ifdef _DEBUG
		return _width==2 && _subset == 0 ? (T (*)[2]) _data : NULL;
#else
		return (T (*)[2]) _data;
#endif
	}
	operator TV3()
	{
#ifdef _DEBUG
		return _width==3 && _subset == 0 ? (T (*)[3]) _data : NULL;
#else
		return (T (*)[3]) _data ;
#endif
	}
	operator TV5()
	{
#ifdef _DEBUG
		return _width==5 && _subset == 0 ? (T (*)[5]) _data : NULL;
#else
		return (T (*)[5]) _data ;
#endif
	}
	operator TV128()
	{
#ifdef _DEBUG
		return _width==128 && _subset == 0 ? (T (*)[128]) _data : NULL;
#else
		return (T (*)[128]) _data ;
#endif
	}
	int checkdim(int dim)
	{
		if(dim >= _width) expand(_width * 2, _height);
		return _width;
	}

	T* getpt(int i)
	{
		return _matrix[i];
	}
	T* getpt(int i)const
	{
		return _matrix[i];
	}
	void fill(T v)
	{
		int i= _width*_height;
		T* temp= _data;
		for (; i>0; i--)*temp++= v;
	}

	void reorder(const int* index)
	{
		//
		if(0 ==_width && 0 ==_height) return;
		T* newdata, **newmatrix, *temp;
		int i;
		newmatrix =	(T**) malloc(sizeof(T)*_width*_height+sizeof(T*)*_height);
		temp = newdata	=	(T* ) (newmatrix+_height);

		for( i =0 ; i < _height;i++)
		{
			newmatrix[i]=temp;
			temp+=_width;
		}
		for( i = 0; i< _height;  i++)
		{
			memcpy(newmatrix[i], _matrix[index[i]], _width*sizeof(T));
		}
		release();
		_subset	=	0;
		_matrix = newmatrix;
		_data = newdata;

	}

};


//triangle matrix
template <class T>
class PointsT
{
protected:
	T **	_matrix;
	int		_width;
private:
	T** allocate(int width)
	{
		if( width >0 )
		{
            T** mat = (T**) malloc(sizeof(T*) * width);
            for(int i = 0; i < _width; ++i)
            {
                mat[i] = ((T*) malloc(sizeof(T) * (width - i))) - i;
            }
            return mat;
		}else
		{
            return NULL;
		}
	}
public:
	PointsT()
	{
		_matrix = NULL;
		_width  = 0;
	}
	PointsT(int width,  int height)
	{
        _width = width > height ? width  :height;
		_matrix = allocate(_width);
	}
	
	void release()
	{
		if(_matrix && _width > 0)	
        {
            for(int i = 0; i < _width; ++i)
            {
                free(_matrix[i] + i);
            }
            free(_matrix);
            _matrix = NULL;
            _width = 0;
        }
	}
public:
    void expand(int width, int height, T v)
    {
        expand(width > height ? width : height, v);
    }
	void expand(int width, T v)
	{
		//make sure size are 
		if(width <= _width ) return;

		T** newmatrix =	(T**) malloc(sizeof(T*)*width);     
        int i = 0, dw = width - _width;
		if(dw <= _width)
		{
			for(; i < dw; ++i)
			{
				newmatrix[i] = ((T*) malloc(sizeof(T) * (width - i))) - i;
				memcpy(newmatrix[i] + i, _matrix[i] + i, (_width - i) * sizeof(T));
				//memset(newmatrix[i] + _width, 0, dw * sizeof(T));
				for(int j = _width; j < width; ++j)newmatrix[i][j] = v;
			}
			for(; i < _width; ++i)
			{
				newmatrix[i] = _matrix[i - dw] - dw;
				memcpy(newmatrix[i] + i, _matrix[i] + i, (_width - i) * sizeof(T));
				//memset(newmatrix[i] + _width, 0, dw * sizeof(T));
				for(int j = _width; j < width; ++j)newmatrix[i][j] = v;
			} 
		}else
		{
			for(; i < _width; ++i)
			{
				newmatrix[i] = ((T*) malloc(sizeof(T) * (width - i))) - i;
				memcpy(newmatrix[i] + i, _matrix[i] + i, (_width - i) * sizeof(T));
				//memset(newmatrix[i] + _width, 0, dw * sizeof(T));
				for(int j = _width; j < width; ++j)newmatrix[i][j] = v;
			}
			for(; i < dw; ++i)
			{
				newmatrix[i] = ((T*) malloc(sizeof(T) * (width - i))) - i;
				//memset(newmatrix[i] + _width, 0, dw * sizeof(T));
				for(int j = i; j < width; ++j)newmatrix[i][j] = v;
			}
		}
           
        for(; i < width; ++i)
        {
            newmatrix[i] = _matrix[i - dw] - dw;
            for(int j = i; j < width;++j) newmatrix[i][j] = v;
        }
		
        free(_matrix);
        _matrix = newmatrix;
		_width		=	width;
	}

	~PointsT()
	{
		release();
	}

	int invalid()
	{
		return _width == 0;
	}
	int width() const
	{
		return _width;
	}

	int ndim() const
	{
		return _width;
	}

	T* operator[](int i) 
	{
		return _matrix[i];
	}
	T* operator[](int i) const
	{
		return _matrix[i];
	}
	operator T** const () const
	{
		return _matrix;
	}
	operator T** () 
	{
		return _matrix;
	}

	void fill(T v)
	{
		for(int i = 0; i < _width; ++i)
        {
            for(int j = i; j < _width; ++j)
            {
                _matrix[i][j] = v;
            }
        }
	}
};

#endif

FeaturePoints.h

////////////////////////////////////////////////////////////////////////////
//	File:		FeaturePoints.h
//	Author:		Changchang Wu ([email protected])
//	Description : 
//
//  Copyright (c) 2011  Changchang Wu ([email protected])
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation; either
//  Version 3 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
////////////////////////////////////////////////////////////////////////////////




#if !defined(FEATURE_POINTS_H_INCLUDED)
#define FEATURE_POINTS_H_INCLUDED
#pragma once


#include <fstream>
#include <vector>
#include <string>
using std::vector;
using std::ifstream;
using std::ofstream;
using std::string;

#include "points.h"



///////////////////////////////////////////////////////////////////
//DESCRIPTOR TYPE
typedef unsigned char	DTYPE;
//FEATURE LOCATION TYPE
typedef float LTYPE;


//#define DEBUG_DESCRIPTOR_BUG
////////////////////////////////////////////////////////////////////
////feature set with position info
//#define SIFT_LOCATION_NEW


class FeatureData 
{
	typedef struct sift_fileheader_v2
	{
		int	 szFeature;
		int  szVersion;
		int  npoint;
		int  nLocDim;
		int  nDesDim;
	}sift_fileheader_v2;
	typedef struct sift_fileheader_v1
	{
		int  npoint;
		int  nLocDim;
		int  nDesDim;
	}sift_fileheader_v1;
	enum
	{
//		READ_BUFFER_SIZE = 0x100000,
		SIFT_NAME= ('S'+ ('I'<<8)+('F'<<16)+('T'<<24)),
		MSER_NAME= ('M'+ ('S'<<8)+('E'<<16)+('R'<<24)),
		RECT_NAME= ('R'+ ('E'<<8)+('C'<<16)+('T'<<24)), 
		//SIFT_VERSION_2=('V'+('2'<<8)+('.'<<16)+('0'<<24)),
		//SIFT_VERSION_3=('V'+('3'<<8)+('.'<<16)+('0'<<24)),
		SIFT_VERSION_4=('V'+('4'<<8)+('.'<<16)+('0'<<24)),
		SIFT_VERSION_5=('V'+('5'<<8)+('.'<<16)+('0'<<24)),
		SIFT_EOF = (0xff+('E'<<8)+('O'<<16)+('F'<<24)),
	};
//	static char readBuf[READ_BUFFER_SIZE];
//	static char sift_version[8];
	static inline int IsValidFeatureName(int value)
	{
		return value == SIFT_NAME || value == MSER_NAME;
	}
	static inline int IsValidVersionName(int value)
	{
		return value == SIFT_VERSION_4 || value == SIFT_VERSION_5;
	}
public:
	class LocationData: public Points<LTYPE>
	{
	public:
	    int              _file_version;
	public:
		//each feature has x,y, z, size, orientation
		//for rect feature, there is x, y, width, height
		//for eclips feature, there is u,v,a,b,c +z
	public:
		void glPaint2D(int style);
		LocationData(int d, int n):Points<LTYPE>(d,n),  _file_version(0){	};
		LocationData( LocationData& sup, int index[], int n): Points<LTYPE>(sup,index,n), _file_version(0){};
		static void glPaintTexSIFT(const float * loc, float td[3]);
		static void glPaintTexFrontalVIP(const float * loc, float td[3]);
		static void glPaintSIFT(const LTYPE* loc);
		static void glPaintSIFTSQ(LTYPE*  loc);
		static void glPaintELIPS(LTYPE*  loc);
		static void glPaintRECT(LTYPE* loc);
	    static void SetPaintColor(LTYPE sz);
	};

	class DescriptorData: public Points<DTYPE>
	{
		//generally d is 128
	public:
		DescriptorData(DescriptorData& sup, int index[], int n): Points<DTYPE>(sup,index,n){};
		DescriptorData(int d, int n):Points<DTYPE>(d,n){};
	};
	static float gSiftDisplayScale;
	static int	 gSiftVisualStyle;
protected:
	void ReadFeatureDataA(ifstream & is, int npt,  int locDim, int desDim, int szFeatureName);
	// the set of feature descriptors
	DescriptorData * _desData;
	// the set of feature locations
	LocationData *   _locData;
    int              _npoint;
	int				 _updated;
public:
	void SetUpdated(){_updated = 1;}
	int  GetUpdated(){return _updated;}
	void CopyToFeatureData(FeatureData &fd);
	int  appendSIFTB(const char* szFile,int pos);
	int  validate()	{		return _locData && _desData;	}
	void ResizeFeatureData(int npoint, int locDim = 5, int desDim = 128)
	{
		if(npoint ==0)
		{
			if(_locData) delete _locData;
			if(_desData) delete _desData;
			_locData = NULL;
			_desData = NULL;
		}else
		{
			if(_locData)
				_locData->resize(locDim, npoint);
			else
				_locData = new LocationData(locDim, npoint);
			if(_desData)
				_desData->resize(desDim, npoint);
			else
				_desData = new DescriptorData(desDim, npoint);
			_locData->_file_version  = SIFT_VERSION_4;
		}
		_npoint = npoint;

	}
	void operator = (FeatureData& ref) { ref.CopyToFeatureData(*this); }
	void ResizeLocationData(int npoint, int locDim)
	{
		if(npoint ==0)
		{
			if(_locData) delete _locData;
			if(_desData) delete _desData;
			_locData = NULL;
			_desData = NULL;
		}else
		{
			if(_locData)
				_locData->resize(locDim, npoint);
			else
				_locData = new LocationData(locDim, npoint);
			if(_desData)
			{
				delete _desData;
				_desData = NULL;
			}
			_locData->_file_version  = SIFT_VERSION_4;	
		}
	}

	void ShrinkLocationData(int ndim = 2, int npoint = -1);
	void ReleaseDescriptorData()
	{
		if(_desData)
		{
			delete _desData;
			_desData = NULL;
		}
	}
public:
	void SortSIFT();
	void SaveSIFTBClip(const char* szFileName, int x1, int x2, int y1, int y2);
	int ValidateIndex(int index[], int n);
	void ConvertA2B(const char* szFile);
	void SaveDescriptorFile(const char* szFeatureFile);
	void SaveLocationFile(const char* szFeatureFile);
	static int ReadRandomFeature(const char* path, double* pt, int nDim);
	static int ExportSIFT(const char*featurefile, Points<double>& points);
	static int OpenSeekSIFT(const char* featurefile, int& npoint, int& ndim);
	static int ExportSIFT(const char* featurefile, int fdx);
	int  ReadSIFTB(const char* szFile);
	int  ReadSIFTB_LOC(const char* szFile);
	int  ReadSIFTB_LOCT(const char* szFile, int fmax);
	int  ReadSIFTB_DES(const char* szFile, int fmax);
	static int ReadSIFTB_DES(const char* szFile, unsigned char * buf, int nmax);
	static int ReadSIFTA_DES(const char* szFile, unsigned char * buf, int nmax);
	static int ReadSIFTB_LOC(const char* szFile, float * buf, int nmax ); 
	static int ReadSIFTB(const char* szFile, float * locbuf, unsigned char * desbuf, int nmax);
	void offsetFeatures(int ox, int oy);
	void saveSIFTB2(const char* szFile);
	void saveSIFTA(const char* szFile, const int nDesDim = 128);
	void Overwrite_SIFTLOC(const char* szFile);
	void CreateFeatureClip(FeatureData& src, int x1, int x2, int y1, int y2, int smax =100000 );
	void SetFeatureClip(FeatureData&src, int nsf, int index[], int subset = 1);
	void ReleaseFeatureData();
	void FlipLocation(float imheight);
	int ReadSIFTA(const char* szFile);
	FeatureData();
	virtual ~FeatureData();
	DescriptorData&  getDescriptorData() {return *_desData;}
	LocationData&   getLocationData()const {return *_locData;}
	int		IsValidFeatureData(){return getFeatureNum() > 0;}
	int		getFeatureNum(){return _npoint;}
	int		getLoadedFeatureNum(){return _locData? _locData->npoint(): 0;}
};


typedef FeatureData::LocationData FeatureLocationData;
typedef FeatureData::DescriptorData FeatureDescriptorData;


#endif // !defined(FEATURE_POINTS_H_INCLUDED)

MatchFile.h

////////////////////////////////////////////////////////////////////////////
//	File:		MatchFile.h
//	Author:		Changchang Wu ([email protected])
//	Description : 
//
//  Copyright (c) 2011  Changchang Wu ([email protected])
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation; either
//  Version 3 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
////////////////////////////////////////////////////////////////////////////////




#ifndef MATCH_FILE_H_INCLUDED
#define MATCH_FILE_H_INCLUDED
#pragma once


#include <vector>
#include <string>
using std::vector;
using std::string;
#include "points.h"
#define MAX_PATH 260

////////////////////////////////////////////////////////////////////////
//+++To read the number of matches of iamge1 and image2------------------------------
//Ues member funcation  -----MatchFile::GetMatchCount--------------------------------
//int NM;		//number of putative matches
//int NF;		//number of inlier matches
//MatchFile mat(image1_full_path); //image1
//if(mat.IsValid() && mat.GetMatchCount(image2_full_path, NM, NF)) {/*we have it*/}

////////////////////////////////////////////////////////////////////////
//+++To read back putative matches----------------------------------------------------
//use member function ----MatchFile::GetPMatch----------------------------------------
//int FC;		//feature count of image2, input
//int NM;		//number of putative matches, output
//Points<int>	matches;// feature index of putative matches, output
//MatchFile mat(image1_full_path); //image1's match database
//if(mat.IsValid() && mat.GetPMatch(image2_full_path, FC, NM, matches)) {/* we have it*/};

//////////////////////////////////////////////////////////////////////////
//+++To write puattive matching----------------------------------------------------------
//Use static function ----MatchFile::WritePMatch---------------------------------------
//You can call MatchFile::WritePMatch(
//		char* image1_full_path_no_extension,
//		char* image2_full_path_no_extension, 
//		int feature_count_of_image1, 
//		int feature_count_of_image2, 
//	    int number_of_matches,
//		Points<int>& matches)
//
//		You should call matches.resize(number_of_matches, 2) to form the matrix
//		matches[0][] are the indices of image1
//		matches[1][] are the indices of image2


struct TwoViewGeometry{
	int   NF, NE;	// ni fundamental/essential matrix
	int   NH, NH2;	// ni homogrphy
	float F[3][3];	// fundamental matrix
	float R[3][3];	// rotation
	float T[3];		// translation
	float F1, F2;	//
	float H[3][3];	//
	float GE;		// geometric error 
	float AA;		// triangulation angle
	TwoViewGeometry()
	{
		NF = NE = NH = NH2 = 0;
		AA = F1 = F2 = 0.0;	
		GE = 100.0f;
	}
	//simple geometry
	TwoViewGeometry(int Num, float FMat[3][3])
	{
		NF = Num;
		NE = NH = NH2 = 0;
		AA = F1 = F2 = 0.0;
		GE = 100.0f;
		memcpy(F, FMat, sizeof(F));
	}
	void ResetGeometry()
	{
		NF = NE = NH = NH2 = 0;
		AA = F1 = F2 = 0.0;
		GE = 100.0f;		
	}
	void ExchangeView()
	{
		float RT[3][3] = {	{R[0][0], R[1][0], R[2][0]},
							{R[0][1], R[1][1], R[2][1]},
							{R[0][2], R[1][2], R[2][2]}};
		float TT[3] = {	-R[0][0] * T[0] - R[1][0] * T[1] - R[2][0] * T[2],
						-R[0][1] * T[0] - R[1][1] * T[1] - R[2][1] * T[2],
						-R[0][2] * T[0] - R[1][2] * T[1] - R[2][2] * T[2]};
		float FT[3][3] = {	{F[0][0], F[1][0], F[2][0]},
							{F[0][1], F[1][1], F[2][1]},
							{F[0][2], F[1][2], F[2][2]}	};
		memcpy(F, FT, sizeof(F));
		memcpy(R, RT, sizeof(R));
		memcpy(T, TT, sizeof(T));
		float TF = F1;	F1 = F2;	F2 = TF;
	}
	static void TransposeMatrix33(const float M[3][3], float MT[3][3])
	{
		MT[0][0] = M[0][0];	MT[0][1] = M[1][0];	MT[0][2] = M[2][0];
		MT[1][0] = M[0][1];	MT[1][1] = M[1][1];	MT[1][2] = M[2][1];
		MT[2][0] = M[0][2];	MT[2][1] = M[1][2];	MT[2][2] = M[2][2];
	}
	void SetGeometryR(const TwoViewGeometry& g)
	{
		NF = g.NF;	NE = g.NE;	
		NH = g.NH;	NH2 = g.NH2;
		GE = g.GE;	AA = g.AA;
		F1 = g.F2;	F2 = g.F1;
		if(g.NF > 0)
		{
			TransposeMatrix33(g.F, F);
			if(g.NE > 0)
			{
				/////////////////////////////////////////////////////////////
				TransposeMatrix33(g.R, R);
				//////////////////////////////////////////////////////////////////
				T[0] = -R[0][0] * g.T[0] - R[0][1] * g.T[1] - R[0][2] * g.T[2];
				T[1] = -R[1][0] * g.T[0] - R[1][1] * g.T[1] - R[1][2] * g.T[2];
				T[2] = -R[2][0] * g.T[0] - R[2][1] * g.T[1] - R[2][2] * g.T[2];
			}
		}
		if(g.NH2 > 0)	TransposeMatrix33(g.H, H);
	}

	void SetGeometry(const TwoViewGeometry& g)
	{
		NF = g.NF;	NE = g.NE;	
		NH = g.NH;	NH2 = g.NH2;
		GE = g.GE;	AA = g.AA;
		F1 = g.F1;	F2 = g.F2;

		if(g.NF > 0)	
		{
			memcpy(F, g.F, sizeof(F));
			if(g.NE > 0)
			{
				memcpy(R, g.R, sizeof(R));
				T[0] = g.T[0];	T[1] = g.T[1];	T[2] = g.T[2];
			}
		}
		if(g.NH2 > 0)	memcpy(H, g.H, sizeof(H));
	}
};

class NamedMutex; 

class MatchFile
{
	enum
	{
		MATCH_FILE_VERSION_3= ('M'+ ('T'<<8)+('0'<<16)+('3'<<24)),
		MATCH_FILE_LATEST_VERSION = MATCH_FILE_VERSION_3,
		MATCH_RECORD_V3 = ('M'+ ('R'<<8)+('V'<<16)+('3'<<24)),
	};

	struct MatchRecordV3{
		int	version;
		TwoViewGeometry	tvg;
		int	 extra[7]; //reserved data for future change;
		////////////////////////////////////////////////////
		MatchRecordV3()
		{
			version = MatchFile::MATCH_RECORD_V3;
			memset(extra, 0, sizeof(extra));
		}
	};

	//image file can change..
	//number of features can change. 
	//exif focal length can change. 
	struct FileHeader
	{
		int		version;
		int		file_count;
		int		definition_size;	//
		int		definition_buf;		//
		int		feature_count;		//this might change..
	};

	struct RecordLoc
	{
		int		fcount;
		int		read_loc;		// read location
		int		block_size;		// block size
		int		trash_size;		// trash size after 
		int		extra_size;		//
		char	file_name[4];
	};

private:
	static int	multi_thread_mode;
	static int	file_title_mode;
	static int	delay_header_update;
	static int  record_reservation;
	static int  num_match_verification;
private:
	NamedMutex*			_mutex;
	int					_fid; 
	int					_opened_for_write;
	int					_header_changed;
	size_t				_recordloc_unchanged;
	int					_matchfile_mode;
	FileHeader			_header;
	char				_filepath[MAX_PATH];
	const char*			_title;
	vector<char>		_record_definition;
	vector<RecordLoc*>	_match_records;
private:
    void DeleteMatchRecord(const char* pattern = "extra");
	void GetRecordList();
	void MoveRecordToEnd(int i);
	void GetMatchFilePath(char* match_path);
	void GetMatchFolderPath(char* match_path);
	int  AddImageMatch(const char* relative_path);
	int  GetImageIndex(const char* relative_path);
	void GetRelativePath(const char* image_match, char* relative_path);
	void UpdateHeaderAndRecordLoc();
	void ResetMatchFile();
public:
	//print out messages
	static int (*matchfile_printf)(const char* format,... ) ;
	static void SetPrintFunction(int (*printf_func)(const char* format,... ));
	static void GetRelativePath(const char* path1, const char* path2, char* relative_path);
	static void SetMultiThreadMode(int multi_thread)	{	multi_thread_mode = multi_thread;			}
	static void SetFileTitleMode(int use_title)			{	file_title_mode = use_title;				}
	static void SetRecordReservation(int num)			{	record_reservation = (num > 1? num : 1);	}
public:
	MatchFile();
	MatchFile(const char* image_path, int guided = 0);
	~MatchFile();
	int IsValid(){return _fid >0;}
	int IsMatchFileOfImage(const char* fullpath, const char* title);
public:
	int  OpenMatchFile(const char* image_path, int write, int mode = 0);
	int  MakeWritable();
	int  HaveMatchRecord(const char* absolute_path);
	void DeleteMatchFile();
	void VerifyFeatureCount(int feature_count);
	void CloseMatchFile();
	void GetMatchedImageList(vector<string>& paths);
    void SaveSubsetMatch(vector<string>& paths, vector<int>& fc);

public:
	//////////////////////////read matches
	int GetMatchCount(const char* image_path, int&NM, int& NF);
	int GetPMatch(const char* image_path, int FC, int& NM, Points<int>& matches);
	int GetIMatch(const char* image_path, int FC, TwoViewGeometry& tvg, Points<int>&inliers);
	int GetPMatchR(const char* image_path, int FC, int& NM, Points<int>& matches);
	int GetIMatchR(const char* image_path, int FC, TwoViewGeometry& tvg, Points<int>&inliers);
public:
	//////////////////////////////write matches
	void WriteIMatch(const char* image_match, int reverse, int NM, TwoViewGeometry& tvg, Points<int>&inliers);
	void WritePMatch(const char* image_match, int FC, int NM, Points<int>&matches, int reverse);

public:
	////////////////////static functions
	static void WriteIMatch(const char* image1, const char* image2, int NM, TwoViewGeometry& tvg, Points<int>&inliers);
	static void WriteIMatch(MatchFile* mat, const char* image1, const char* image2, int NM, TwoViewGeometry& tvg, Points<int>&inliers);
	static void WritePMatch(const char* image1, const char* image2, int fc1, int fc2, int NM, Points<int>& matches);
	static void WriteFMatch(const char* image1, const char* image2, int NF,	int * index1, int * index, float F[3][3]);
	///////////////////////////////////////
	friend  struct MatchFile::MatchRecordV3;
};

#endif

FeaturePoints.cpp

////////////////////////////////////////////////////////////////////////////
//	File:		FeaturePoints.cpp
//	Author:		Changchang Wu ([email protected])
//	Description : 
//
//  Copyright (c) 2011  Changchang Wu ([email protected])
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation; either
//  Version 3 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
////////////////////////////////////////////////////////////////////////////////
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <math.h>
#include <string>
#include <fstream>
#include <algorithm>
using namespace std;

#include "FeaturePoints.h"

float FeatureData::gSiftDisplayScale = 6.0f;
int FeatureData::gSiftVisualStyle = 0;


//////////////////////////////////////////////////////////////////////
// Construction/Destruction

FeatureData::FeatureData()
{
	_desData  = NULL;
	_locData  = NULL;
	_updated  = 0;
    _npoint = 0;
}

FeatureData::~FeatureData()
{
	
	if (_desData) delete _desData;
	if (_locData) delete _locData;
}

int FeatureData::ReadSIFTA(const char* szFile)
{
	int npt=0, nd=0;
	ifstream is(szFile);
	if(!is.is_open())return 0;
	is>> npt >> nd;
	if (npt <= 0 || nd <= 0 ) 
	{
		_npoint = 0;
		is.close();
		return 0;
	}else
	{
		ReadFeatureDataA(is, npt, 4, nd, SIFT_NAME);
		is.close();
		SetUpdated();
		return 1;
	}
}


void FeatureData::ReadFeatureDataA(ifstream &is, int npt, int locDim, int desDim, int szFeatureName)
{
	int i, j;
	
	///////////////////////////////////////
    _npoint = npt;
	_locData = new LocationData( locDim +1, npt);//one more column for z
	_desData = new DescriptorData(desDim, npt);
	LTYPE * pLoc = _locData->data();
	DTYPE *	pDes = _desData->data();


	////////////////////////////////////////////////
	for ( i = 0 ; i< npt; i++)
	{

		if( locDim ==4)
		{
			is>> *(pLoc+1); //x
			is>> *pLoc; //
		}else
		{
			is>> *pLoc; //x
			is>> *(pLoc+1); //y
		}
		//SIFT_LOCATION_NEW
		pLoc[0] += 0.5f; 
		pLoc[1] += 0.5f; 
		pLoc[2] = 0;
		pLoc+=3;
		if (locDim ==4)
		{
			is>> pLoc[0];
			is>> pLoc[1];
			pLoc[1] = - pLoc[1];//flip the angle
			pLoc+=2; 
		}else
		{
			is>> *pLoc++;
			is>> *pLoc++;
			is>> *pLoc++;
		}

		for ( j = 0 ; j< desDim; j++)
		{
			unsigned int value;
			is >> value;
			*pDes++ = value;
		}
	}
}

void FeatureData::CopyToFeatureData(FeatureData &fd) 
{
	if(getFeatureNum()>0)
	{
		fd.ResizeFeatureData(getFeatureNum(), getLocationData().ndim(), 128);
		fd.getLocationData() = getLocationData();
		fd.getDescriptorData() = getDescriptorData();
		//memcpy(fd.getLocationData().data(), getLocationData().data(), getLocationData().bsize());
		//memcpy(fd.getDescriptorData().data(), getDescriptorData().data(), getDescriptorData().bsize());
	}
}

void FeatureData::FlipLocation(float imheight)
{

	if(_locData == NULL) return;
	LTYPE * feature; 
	if(_locData->ndim()==5)
	{
		for (int i = 0 ; i< _locData->npoint();i++)
		{
			feature = _locData->getpt(i);
			feature[1] = imheight - feature[1];
		}
	}else if(_locData->ndim()==6)
	{
		for (int i = 0 ; i< _locData->npoint();i++)
		{
			feature = _locData->getpt(i);
//	SIFT_LOCATION_NEW
			feature[1] = imheight - feature[1];
			feature[4] = - feature[4];
		}

	}
}

void FeatureData::ReleaseFeatureData()
{
	if (_locData ) delete _locData;
	if (_desData ) delete _desData;
	_locData = NULL;
	_desData = NULL;
	_npoint = 0;
}


void FeatureData::SetFeatureClip(FeatureData&src, int nsf, int index[], int subset)
{
	ReleaseFeatureData();
	if(subset)
	{
		if(src._locData) _locData = new LocationData(src.getLocationData(), index, nsf);
		if(src._desData) _desData = new DescriptorData(src.getDescriptorData(), index, nsf);
	}else
	{
		FeatureData fd2;
		fd2.SetFeatureClip(src, nsf, index, 1);
		ResizeFeatureData(nsf, src._locData->width(), src._desData->width());
		getLocationData() = fd2.getLocationData();
		getDescriptorData() = fd2.getDescriptorData();
	}
	SetUpdated();
}

void FeatureData::offsetFeatures(int ox, int oy)
{
	if(_locData == NULL) return;
	LTYPE dox = (LTYPE) ox, doy = (LTYPE) oy;
	LTYPE * feature;
	for (int i = 0 ; i< _locData->npoint();i++)
	{
		feature = _locData->getpt(i);
		feature[0] =  feature[0]  + dox ;
		feature[1] =  feature[1]  + doy;
	}
}

void FeatureData::	saveSIFTA(const char* szFile, const int nDesDim)
{
	if(_locData == NULL) return ;
	int n = _locData->npoint();
	if(n <=0) return;
	ofstream out(szFile);
	out << n << " " << nDesDim <<"\n";
	//
	for(int i = 0; i < n; i++)
	{
		LTYPE * loc = _locData->getpt(i);
		unsigned char * des = _desData->getpt(i);
		out << loc[1] << " " << loc[0] << " " << loc[3] << " " << loc[4] << endl;
		for(int k = 0; k < nDesDim; k ++) 
		{
			out<< ((unsigned int)des[k])<<" ";
			if ( (k+1)%20 == 0 ) out<<endl; 
		}
		out<<endl;
	}
}

void FeatureData::saveSIFTB2(const char* szFile)
{

	int i,j, sift_eof = SIFT_EOF;
	sift_fileheader_v2 sfh;
	int fd = _open(szFile, _O_BINARY|_O_CREAT|_O_WRONLY|_O_TRUNC,_S_IREAD |_S_IWRITE);
	if(fd<0) return;

	///
	sfh.szFeature=SIFT_NAME;
	sfh.szVersion=  SIFT_VERSION_4;
	sfh.npoint  = _locData->npoint();
	sfh.nLocDim = _locData->ndim();
	sfh.nDesDim = _desData->ndim();
	_write(fd, &sfh, sizeof(sfh));
	////
	LTYPE * lp;
	DTYPE * dp;
	unsigned char* fph; 
	float  *fp;
	unsigned char * ucp;
	int Max, MemNum;
	lp =  _locData->data();
	MemNum = sfh.nDesDim * sfh.npoint;
	Max = sfh.npoint*sfh.nLocDim;
	fph= new unsigned char[MemNum]; //MemCollect::Malloc(MemNum);
	fp = (float*) fph;
	
	for( i = 0; i < sfh.npoint; i++)
	{
		lp = (*_locData)[i];
		for(j=0;j<sfh.nLocDim;j++)
		{
			*fp++ = (float) *lp++;
		}
	}
	_write(fd,fph,sizeof(float)*Max);

	dp = _desData->data();
	Max = sfh.npoint*sfh.nDesDim;
	ucp = (unsigned char*) fph;
	for( i = 0; i < sfh.npoint; i++)
	{
		dp = (*_desData)[i];
		for(j=0;j<sfh.nDesDim;j++,dp++)
		{
			*ucp++ = *dp;
		}
	}
	_write(fd,fph,sizeof(unsigned char)*Max);
	_write(fd,&sift_eof, sizeof(int));
	_close(fd);
}

int FeatureData::ReadSIFTB(const char* szFile)
{
	int name, version, npoint, nLocDim, nDesDim, sift_eof, sorted = 0;
	int fd = _open(szFile, _O_BINARY|_O_RDONLY,_S_IREAD);
	if (fd<0) return 0;
	///
	_read(fd, &name, sizeof(int));
	_read(fd, &version, sizeof(int));
	if(IsValidFeatureName(name) && IsValidVersionName(version))
	{
		//version 2 file
		_read(fd, &npoint, sizeof(int));
		_read(fd, &nLocDim, sizeof(int));
		_read(fd, &nDesDim, sizeof(int));
		if(npoint>0 && nLocDim >0 && nDesDim==128)
		{
			ResizeFeatureData(npoint,nLocDim,nDesDim);
			_read(fd,_locData->data(), nLocDim *npoint*sizeof(float));
			_read(fd,_desData->data(), nDesDim*npoint*sizeof(unsigned char));
			_read(fd,&sift_eof,sizeof(int));
			//assert(sift_eof == SIFT_EOF);
			_close(fd);
			_locData->_file_version = version;
			SetUpdated();
#ifdef DEBUG_DESCRIPTOR_BUG
			unsigned char * pb = desData->data();
			int bad_descriptor_count = 0;
			for(int i = 0; i < npoint; ++i, pb+=128)
			{
				int good_descriptor = 0;
				for(int j = 0; j < 128; ++j)
				{
					if(pb[j]!=45)
					{
						good_descriptor = 1;
						break;
					}
				}
				if(good_descriptor==0) bad_descriptor_count++;
			}
			if(bad_descriptor_count) printf("xxxxxx %d bad descriptor xxxxxx\r\n", bad_descriptor_count);
#endif
		}else
		{
			ResizeFeatureData(0, 0, 0);
			_close(fd);
			return 0;
		}
		return 1;
	}else 
	{
		_close(fd);
		return 0;
	}
}

int FeatureData::ReadSIFTB_DES(const char* szFile, int fmax)
{
	sift_fileheader_v2 sfh;	
	int fd = _open(szFile, _O_BINARY|_O_RDONLY,_S_IREAD);
	if (fd<0) return 0;
	///
	_read(fd, &sfh, sizeof(sfh));

    int npoint = fmax > 0 ? min(sfh.npoint, fmax) : sfh.npoint;
	if(_desData)
		_desData->resize(sfh.nDesDim, npoint);
	else
		_desData = new DescriptorData(sfh.nDesDim, npoint);
	_lseek(fd, sfh.nLocDim *sfh.npoint*sizeof(float), SEEK_CUR);
	_read(fd,_desData->data(), sfh.nDesDim*npoint*sizeof(unsigned char));
	_close(fd);
	return 1;
}

int FeatureData::ReadSIFTB_LOC(const char* szFile, float * buf, int nmax )
{
	sift_fileheader_v2 sfh;	
	int fd = _open(szFile, _O_BINARY|_O_RDONLY,_S_IREAD);
	if (fd<0) return 0;
	///
	_read(fd, &sfh, sizeof(sfh));
	
	nmax = min(nmax, sfh.npoint);
		
	_read(fd, buf, sfh.nLocDim *sfh.npoint*sizeof(float));
	_close(fd);
	return nmax;
}

int FeatureData::ReadSIFTB_DES(const char* szFile, unsigned char * buf, int nmax )
{
	sift_fileheader_v2 sfh;	
	int fd = _open(szFile, _O_BINARY|_O_RDONLY,_S_IREAD);
	if (fd<0) return 0;
	///
	_read(fd, &sfh, sizeof(sfh));
	
	nmax = min(nmax, sfh.npoint);
		
	_lseek(fd, sfh.nLocDim *sfh.npoint*sizeof(float), SEEK_CUR);
	_read(fd, buf, sfh.nDesDim* nmax*sizeof(unsigned char));
	_close(fd);
	return nmax;
}

int FeatureData::ReadSIFTA_DES(const char* szFile, unsigned char * buf, int nmax )
{
	FeatureData fd;
	fd.ReadSIFTA(szFile);
	if(fd.getLocationData().getpt(0)[3] < fd.getLocationData().getpt(fd.getFeatureNum() -1)[3])
	{
		//sort
		fd.SortSIFT();
	}
	nmax = min(nmax, fd.getFeatureNum());
	if(nmax > 0)
	{
		memcpy(buf, fd.getDescriptorData().data(), nmax * 128);
	}
	return nmax;
}


int FeatureData::ReadSIFTB(const char* szFile, float * locbuf, unsigned char * desbuf, int nmax)
{
	sift_fileheader_v2 sfh;	
	int fd = _open(szFile, _O_BINARY|_O_RDONLY,_S_IREAD);
	if (fd<0) return 0;
	///
	_read(fd, &sfh, sizeof(sfh));
	
	nmax = min(nmax, sfh.npoint);
		
	_read(fd, locbuf, sfh.nLocDim *sfh.npoint*sizeof(float));
	_read(fd, desbuf, sfh.nDesDim* nmax*sizeof(unsigned char));
	_close(fd);
	return nmax;

}


int FeatureData::ReadSIFTB_LOC(const char* szFile)
{
	sift_fileheader_v2 sfh;	
	int fd = _open(szFile, _O_BINARY|_O_RDONLY,_S_IREAD);
	if (fd<0) return 0;
	///
	_read(fd, &sfh, sizeof(sfh));
	if(IsValidFeatureName(sfh.szFeature) && IsValidVersionName(sfh.szVersion))
	{
		//version 2 file
		if(sfh.npoint>0 && sfh.nLocDim >0 && sfh.nDesDim==128)
		{
			_npoint = sfh.npoint;
			ResizeLocationData(sfh.npoint,sfh.nLocDim);
            if(_locData->data())
            {
			    _read(fd,_locData->data(), sfh.nLocDim *sfh.npoint*sizeof(float));
				_locData->_file_version  = sfh.szVersion;
            }else
            {
                printf("ERROR: ReadSIFTB_LOC allocatoin faled\r\n");
            }
			_close(fd);
			SetUpdated();
		}else
		{
			ResizeFeatureData(0, 0, 0);
			_close(fd);
			return 0;
		}
		return 1;
	}else
	{
		_npoint = 0;
		_close(fd);
		return 0;
	}



}

int FeatureData::appendSIFTB(const char* szFile, int pos)
{
	int npoint, nLocDim, nDesDim;
	int fd = _open(szFile, _O_BINARY|_O_RDONLY,_S_IREAD);
	if (fd<0) return pos;
	///
	///
	_read(fd, &npoint, sizeof(int)); 
	_read(fd, &nLocDim, sizeof(int)); 
	
	if(npoint == SIFT_NAME && IsValidVersionName(nLocDim))
	{
		_read(fd, &npoint, sizeof(int)); 
		_read(fd, &nLocDim, sizeof(int)); 
		//assert(nLocDim == 5);
		_read(fd, &nDesDim, sizeof(int)); //assert(nDesDim == 128);
		_read(fd,(float*)_locData->data()+ pos*nLocDim, nLocDim*npoint*sizeof(float));
		_read(fd,(unsigned char*)_desData->data()+ pos*nDesDim, nDesDim*npoint*sizeof(unsigned char));
	}
	_close(fd);

	return pos + npoint;
}


int FeatureData::OpenSeekSIFT(const char *featurefile,int&npoint, int&ndim)
{
	sift_fileheader_v2 sfh={SIFT_NAME,SIFT_VERSION_4,0,0,0};

	int fd = _open(featurefile, _O_BINARY|_O_RDONLY);
	if (fd<0) return 0;
	///
	_read(fd, &sfh, sizeof(sfh));
	if(	sfh.szFeature != SIFT_NAME || 	!IsValidVersionName(sfh.szVersion)||
		sfh.npoint <=0 || 		sfh.nLocDim<=0 || 		sfh.nDesDim !=128)
	{
		// incorrect version
		_close(fd);
		return 0;
	}else
	{
		_lseek(fd, sfh.nLocDim*sfh.npoint*sizeof(float), SEEK_CUR);
		npoint = sfh.npoint;
		ndim = sfh.nDesDim;
		return fd;
	}
}

void FeatureData::SaveLocationFile(const char* szFeatureFile)
{
	int nf = _locData->npoint();
	if(nf ==0) return;
//	struct _stat buf;
//	if(_stat(szFeatureFile, &buf)!=-1) return; //already saved
	vector<float > loc(nf*2);
	float * p = &loc[0];
	int fid = _open(szFeatureFile, _O_CREAT|_O_BINARY|_O_WRONLY|_O_TRUNC,_S_IREAD | _S_IWRITE);
	if(fid ==-1) return;

	for(int i = 0; i < nf ; i++)
	{
		*p++ =(float) _locData->getpt(i)[0];
		*p++ =(float) _locData->getpt(i)[1];
	}

	_write(fid, &loc[0], loc.size()*sizeof(float));
	_close(fid);
}	

void FeatureData::SaveDescriptorFile(const char* szFeatureFile)
{
	int fid = _open(szFeatureFile, _O_CREAT|_O_BINARY|_O_WRONLY|_O_TRUNC,_S_IREAD | _S_IWRITE);

	int nf = _desData->npoint();
	DTYPE * dp = _desData->data();
	_write(fid, dp, nf*128*sizeof(unsigned char));
	_close(fid);
}

void FeatureData::ConvertA2B(const char* szFile)
{

	//LET'S AUTOMATICALLY GENERATE A BINARY VRSION

	//make sure it is the same format of sift

	double normal = 0;
	DTYPE*  d = _desData->data();

	for(int i = 0; i < 128; i++) normal += d[i] * d[i];
	normal = sqrt(normal);

	if ( normal < 400)
	{
		//__asm int 03h;
		for(int i = 0; i < _desData->npoint(); i++)
		{
			d = _desData->getpt(i);
			normal = 0;
			for(int j = 0; j < 128; j ++)
			{
				normal += d[j]*d[j];
			}

			normal = 512.0/sqrt(normal);
			for(int k = 0; k < 128; k++)
			{
				d[k] = (DTYPE) floor (normal * d[k] +0.5);
			}

		}

		for(int j = 0; j < _locData->npoint(); j++)
		{
			LTYPE* l= _locData->getpt(j);
			LTYPE temp = l[0];
			l[0] = l[1];
			l[1] = temp;
		}
	}

	int len = strlen(szFile);
	if(len>10 && strcmp(szFile + len -10, ".sift.sift")==0)
	{
		char szNewFile[260];
		strcpy(szNewFile, szFile);
		szNewFile[len-5] = 0;
		saveSIFTB2(szNewFile);
		remove(szFile);
	}else if(len >5 && strcmp(szFile + len - 5, ".sift") ==0)
	{
		saveSIFTB2(szFile);
	}

}

int FeatureData::ValidateIndex(int index[], int n)
{
	int num = getFeatureNum();
	for (int i = 0 ; i < n ; i ++)
	{
		if( index[i]>= num || index[i] < 0)
		{

			return 0;
		}
	}
	return 1;
}

void FeatureData::SortSIFT()
{
	int i, j, nf = getFeatureNum();
	if(nf ==0 || _locData == NULL ||  _desData == NULL) return;
	LTYPE * loc = _locData->data();
	DTYPE * des = _desData->data();
	vector<int> orderv(nf);
	vector<LTYPE> sizes(nf);
	int* order = &orderv[0];
	LTYPE* size = &sizes[0];


	//bubble sort 
	for( i = 0; i < nf; i++) order[i] = nf - i - 1;
	for( i = 0; i < nf; i++) size[i] = loc[5 * (nf - i -1) + 3];
	for( i =0; i < nf; i ++)
	{
		int swaped = 0;
		for( j = nf -1 ; j > i; j--)
		{
			if(size[j] > size[j-1])
			{
				//size
				LTYPE dtemp = size[j];
				size[j] = size[j-1];
				size[j-1] = dtemp;

				//order
				int itemp = order[j];
				order[j] = order[j-1];
				order[j-1] = itemp;
				swaped = 1;
			}
		}
		if(!swaped) break;
	}
	_locData->reorder(order);
	_desData->reorder(order);
	//printf("\r\n");
}

void FeatureData::ShrinkLocationData(int ndim, int npoint)
{
	if(_locData) _locData->shrink(ndim, 
		npoint < 0? _locData->npoint() : min(npoint, _locData->npoint()));
}

MatchFile.cpp

////////////////////////////////////////////////////////////////////////////
//	File:		MatchFile.cpp
//	Author:		Changchang Wu ([email protected])
//	Description : 
//
//  Copyright (c) 2011  Changchang Wu ([email protected])
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation; either
//  Version 3 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
////////////////////////////////////////////////////////////////////////////////

#include "stdio.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <algorithm>
#include <iomanip>
#include <io.h>
#include <assert.h>
using namespace std;
#include "MatchFile.h"


//////////////////////////////////////
int MatchFile::multi_thread_mode  = 0;
int MatchFile::file_title_mode = 0;
int MatchFile::num_match_verification = 1;
int	MatchFile::delay_header_update = 0;
int	MatchFile::record_reservation = 20;

//function for printing out messages.
int (*MatchFile::matchfile_printf)(const char* format,... ) = ::printf;
#define printf matchfile_printf

#ifdef _WIN64
#define _lseek _lseeki64
#endif


#ifdef WIN32
#define PATH_SLASH '\\'
#define PATH_SLASH_X '/'
#define PATH_PARENT "..\\"
#else
#define PATH_SLASH '/'
#define PATH_SLASH_X '\\'
#define PATH_PARENT "../"
#endif

void MatchFile::SetPrintFunction(int (*printf_func)(const char* format,... ))
{
	matchfile_printf = printf_func;
}

MatchFile::MatchFile()
{
	_fid = 0;
	_header.definition_size = 0;
	_header.file_count = 0;
	_header.feature_count = 0;
	_recordloc_unchanged = 0;
	_header_changed = 0;
	_opened_for_write = 0;
	_mutex = NULL;
	_matchfile_mode= 0;
	_title = _filepath; 
}

MatchFile::~MatchFile()
{
	CloseMatchFile();
}


MatchFile::MatchFile(const char* image_path, int mode)
{
	_fid = 0;
	_mutex = NULL;
	_header.definition_size = 0;
	_header.file_count = 0;
	_header.feature_count = 0;
	_recordloc_unchanged = 0;
	_header_changed = 0;
	OpenMatchFile(image_path, 0, mode);
}

int MatchFile::IsMatchFileOfImage(const char* fullpath, const char* title)
{
		if(file_title_mode && title) return strcmp(_title, title) == 0;
		else return strcmp(_filepath, fullpath) == 0; 
}

void MatchFile::GetMatchFilePath(char* match_path)
{
	strcpy(match_path, _filepath);


    if(_matchfile_mode == 0) strcat(match_path, ".mat");
    else if(_matchfile_mode == 1)strcat(match_path, ".gmat");
    else strcat(match_path, ".xmat");

	//////////////////////
	_title = strrchr(_filepath, PATH_SLASH);
	if(_title == NULL) _title = _filepath;
	else _title++; 
}

void MatchFile::GetMatchFolderPath(char* match_path)
{
	strcpy(match_path, _filepath);
	char* p = strrchr(match_path, PATH_SLASH);	p[1] = 0;
}

int  MatchFile::MakeWritable()
{
	char match_path[MAX_PATH];
	//already opened for write
	if(_fid <=0) return 0;
	if(_opened_for_write) return 1;
	//////////////////////////////

	GetMatchFilePath(match_path);

	_close(_fid);
	_fid = _open(match_path, _O_BINARY|_O_CREAT|_O_RDWR, _S_IWRITE|_S_IREAD);
	if(_fid > 0)
	{
		_opened_for_write = 1;
		return 1;
	}else
	{
		_opened_for_write = 0;
		return 0;
	}
}

void MatchFile::VerifyFeatureCount(int feature_count)
{
	if(_fid <= 0 ) return ;

	if(_header.feature_count <= 0)
	{
		//update the feature count
		if(feature_count > 0)
		{
			_header.feature_count = feature_count;
			if(MakeWritable())
			{
				_lseek(_fid, 0, SEEK_SET);
				_write(_fid, &_header, sizeof(_header));
				//printf("Update feature count [%d]!\r\n", feature_count);
			}
		}
	}else if(feature_count > 0 && _header.feature_count != feature_count)
	{
		//destroy all match record.	
		DeleteMatchFile();
		printf("Delete match record: feature changed!\r\n");
	}
}

void MatchFile::DeleteMatchRecord(const char* pattern)
{
    if(_fid <= 0) return;
    int changed = 0;
    for(int i = 0; i < _match_records.size(); ++i)
    {
        if(strstr(_match_records[i]->file_name, pattern))
        {            
			int NM;	
			RecordLoc * loc = _match_records[i];
			_lseek(_fid, loc->read_loc, SEEK_SET);
			_read(_fid, &NM, sizeof(int));

			////////////////////////////////
			if(NM == 0) continue;
            MakeWritable();
		    _lseek(_fid, loc->read_loc, SEEK_SET);
            NM = 0;	    _write(_fid, &NM, sizeof(int));
            changed = 1;
        }
    }
}


void MatchFile::DeleteMatchFile()
{
	char match_path[MAX_PATH];
	GetMatchFilePath(match_path);
	CloseMatchFile();
	remove(match_path);
}

int  MatchFile::OpenMatchFile(const char* imagepath, int write, int mode)
{
	char match_path[MAX_PATH];

	CloseMatchFile();

	//
	_matchfile_mode = mode;

	///////////////
	strcpy(_filepath, imagepath);


    GetMatchFilePath(match_path);

	if(!write)
		_fid = _open(match_path, _O_BINARY|_O_RDONLY);
	else 
		_fid = _open(match_path, _O_BINARY|_O_CREAT|_O_RDWR, _S_IWRITE|_S_IREAD);

	if(_fid > 0) 
	{
		//read file _header
		int readsz = _read(_fid, (char*) (&_header), sizeof(_header));
		_opened_for_write = write; 

		if( sizeof(_header) == readsz && _header.definition_size >0 && 
			_header.definition_buf >= _header.definition_size && 
			_header.version == MATCH_FILE_VERSION_3)
		{
			assert(_header.file_count>=0);
			_record_definition.resize(_header.definition_buf, 0);
			_read(_fid, (char*) &_record_definition[0], _header.definition_size);
			GetRecordList();
			_header_changed = 0;
			_recordloc_unchanged = _header.definition_size;
		}else if (readsz > 0)
		{
			printf("Unsupported MatchFile [%s]\r\n", _filepath );
			ResetMatchFile();
			if(write)UpdateHeaderAndRecordLoc();
		}
		return 1;
	} else 
	{
		_filepath[0] = 0;
		return 0;
	}
}

void MatchFile::GetRecordList()
{
	char * p = &_record_definition[0];
	_match_records.resize(_header.file_count);
	for(int i = 0; i < _match_records.size(); ++i)
	{
        RecordLoc* rp = (RecordLoc*) p;
		_match_records[i] = rp;
       
        if(rp->read_loc <= 0 || rp->block_size == 0 || 
            rp->extra_size > MAX_PATH ||
            (rp->fcount > 1000000 || rp->fcount < 0))
        {
            _match_records.resize(i);
            _header.file_count = i;
            _header.definition_size = (p - &_record_definition[0]);
            break;
        }else
        {
		    p += sizeof(RecordLoc) + _match_records[i]->extra_size;
			//convert file name for different operation system
			for(char* c = rp->file_name; *c; ++c) {if (*c == PATH_SLASH_X) *c = PATH_SLASH; }
        }
	}
}

void MatchFile::GetMatchedImageList(vector<string>& paths)
{
	char match_path[MAX_PATH];
	GetMatchFolderPath(match_path);
	string folder = match_path;
	paths.resize(0);

	for(int i = 0; i < _match_records.size(); ++i)
	{
		paths.push_back(folder + _match_records[i]->file_name);
	}
}

void MatchFile::SaveSubsetMatch(vector<string>& paths, vector<int>&fc)
{
    MatchFile sub;
    sub.OpenMatchFile(_filepath, 1, 2);
    sub.ResetMatchFile();
    ////
    int NM; 
    Points<int> matches;
    TwoViewGeometry tvg;
    Points<int> inliers;

    /////////////////////////////
    for(int i = 0; i < paths.size(); ++i)
    {

        if(GetPMatch(paths[i].c_str(), fc[i], NM, matches))
        {  
            sub.WritePMatch(paths[i].c_str(), fc[i], NM, matches, 0);
            if(GetIMatch(paths[i].c_str(), fc[i], tvg, inliers))
            {
                sub.WriteIMatch(paths[i].c_str(), 0, NM, tvg, inliers);
            }
        }
    }
}

int MatchFile::HaveMatchRecord(const char* absolute_path)
{
	char relative_path[MAX_PATH];
	GetRelativePath(absolute_path, relative_path);
	return GetImageIndex(relative_path) >= 0;
}

int  MatchFile::GetImageIndex(const char* relative_path)
{
	if(file_title_mode)
	{
		const char * ps = strrchr(relative_path, PATH_SLASH);
		ps = (ps == NULL? relative_path : ps + 1);

		for(int i = 0; i < _match_records.size(); i++)
		{
			RecordLoc* loc = _match_records[i];
			const char * p = strrchr(loc->file_name, PATH_SLASH);
			p = (p == NULL ) ?  loc->file_name : p + 1;
			if(strcmp(p, ps) == 0) return i;
		}
	}else
	{
		for(int i = 0; i < _match_records.size(); i++)
		{
			if(strcmp(_match_records[i]->file_name, relative_path) == 0) return i;
		}
	}
	return -1;
}


void MatchFile::GetRelativePath(const char* path1, const char* path2, char* relative_path)
{

	int i = 0;
	while(path2[i] == path1[i] && path2[i] && path1[i]) i++;
	while(i > 0 && path1[i] != PATH_SLASH) i--;
	if( i == 0)
	{
		strcpy(relative_path, path2);
	}else
	{
		relative_path[0] = 0;
		const char* p = path1 + i + 1;
		char * rp = relative_path;
		int rc1 = 0, rc2 = 0;
		while(*p)
		{
			if(p[0] ==  PATH_SLASH && p[1] != PATH_SLASH) 
			{
				strcpy(rp, PATH_PARENT);
				rp += 3;
				rc1 ++;
			}
			p++;
		}
		p = path2 + i + 1;
		while(*p)
		{
			if(p[0] == PATH_SLASH && p[1] != PATH_SLASH) rc2 ++;
			p++;
		}
		if(rc1 <=1 || rc2 <=1) strcpy(rp, path2 + i + 1); 
		else strcpy(relative_path, path2);
	}
}


inline void MatchFile::GetRelativePath(const char* image_match, char* relative_path)
{
    if(file_title_mode)
    {
        const char* pslash = strrchr(image_match, PATH_SLASH);
        if(pslash) strcpy(relative_path, pslash + 1);
        else       strcpy(relative_path, image_match); 
    }else
    {
	    GetRelativePath(_filepath, image_match, relative_path);
    }
}

void MatchFile::MoveRecordToEnd(int i)
{
	if(i >= _header.file_count - 1 || i < 0 || _header.file_count < 2) return;
	char* p0 = (char*) _match_records[0];
	char* p1 = (char*) _match_records[i];
	char* p2 = (char*) _match_records[i + 1];
	size_t loc1 = p1 - p0;
	size_t loc2 = p2 - p0;
	int len = loc2 - loc1;
	vector<char> temp;
	temp.insert(temp.begin(), p1, p2);
	_record_definition.erase(_record_definition.begin() + loc1, _record_definition.begin() + loc2);
	//_record_definition.insert(_record_definition.end(), temp.begin(), temp.begin() + len);
    _record_definition.insert(_record_definition.begin() + _header.definition_size - len, temp.begin(), temp.begin() + len);
	_recordloc_unchanged = min(_recordloc_unchanged, loc1);
	GetRecordList();

	if(i == 0)
	{
		_header.definition_buf += len;
		_header_changed = 1;
	}else
	{
		_match_records[i -1]->trash_size += len;
	}
	//
	
	_match_records[_header.file_count -1]->read_loc = 
		_match_records[_header.file_count - 2]->read_loc + _match_records[_header.file_count - 2]->block_size;

	printf("MoveRecordToEnd [%s]\r\n", _filepath );
}

int  MatchFile::AddImageMatch(const char* relative_path)
{
	//see if the name buffer has enough space..
	int slen = (strlen(relative_path) / 4  + 1) * 4; 
	int elen = slen - 4;
	int rlen = elen + sizeof(RecordLoc);

	//////////////////
	_header_changed = 1;
	//////////////
	if(_header.file_count == 0)
	{
		_header.version = MATCH_FILE_LATEST_VERSION;
		_header.file_count = 1;
		_header.definition_buf = max(20, record_reservation) * (MAX_PATH + sizeof(RecordLoc));
		_record_definition.resize(_header.definition_buf, 0);	
		_header.definition_size = rlen;
		RecordLoc* loc = (RecordLoc*) (&_record_definition[0]);
		_match_records.resize(1);
		_match_records[0] = loc;
		strcpy(loc->file_name, relative_path);
		loc->extra_size = elen;
		loc->trash_size = 0;
		loc->block_size = 0;
		loc->read_loc = sizeof(FileHeader) + _header.definition_buf;
		// should write the _header now?
		return 0;
	}
	else if(_header.definition_size + rlen < _header.definition_buf)
	{
		RecordLoc* rec = (RecordLoc*) (&_record_definition[_header.definition_size]);
		rec->block_size = 0;
		rec->extra_size = elen;
		rec->read_loc = _match_records.back()->read_loc + _match_records.back()->block_size;
		strcpy(rec->file_name, relative_path);
		_match_records.push_back(rec);
		_header.definition_size += rlen ;
		_header.file_count++;
		return _header.file_count -1;
	}else 
	{
		//size_t szr = max(((int) (_match_records.size() + 1)), record_reservation) * (MAX_PATH + sizeof(RecordLoc));
		int extra_needed = rlen + _header.definition_buf;
		int match_move_needed = 0;
		int extra_space = 0;

		// move the match data
		while(extra_space < extra_needed)
		{
			RecordLoc* loc = _match_records[match_move_needed];
			extra_space+= (loc->block_size + loc->trash_size);
			match_move_needed++;
		}
		assert(match_move_needed > 0);

		//read match data that needs to move
		vector<char> read_buffer(extra_space);
		char* pbuf = &read_buffer[0];
		_lseek(_fid, _match_records[0]->read_loc, SEEK_SET);
		_read(_fid, &read_buffer[0], extra_space);

		//write match data to the end of file
		int match_write_location = _match_records.back()->read_loc + _match_records.back()->block_size;
		_lseek(_fid, match_write_location, SEEK_SET);
		for(int i = 0; i < match_move_needed; i++)
		{
			RecordLoc* loc = _match_records[i];
			_write(_fid, pbuf, loc->block_size);
			pbuf += (loc->block_size + loc->trash_size);
			loc->read_loc = match_write_location;
			match_write_location += loc->block_size;
			loc->trash_size = 0;
		}

		//organize file names
		int definition_move = ((char*)_match_records[match_move_needed]) - &_record_definition[0];
		if(match_move_needed < _header.file_count)
		{
			//reorganize strings..move several string to the end
			vector<char> temp = _record_definition;
			std::copy(temp.begin() + definition_move, temp.begin() + _header.definition_size, _record_definition.begin() );
			std::copy(temp.begin(), temp.begin() + definition_move, _record_definition.begin() + _header.definition_size - definition_move);
		}
		_header.definition_buf = _header.definition_buf * 2 + rlen;
		_record_definition.resize(_header.definition_buf, 0);
		GetRecordList();

		RecordLoc* rec = (RecordLoc*) (&_record_definition[_header.definition_size]);
		rec->read_loc = match_write_location;
		rec->trash_size = 0;
		rec->block_size = 0;
		rec->extra_size = elen;
		_match_records.push_back(rec);
		strcpy(rec->file_name, relative_path);


		//write all previous data to file
		_lseek(_fid, sizeof(_header), SEEK_SET);
		_write(_fid, &_record_definition[0], _header.definition_size);

		////
		_header.definition_size += rlen;
		_header.file_count++;
		_recordloc_unchanged = 0;
		return _header.file_count -1; 
	}
}

void MatchFile::ResetMatchFile()
{
	_header.file_count = 0;
	_header.definition_size = 0;
	_header.definition_buf = 0;
	_header.version = MATCH_FILE_LATEST_VERSION;
	_match_records.resize(0);
	_record_definition.resize(0);
	_recordloc_unchanged = 0;
	_header_changed = 1;
}

void MatchFile::CloseMatchFile()
{
	if(_fid > 0) 
	{
		if(_opened_for_write && delay_header_update)	UpdateHeaderAndRecordLoc();
		ResetMatchFile();
		_close(_fid);
		_fid = 0;
		_opened_for_write = 0; 
		_matchfile_mode = 0;

	}
}

void MatchFile::WriteFMatch(const char* image1, const char* image2,
							int NF, int* index1, int* index2, float F[3][3])
{
	if(index1 == NULL || index2 == NULL) return;
	int* indices [2] = {index1, index2};
	Points<int> inliers(indices, NF, 2);
	TwoViewGeometry tvg(NF, F);
	WriteIMatch(image1, image2, 0, tvg, inliers);

}


void MatchFile::WriteIMatch(MatchFile* mat, const char* image1, const char* image2, 
							int NM, TwoViewGeometry& tvg, Points<int>&inliers)
{

	if(mat == NULL || ! mat->IsValid())
	{
		WriteIMatch(image1, image2, NM, tvg, inliers);
	}else 	if(_stricmp(mat->_filepath, image1) ==0)
	{
		if(mat->MakeWritable())
		{
			mat->WriteIMatch(image2, 0, NM, tvg, inliers);
		}
		MatchFile file2;
		if(file2.OpenMatchFile(image2, 1))
		{
			file2.WriteIMatch(image1, 1, NM, tvg, inliers);
		}
	}else if(_stricmp(mat->_filepath, image2) == 0)
	{
		if(mat->MakeWritable())
		{
			mat->WriteIMatch(image1, 1, NM, tvg, inliers);

		}
		
		MatchFile file1;
		if(file1.OpenMatchFile(image1, 1))
		{
			file1.WriteIMatch(image2, 0, NM, tvg, inliers);
		}
	}

}

void MatchFile::WriteIMatch(const char* image1, const char* image2, int NM, TwoViewGeometry& tvg, Points<int>&inliers)
{

	MatchFile file1, file2;
	if(file1.OpenMatchFile(image1, 1))
	{
		file1.WriteIMatch(image2, 0, NM, tvg, inliers);
		file1.CloseMatchFile();
	}

	if(file2.OpenMatchFile(image2, 1))
	{
		file2.WriteIMatch(image1, 1, NM, tvg, inliers);
		file2.CloseMatchFile();
	}
}

void MatchFile::WriteIMatch(const char* image_match, int reverse, int NM,
							TwoViewGeometry& tvg, Points<int>&inliers)
{
	int index, fnm, szmin;
	char relative_path[MAX_PATH];
	if(image_match == NULL || image_match[0] == 0) return;
	GetRelativePath(image_match, relative_path);
	index = GetImageIndex(relative_path);
	if(index < 0) return;

	RecordLoc* loc = _match_records[index];
	MatchRecordV3 rec;

	assert(loc->read_loc > 0);
	
	//read in the number of 
	if(num_match_verification || NM == 0)
	{
		_lseek(_fid, loc->read_loc, SEEK_SET);
		_read(_fid, &fnm, sizeof(int));
		NM = fnm;
	}else
	{
		_lseek(_fid, loc->read_loc + sizeof(int), SEEK_SET);
	}

	assert(tvg.NF<=0 || tvg.NE==0 || tvg.NF == tvg.NE);

	szmin = (1 + (NM + tvg.NF) * 2 )* sizeof(int) + sizeof(rec);

	if(szmin > loc->block_size) //this is unlikey to happen, right?
	{
		//not enough size.
		size_t offset = ((char*)loc) - ((char*)_match_records[0]);
		_recordloc_unchanged = min (_recordloc_unchanged,  offset);
		if(loc->block_size ==0 || index == _header.file_count - 1)
		{
			int bs = sizeof(MatchRecordV3) +  max(NM + tvg.NF, 8) * sizeof(int) * 4;
			//last one in the file
			loc->block_size = bs;
		}else	if(szmin > loc->block_size + loc->trash_size)
		{
			// not enough space?
			MoveRecordToEnd(index);
			index = _header.file_count -1;
			loc = _match_records[index];
			loc->block_size = sizeof(MatchRecordV3) +  max(NM + tvg.NF, 8) * sizeof(int) * 4;
		}else
		{
			loc->block_size += loc->trash_size;
			loc->trash_size = 0;
		}

		if(!delay_header_update) 
		{
			printf("Reallocate space fo record %d\r\n", index);
			UpdateHeaderAndRecordLoc();
			_lseek(_fid, loc->read_loc + sizeof(int), SEEK_SET);
		}
	}

	//
	//Write inlier pairs
	if(reverse == 0)
	{
		rec.tvg.SetGeometry(tvg);
		//write inlier match record
		_write(_fid, &rec, sizeof(rec));
		_lseek(_fid, NM * sizeof(int) * 2, SEEK_CUR);
		if(tvg.NF >0)
		{
			_write(_fid, inliers[0], sizeof(int) * tvg.NF);
			_write(_fid, inliers[1], sizeof(int) * tvg.NF);
		}

	}else
	{
		rec.tvg.SetGeometryR(tvg);;
		//write inlier match record
		_write(_fid, &rec, sizeof(rec));

		_lseek(_fid, NM * sizeof(int) * 2, SEEK_CUR);
		if(tvg.NF > 0)
		{
			_write(_fid, inliers[1], sizeof(int) * tvg.NF);
			_write(_fid, inliers[0], sizeof(int) * tvg.NF);
		}
	}
}


void MatchFile::WritePMatch(const char* image1, const char* image2, 
							int fc1, int fc2, int NM, Points<int>& matches)
{
	MatchFile file1, file2;
	if(file1.OpenMatchFile(image1, 1))
	{
		file1.WritePMatch(image2, fc2, NM, matches, 0);
		file1.CloseMatchFile();
	}

	if(file2.OpenMatchFile(image2, 1))
	{
		file2.WritePMatch(image1, fc1, NM, matches, 1);
		file2.CloseMatchFile();
	}
}

void MatchFile::WritePMatch(const char* image_match, int FC, int NM, Points<int>&matches, int reverse)
{
	int index;
	char relative_path[MAX_PATH];
	if(image_match == NULL || image_match[0] == 0) return;
	GetRelativePath(image_match, relative_path);
	index = GetImageIndex(relative_path);
	if(index < 0) index = AddImageMatch(relative_path);
	RecordLoc* loc = _match_records[index];
	loc->fcount = FC;
	assert(loc->read_loc > 0);
	size_t offset = ((char*)loc) - ((char*)_match_records[0]);
	_recordloc_unchanged = min (_recordloc_unchanged, offset); 
	if(loc->block_size ==0 || index == _header.file_count - 1)
	{
		int bs = sizeof(MatchRecordV3) +  max(NM, 8) * sizeof(int) * 6;
		//last one in the file
		loc->block_size = bs;

	}else
	{
		int bsmin = sizeof(MatchRecordV3) + max(NM, 0) * sizeof(int) * 4;
		if(bsmin > loc->block_size)
		{
			if(bsmin > loc->block_size + loc->trash_size)
			{
				// not enough space?
				MoveRecordToEnd(index);
				index = _header.file_count -1;
				loc = _match_records[index];
				loc->block_size = sizeof(MatchRecordV3) + max(NM, 8) * sizeof(int) * 6;
			}else
			{
				loc->block_size += loc->trash_size;
				loc->trash_size = 0;
			}
		}
	}

	//update file _header and locs
	if(!delay_header_update)
	{
		UpdateHeaderAndRecordLoc();
	}

	MatchRecordV3 rec;

	//write pmatch
	_lseek(_fid, loc->read_loc, SEEK_SET);
	//write match record
	_write(_fid, &NM, sizeof(int));
	_write(_fid, &rec, sizeof(rec));

	//write matched pairs
	if(NM <=0) return;
	if(reverse == 0)
	{
		_write(_fid, matches[0], sizeof(int) * NM);
		_write(_fid, matches[1], sizeof(int) * NM);
	}else
	{
		_write(_fid, matches[1], sizeof(int) * NM);
		_write(_fid, matches[0], sizeof(int) * NM);
	}
}

void MatchFile::UpdateHeaderAndRecordLoc()
{
	//the file _header
	if(_header_changed)
	{
		_lseek(_fid, 0, SEEK_SET);
		//VERIFY(_header.version == MATCH_FILE_LATEST_VERSION);
		_write(_fid, &_header, sizeof(_header));
		_header_changed = 0;
	}

	if(_header.definition_size > _recordloc_unchanged)
	{
		//recordloc
		_lseek(_fid, sizeof(_header) + _recordloc_unchanged, SEEK_SET);
		_write(_fid, &_record_definition[_recordloc_unchanged], _header.definition_size - _recordloc_unchanged);
		_recordloc_unchanged = _header.definition_size;
	}
}


///////////////////////
int MatchFile::GetPMatch(const char* image_path, int FC, int& NM, Points<int>& matches)
{
	int index;
	char relative_path[MAX_PATH];
	GetRelativePath(image_path, relative_path);
	index = GetImageIndex(relative_path);
	if(index < 0)
	{
		NM = 0;
		matches.resize(0, 0);
		return 0;
	}else
	{
		RecordLoc * loc = _match_records[index];

		if(loc->fcount == FC)
		{
			_lseek(_fid, loc->read_loc, SEEK_SET);
			_read(_fid, &NM, sizeof(int));
			_lseek(_fid, sizeof(MatchRecordV3), SEEK_CUR);

			if(NM >0 && NM <= FC)
			{
				matches.resize(NM, 2);
				_read(_fid, matches[0], 2 * NM * sizeof(int));
			}else
			{
				matches.resize(0, 0);
                NM = 0;
			}
			return NM;
		} else 
		{
			NM = 0;
			matches.resize(0, 0);
			return 0;
		}
	}

}

int MatchFile::GetPMatchR(const char* image_path, int FC, int& NM, Points<int>& matches)
{
	int index;
	char relative_path[MAX_PATH];
	GetRelativePath(image_path, relative_path);
	index = GetImageIndex(relative_path);
	if(index < 0)
	{
		NM = 0;
		matches.resize(0, 0);
		return 0;
	}else
	{
		RecordLoc * loc = _match_records[index];

		if(loc->fcount == FC)
		{
			_lseek(_fid, loc->read_loc, SEEK_SET);
			_read(_fid, &NM, sizeof(int));
			_lseek(_fid, sizeof(MatchRecordV3), SEEK_CUR);

			if(NM > 0 && NM <= FC)
			{
				matches.resize(NM, 2);
				_read(_fid, matches[1],  NM * sizeof(int));
				_read(_fid, matches[0],  NM * sizeof(int));
			}else
			{
				matches.resize(0, 0);
			}
			return NM;
		} else 
		{
			NM = 0;
			matches.resize(0, 0);
			return 0;
		}
	}

}

int MatchFile::	GetMatchCount(const char* image_path, int&NM, int& NF)
{
	int index;
	char relative_path[MAX_PATH];
	GetRelativePath(image_path, relative_path);
	index = GetImageIndex(relative_path);
	if(index < 0 )
	{
		NM = NF = 0;
		return 0;
	}else
	{
		int counts[3];
		RecordLoc * loc = _match_records[index];
		_lseek(_fid, loc->read_loc, SEEK_SET);
		_read(_fid, counts, sizeof(counts));
		NM = counts[0];	NF = counts[2];
		return 1;
	}

}


int MatchFile::GetIMatch(const char* image_path, int FC, TwoViewGeometry& tvg,  Points<int>&inliers)
{
	int index;
	char relative_path[MAX_PATH];
	GetRelativePath(image_path, relative_path);
	index = GetImageIndex(relative_path);
	if(index < 0 )
	{
		tvg.ResetGeometry();
		inliers.resize(0, 0);
		return 0;
	}else
	{
		RecordLoc * loc = _match_records[index];
		if(loc->fcount != FC)
		{
			tvg.ResetGeometry();
			inliers.resize(0, 0);
			printf("# features changed: [%s][%d->%d]!!!\r\n", image_path, loc->fcount, FC);
			return 0;
		}else
		{
			int NM;
			MatchRecordV3 rec;
			_lseek(_fid, loc->read_loc, SEEK_SET);
			_read(_fid, &NM, sizeof(int));
			_read(_fid, &rec, sizeof(rec));
            if(NM > loc->fcount || NM < 0)
            {
				tvg.ResetGeometry();
				inliers.resize(0, 0);
                printf("ERROR: incorrect matching count [%d, %d]\r\n", NM, loc->fcount);
                return 0;

            }else   if(NM == 0 || rec.version != MatchFile::MATCH_RECORD_V3 || rec.tvg.NF > loc->fcount)
			{
				tvg.ResetGeometry();
				inliers.resize(0, 0);
				//printf("#--BAD matching record---###\r\n");
				return 0;
			}else
			{
				//////////////////////////
				tvg.SetGeometry(rec.tvg);

				//
				if(tvg.NF > 0)
				{
					_lseek(_fid, NM * 2 * sizeof(int), SEEK_CUR);
					inliers.resize(tvg.NF, 2);
					_read(_fid, inliers[0], 2 * tvg.NF * sizeof(int));
				}else
				{
					inliers.resize(0, 0);
				}
				return NM;
			}
		}
	}

}



int MatchFile::GetIMatchR(const char* image_path, int FC, TwoViewGeometry& tvg,  Points<int>&inliers)
{
	int index;
	char relative_path[MAX_PATH];
	GetRelativePath(image_path, relative_path); 
	index = GetImageIndex(relative_path);
	if(index < 0 )
	{
		tvg.ResetGeometry();
		inliers.resize(0, 0);
		return 0;
	}else
	{
		RecordLoc * loc = _match_records[index];
		if(loc->fcount != FC)
		{
			tvg.ResetGeometry();
			inliers.resize(0, 0);
			printf("# feature changed: [%s][%d->%d]!!!\r\n", image_path, loc->fcount, FC);
			return 0;
		}else
		{
			int NM;
			MatchRecordV3 rec;
			_lseek(_fid, loc->read_loc, SEEK_SET);
			_read(_fid, &NM, sizeof(int));
			_read(_fid, &rec, sizeof(rec));
            if(NM > loc->fcount || NM < 0)
            {
				tvg.ResetGeometry();
				inliers.resize(0, 0);
                printf("ERROR: incorrect matching count [%d, %d]\r\n", NM, loc->fcount);
                return 0;

            }else if(NM == 0  || rec.version != MatchFile::MATCH_RECORD_V3 || rec.tvg.NF > loc->fcount)
			{
				tvg.ResetGeometry();
				inliers.resize(0, 0);
				//printf("#--BAD matching record---###\r\n");
				return 0;
			}else
			{
				///
				tvg.SetGeometryR(rec.tvg);
				//
				if(tvg.NF > 0)
				{
					_lseek(_fid, NM * 2 * sizeof(int), SEEK_CUR);
					inliers.resize(tvg.NF, 2);
					_read(_fid, inliers[1],  tvg.NF * sizeof(int));
					_read(_fid, inliers[0],  tvg.NF * sizeof(int));
				}else
				{
					inliers.resize(0, 0);
				}
				return NM;
			}
		}
	}
}

 

然後自己隨便加一個頭文件,嘗試讀取.mat

main.cpp

/*
error C4996: '_open': This function or variable may be unsafe. Consider using _sopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.

error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.

根據提示,use _CRT_SECURE_NO_DEPRECATE
在項目|屬性|配置屬性|C/C++|命令行|附加選項,加入{/D "_CRT_SECURE_NO_DEPRECATE"}(注:加入中括號中完整的內容)
或者在項目|屬性|配置屬性|C/C++|預處理器|預處理定義中加入 _CRT_SECURE_NO_DEPRECATE
*/
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <cmath>
using namespace std;

#include "FeaturePoints.h"
#include "MatchFile.h"

int main()
{
	//MatchFile match;
	//int flag = match.OpenMatchFile("D:\\code\\SFM\\ImageDataset_SceauxCastle-master\\images\\100_7100", 0, 0);

	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章