教你一步一步用c语言实现sift算法、下

    ok,接上文,咱们一个一个的来编写main函数中所涉及到所有函数,这也是本文的关键部分:

    五个步骤

    ok,接下来,进入重点部分,咱们依据上文介绍的sift算法的几个步骤,来一一实现这些函数。

    为了版述清晰,再贴一下,主函数,顺便再加强下对sift 算法的五个步骤的认识:

    1、 SIFT算法第一步:图像预处理

    CvMat *ScaleInitImage(CvMat * im) ; //金字塔初始化

    2、 SIFT算法第二步:建立高斯金字塔函数

    ImageOctaves* BuildGaussianOctaves(CvMat * image) ; //建立高斯金字塔

    3、 SIFT算法第三步:特征点位置检测,最后确定特征点的位置

    int DetectKeypoint(int numoctaves, ImageOctaves *GaussianPyr);

    void ComputeGrad_DirecandMag(int numoctaves, ImageOctaves *GaussianPyr);

    5、 SIFT算法第五步:抽取各个特征点处的特征描述字

    void ExtractFeatureDescriptors(int numoctaves, ImageOctaves *GaussianPyr);

    ok,接下来一一具体实现这几个函数:

    SIFT算法第一步

    SIFT算法第一步:扩大图像,预滤波剔除噪声,得到金字塔的最底层-第一阶的第一层:

    1. {
    2. double sigma,preblur_sigma;
    3. CvMat *imMat;
    4. CvMat * dst;
    5. CvMat *tempMat;
    6. //首先对图像进行平滑滤波,抑制噪声
    7. imMat = cvCreateMat(im->rows, im->cols, CV_32FC1);
    8. BlurImage(im, imMat, INITSIGMA);
    9. //针对两种情况分别进行处理:初始化放大原始图像或者在原图像基础上进行后续操作
    10. //建立金字塔的最底层
    11. if (DOUBLE_BASE_IMAGE_SIZE)
    12. {
    13. tempMat = doubleSizeImage2(imMat);//对扩大两倍的图像进行二次采样,采样率为0.5,采用线性插值
    14. #define TEMPMAT(ROW,COL) ((float *)(tempMat->data.fl + tempMat->step/sizeof(float) * (ROW)))[(COL)]
    15. dst = cvCreateMat(tempMat->rows, tempMat->cols, CV_32FC1);
    16. preblur_sigma = 1.0;//sqrt(2 - 4*INITSIGMA*INITSIGMA);
    17. BlurImage(tempMat, dst, preblur_sigma);
    18. // The initial blurring for the first image of the first octave of the pyramid.
    19. sigma = sqrt( (4*INITSIGMA*INITSIGMA) + preblur_sigma * preblur_sigma );
    20. // sigma = sqrt(SIGMA * SIGMA - INITSIGMA * INITSIGMA * 4);
    21. //printf("Init Sigma: %f/n", sigma);
    22. BlurImage(dst, tempMat, sigma); //得到金字塔的最底层-放大2倍的图像
    23. cvReleaseMat( &dst );
    24. return tempMat;
    25. }
    26. else
    27. {
    28. dst = cvCreateMat(im->rows, im->cols, CV_32FC1);
    29. //sigma = sqrt(SIGMA * SIGMA - INITSIGMA * INITSIGMA);
    30. preblur_sigma = 1.0;//sqrt(2 - 4*INITSIGMA*INITSIGMA);
    31. sigma = sqrt( (4*INITSIGMA*INITSIGMA) + preblur_sigma * preblur_sigma );
    32. //printf("Init Sigma: %f/n", sigma);
    33. BlurImage(imMat, dst, sigma); //得到金字塔的最底层:原始图像大小
    34. return dst;
    35. }
    36. }

    SIFT算法第二步

    SIFT第二步,建立Gaussian金字塔,给定金字塔第一阶第一层图像后,计算高斯金字塔其他尺度图像,
    每一阶的数目由变量SCALESPEROCTAVE决定,给定一个基本图像,计算它的高斯金字塔图像,返回外部向量是阶梯指针,内部向量是每一个阶梯内部的不同尺度图像。

    SIFT算法第三步

    SIFT算法第三步,特征点位置检测,最后确定特征点的位置检测DOG金字塔中的局部最大值,找到之后,还要经过两个检验才能确认为特征点:一是它必须有明显的差异,二是他不应该是边缘点,(也就是说,在极值点处的主曲率比应该小于某一个阈值)。

    1. //SIFT算法第三步,特征点位置检测,
    2. int DetectKeypoint(int numoctaves, ImageOctaves *GaussianPyr)
    3. {
    4. //计算用于DOG极值点检测的主曲率比的阈值
    5. double curvature_threshold;
    6. curvature_threshold= ((CURVATURE_THRESHOLD + 1)*(CURVATURE_THRESHOLD + 1))/CURVATURE_THRESHOLD;
    7. #define ImLevels(OCTAVE,LEVEL,ROW,COL) ((float *)(DOGoctaves[(OCTAVE)].Octave[(LEVEL)].Level->data.fl + DOGoctaves[(OCTAVE)].Octave[(LEVEL)].Level->step/sizeof(float) *(ROW)))[(COL)]
    8. int keypoint_count = 0;
    9. for (int i=0; i<numoctaves; i++)
    10. {
    11. for(int j=1;j<SCALESPEROCTAVE+1;j++)//取中间的scaleperoctave个层
    12. {
    13. //在图像的有效区域内寻找具有显著性特征的局部最大值
    14. //float sigma=(GaussianPyr[i].Octave)[j].levelsigma;
    15. //int dim = (int) (max(3.0f, 2.0*GAUSSKERN *sigma + 1.0f)*0.5);
    16. int dim = (int)(0.5*((GaussianPyr[i].Octave)[j].levelsigmalength)+0.5);
    17. for (int m=dim;m<((DOGoctaves[i].row)-dim);m++)
    18. for(int n=dim;n<((DOGoctaves[i].col)-dim);n++)
    19. {
    20. if ( fabs(ImLevels(i,j,m,n))>= CONTRAST_THRESHOLD )
    21. {
    22. if ( ImLevels(i,j,m,n)!=0.0 ) //1、首先是非零
    23. {
    24. float inf_val=ImLevels(i,j,m,n);
    25. if(( (inf_val <= ImLevels(i,j-1,m-1,n-1))&&
    26. (inf_val <= ImLevels(i,j-1,m ,n-1))&&
    27. (inf_val <= ImLevels(i,j-1,m+1,n-1))&&
    28. (inf_val <= ImLevels(i,j-1,m-1,n ))&&
    29. (inf_val <= ImLevels(i,j-1,m ,n ))&&
    30. (inf_val <= ImLevels(i,j-1,m+1,n ))&&
    31. (inf_val <= ImLevels(i,j-1,m-1,n+1))&&
    32. (inf_val <= ImLevels(i,j-1,m ,n+1))&&
    33. (inf_val <= ImLevels(i,j-1,m+1,n+1))&& //底层的小尺度9
    34. (inf_val <= ImLevels(i,j,m-1,n-1))&&
    35. (inf_val <= ImLevels(i,j,m ,n-1))&&
    36. (inf_val <= ImLevels(i,j,m+1,n-1))&&
    37. (inf_val <= ImLevels(i,j,m-1,n ))&&
    38. (inf_val <= ImLevels(i,j,m+1,n ))&&
    39. (inf_val <= ImLevels(i,j,m-1,n+1))&&
    40. (inf_val <= ImLevels(i,j,m ,n+1))&&
    41. (inf_val <= ImLevels(i,j,m+1,n+1))&& //当前层8
    42. (inf_val <= ImLevels(i,j+1,m-1,n-1))&&
    43. (inf_val <= ImLevels(i,j+1,m ,n-1))&&
    44. (inf_val <= ImLevels(i,j+1,m+1,n-1))&&
    45. (inf_val <= ImLevels(i,j+1,m-1,n ))&&
    46. (inf_val <= ImLevels(i,j+1,m ,n ))&&
    47. (inf_val <= ImLevels(i,j+1,m+1,n ))&&
    48. (inf_val <= ImLevels(i,j+1,m-1,n+1))&&
    49. (inf_val <= ImLevels(i,j+1,m ,n+1))&&
    50. (inf_val <= ImLevels(i,j+1,m+1,n+1)) //下一层大尺度9
    51. ) ||
    52. ( (inf_val >= ImLevels(i,j-1,m-1,n-1))&&
    53. (inf_val >= ImLevels(i,j-1,m ,n-1))&&
    54. (inf_val >= ImLevels(i,j-1,m+1,n-1))&&
    55. (inf_val >= ImLevels(i,j-1,m-1,n ))&&
    56. (inf_val >= ImLevels(i,j-1,m ,n ))&&
    57. (inf_val >= ImLevels(i,j-1,m+1,n ))&&
    58. (inf_val >= ImLevels(i,j-1,m-1,n+1))&&
    59. (inf_val >= ImLevels(i,j-1,m ,n+1))&&
    60. (inf_val >= ImLevels(i,j-1,m+1,n+1))&&
    61. (inf_val >= ImLevels(i,j,m-1,n-1))&&
    62. (inf_val >= ImLevels(i,j,m ,n-1))&&
    63. (inf_val >= ImLevels(i,j,m+1,n-1))&&
    64. (inf_val >= ImLevels(i,j,m-1,n ))&&
    65. (inf_val >= ImLevels(i,j,m+1,n ))&&
    66. (inf_val >= ImLevels(i,j,m-1,n+1))&&
    67. (inf_val >= ImLevels(i,j,m ,n+1))&&
    68. (inf_val >= ImLevels(i,j,m+1,n+1))&&
    69. (inf_val >= ImLevels(i,j+1,m-1,n-1))&&
    70. (inf_val >= ImLevels(i,j+1,m ,n-1))&&
    71. (inf_val >= ImLevels(i,j+1,m+1,n-1))&&
    72. (inf_val >= ImLevels(i,j+1,m-1,n ))&&
    73. (inf_val >= ImLevels(i,j+1,m ,n ))&&
    74. (inf_val >= ImLevels(i,j+1,m+1,n ))&&
    75. (inf_val >= ImLevels(i,j+1,m-1,n+1))&&
    76. (inf_val >= ImLevels(i,j+1,m ,n+1))&&
    77. (inf_val >= ImLevels(i,j+1,m+1,n+1))
    78. ) ) //2、满足26个中极值点
    79. {
    80. //此处可存储
    81. //然后必须具有明显的显著性,即必须大于CONTRAST_THRESHOLD=0.02
    82. if ( fabs(ImLevels(i,j,m,n))>= CONTRAST_THRESHOLD )
    83. {
    84. //最后显著处的特征点必须具有足够的曲率比,CURVATURE_THRESHOLD=10.0,首先计算Hessian矩阵
    85. // Compute the entries of the Hessian matrix at the extrema location.
    86. /*
    87. 1 0 -1
    88. 0 0 0
    89. -1 0 1 *0.25
    90. */
    91. // Compute the trace and the determinant of the Hessian.
    92. //Det_H = Dxx*Dyy - Dxy^2;
    93. float Dxx,Dyy,Dxy,Tr_H,Det_H,curvature_ratio;
    94. Dxx = ImLevels(i,j,m,n-1) + ImLevels(i,j,m,n+1)-2.0*ImLevels(i,j,m,n);
    95. Dyy = ImLevels(i,j,m-1,n) + ImLevels(i,j,m+1,n)-2.0*ImLevels(i,j,m,n);
    96. Tr_H = Dxx + Dyy;
    97. Det_H = Dxx*Dyy - Dxy*Dxy;
    98. // Compute the ratio of the principal curvatures.
    99. curvature_ratio = (1.0*Tr_H*Tr_H)/Det_H;
    100. if ( (Det_H>=0.0) && (curvature_ratio <= curvature_threshold) ) //最后得到最具有显著性特征的特征点
    101. {
    102. //将其存储起来,以计算后面的特征描述字
    103. keypoint_count++;
    104. Keypoint k;
    105. /* Allocate memory for the keypoint. */
    106. k = (Keypoint) malloc(sizeof(struct KeypointSt));
    107. k->next = keypoints;
    108. keypoints = k;
    109. k->row = m*(GaussianPyr[i].subsample);
    110. k->col =n*(GaussianPyr[i].subsample);
    111. k->sy = m; //行
    112. k->sx = n; //列
    113. k->octave=i;
    114. k->level=j;
    115. k->scale = (GaussianPyr[i].Octave)[j].absolute_sigma;
    116. }//if >curvature_thresh
    117. }//if >contrast
    118. }//if inf value
    119. }//if non zero
    120. }//if >contrast
    121. } //for concrete image level col
    122. }//for levels
    123. }//for octaves
    124. return keypoint_count;
    125. }
    126. //在图像中,显示SIFT特征点的位置
    127. void DisplayKeypointLocation(IplImage* image, ImageOctaves *GaussianPyr)
    128. {
    129. Keypoint p = keypoints; // p指向第一个结点
    130. while(p) // 没到表尾
    131. {
    132. cvLine( image, cvPoint((int)((p->col)-3),(int)(p->row)),
    133. cvPoint((int)((p->col)+3),(int)(p->row)), CV_RGB(255,255,0),
    134. 1, 8, 0 );
    135. cvLine( image, cvPoint((int)(p->col),(int)((p->row)-3)),
    136. cvPoint((int)(p->col),(int)((p->row)+3)), CV_RGB(255,255,0),
    137. 1, 8, 0 );
    138. // cvCircle(image,cvPoint((uchar)(p->col),(uchar)(p->row)),
    139. // (int)((GaussianPyr[p->octave].Octave)[p->level].absolute_sigma),
    140. // CV_RGB(255,0,0),1,8,0);
    141. p=p->next;
    142. }
    143. }
    144. // Compute the gradient direction and magnitude of the gaussian pyramid images
    145. void ComputeGrad_DirecandMag(int numoctaves, ImageOctaves *GaussianPyr)
    146. {
    147. // ImageOctaves *mag_thresh ;
    148. mag_pyr=(ImageOctaves*) malloc( numoctaves * sizeof(ImageOctaves) );
    149. grad_pyr=(ImageOctaves*) malloc( numoctaves * sizeof(ImageOctaves) );
    150. // float sigma=( (GaussianPyr[0].Octave)[SCALESPEROCTAVE+2].absolute_sigma ) / GaussianPyr[0].subsample;
    151. // int dim = (int) (max(3.0f, 2 * GAUSSKERN *sigma + 1.0f)*0.5+0.5);
    152. #define ImLevels(OCTAVE,LEVEL,ROW,COL) ((float *)(GaussianPyr[(OCTAVE)].Octave[(LEVEL)].Level->data.fl + GaussianPyr[(OCTAVE)].Octave[(LEVEL)].Level->step/sizeof(float) *(ROW)))[(COL)]
    153. for (int i=0; i<numoctaves; i++)
    154. {
    155. mag_pyr[i].Octave= (ImageLevels*) malloc( (SCALESPEROCTAVE) * sizeof(ImageLevels) );
    156. grad_pyr[i].Octave= (ImageLevels*) malloc( (SCALESPEROCTAVE) * sizeof(ImageLevels) );
    157. for(int j=1;j<SCALESPEROCTAVE+1;j++)//取中间的scaleperoctave个层
    158. {
    159. CvMat *Mag = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);
    160. CvMat *Ori = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);
    161. CvMat *tempMat1 = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);
    162. CvMat *tempMat2 = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);
    163. cvZero(Mag);
    164. cvZero(Ori);
    165. cvZero(tempMat1);
    166. cvZero(tempMat2);
    167. #define MAG(ROW,COL) ((float *)(Mag->data.fl + Mag->step/sizeof(float) *(ROW)))[(COL)]
    168. #define ORI(ROW,COL) ((float *)(Ori->data.fl + Ori->step/sizeof(float) *(ROW)))[(COL)]
    169. #define TEMPMAT1(ROW,COL) ((float *)(tempMat1->data.fl + tempMat1->step/sizeof(float) *(ROW)))[(COL)]
    170. #define TEMPMAT2(ROW,COL) ((float *)(tempMat2->data.fl + tempMat2->step/sizeof(float) *(ROW)))[(COL)]
    171. for (int m=1;m<(GaussianPyr[i].row-1);m++)
    172. for(int n=1;n<(GaussianPyr[i].col-1);n++)
    173. {
    174. //计算幅值
    175. TEMPMAT1(m,n) = 0.5*( ImLevels(i,j,m,n+1)-ImLevels(i,j,m,n-1) ); //dx
    176. TEMPMAT2(m,n) = 0.5*( ImLevels(i,j,m+1,n)-ImLevels(i,j,m-1,n) ); //dy
    177. MAG(m,n) = sqrt(TEMPMAT1(m,n)*TEMPMAT1(m,n)+TEMPMAT2(m,n)*TEMPMAT2(m,n)); //mag
    178. //计算方向
    179. ORI(m,n) =atan( TEMPMAT2(m,n)/TEMPMAT1(m,n) );
    180. if (ORI(m,n)==CV_PI)
    181. ORI(m,n)=-CV_PI;
    182. }
    183. ((mag_pyr[i].Octave)[j-1]).Level=Mag;
    184. ((grad_pyr[i].Octave)[j-1]).Level=Ori;
    185. cvReleaseMat(&tempMat1);
    186. cvReleaseMat(&tempMat2);
    187. }//for levels
    188. }//for octaves
    189. }

    SIFT算法第四步

    SIFT算法第五步

    SIFT算法第五步:抽取各个特征点处的特征描述字,确定特征点的描述字。描述字是Patch网格内梯度方向的描述,旋转网格到主方向,插值得到网格处梯度值。

    一个特征点可以用228=32维的向量,也可以用448=128维的向量更精确的进行描述。

    1. void ExtractFeatureDescriptors(int numoctaves, ImageOctaves *GaussianPyr)
    2. {
    3. // The orientation histograms have 8 bins
    4. float orient_bin_spacing = PI/4;
    5. float orient_angles[8]={-PI,-PI+orient_bin_spacing,-PI*0.5, -orient_bin_spacing,
    6. 0.0, orient_bin_spacing, PI*0.5, PI+orient_bin_spacing};
    7. //产生描述字中心各点坐标
    8. float *feat_grid=(float *) malloc( 2*16 * sizeof(float));
    9. for (int i=0;i<GridSpacing;i++)
    10. {
    11. for (int j=0;j<2*GridSpacing;++j,++j)
    12. {
    13. feat_grid[i*2*GridSpacing+j]=-6.0+i*GridSpacing;
    14. feat_grid[i*2*GridSpacing+j+1]=-6.0+0.5*j*GridSpacing;
    15. }
    16. }
    17. //产生网格
    18. float *feat_samples=(float *) malloc( 2*256 * sizeof(float));
    19. for ( i=0;i<4*GridSpacing;i++)
    20. {
    21. for (int j=0;j<8*GridSpacing;j+=2)
    22. {
    23. feat_samples[i*8*GridSpacing+j]=-(2*GridSpacing-0.5)+i;
    24. feat_samples[i*8*GridSpacing+j+1]=-(2*GridSpacing-0.5)+0.5*j;
    25. }
    26. }
    27. float feat_window = 2*GridSpacing;
    28. Keypoint p = keyDescriptors; // p指向第一个结点
    29. while(p) // 没到表尾
    30. {
    31. float scale=(GaussianPyr[p->octave].Octave)[p->level].absolute_sigma;
    32. float sine = sin(p->ori);
    33. float cosine = cos(p->ori);
    34. //计算中心点坐标旋转之后的位置
    35. float *featcenter=(float *) malloc( 2*16 * sizeof(float));
    36. for (int i=0;i<GridSpacing;i++)
    37. {
    38. for (int j=0;j<2*GridSpacing;j+=2)
    39. {
    40. float x=feat_grid[i*2*GridSpacing+j];
    41. featcenter[i*2*GridSpacing+j]=((cosine * x + sine * y) + p->sx);
    42. }
    43. }
    44. // calculate sample window coordinates (rotated along keypoint)
    45. float *feat=(float *) malloc( 2*256 * sizeof(float));
    46. for ( i=0;i<64*GridSpacing;i++,i++)
    47. {
    48. float x=feat_samples[i];
    49. float y=feat_samples[i+1];
    50. feat[i]=((cosine * x + sine * y) + p->sx);
    51. feat[i+1]=((-sine * x + cosine * y) + p->sy);
    52. }
    53. //Initialize the feature descriptor.
    54. float *feat_desc = (float *) malloc( 128 * sizeof(float));
    55. for (i=0;i<128;i++)
    56. {
    57. feat_desc[i]=0.0;
    58. // printf("%f ",feat_desc[i]);
    59. }
    60. //printf("/n");
    61. for ( i=0;i<512;++i,++i)
    62. {
    63. float x_sample = feat[i];
    64. float y_sample = feat[i+1];
    65. // Interpolate the gradient at the sample position
    66. /*
    67. 0 1 0
    68. 1 * 1
    69. 0 1 0 具体插值策略如图示
    70. */
    71. float sample12=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample, y_sample-1);
    72. float sample21=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample-1, y_sample);
    73. float sample22=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample, y_sample);
    74. float sample23=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample+1, y_sample);
    75. float sample32=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample, y_sample+1);
    76. //float diff_x = 0.5*(sample23 - sample21);
    77. //float diff_y = 0.5*(sample32 - sample12);
    78. float diff_x = sample23 - sample21;
    79. float diff_y = sample32 - sample12;
    80. float mag_sample = sqrt( diff_x*diff_x + diff_y*diff_y );
    81. float grad_sample = atan( diff_y / diff_x );
    82. if(grad_sample == CV_PI)
    83. grad_sample = -CV_PI;
    84. // Compute the weighting for the x and y dimensions.
    85. float *x_wght=(float *) malloc( GridSpacing * GridSpacing * sizeof(float));
    86. float *y_wght=(float *) malloc( GridSpacing * GridSpacing * sizeof(float));
    87. float *pos_wght=(float *) malloc( 8*GridSpacing * GridSpacing * sizeof(float));;
    88. for (int m=0;m<32;++m,++m)
    89. {
    90. float x=featcenter[m];
    91. float y=featcenter[m+1];
    92. x_wght[m/2] = max(1 - (fabs(x - x_sample)*1.0/GridSpacing), 0);
    93. y_wght[m/2] = max(1 - (fabs(y - y_sample)*1.0/GridSpacing), 0);
    94. }
    95. for ( m=0;m<16;++m)
    96. for (int n=0;n<8;++n)
    97. pos_wght[m*8+n]=x_wght[m]*y_wght[m];
    98. free(x_wght);
    99. free(y_wght);
    100. //计算方向的加权,首先旋转梯度场到主方向,然后计算差异
    101. float diff[8],orient_wght[128];
    102. for ( m=0;m<8;++m)
    103. {
    104. float angle = grad_sample-(p->ori)-orient_angles[m]+CV_PI;
    105. float temp = angle / (2.0 * CV_PI);
    106. angle -= (int)(temp) * (2.0 * CV_PI);
    107. diff[m]= angle - CV_PI;
    108. }
    109. // Compute the gaussian weighting.
    110. float x=p->sx;
    111. float y=p->sy;
    112. float g = exp(-((x_sample-x)*(x_sample-x)+(y_sample-y)*(y_sample-y))/(2*feat_window*feat_window))/(2*CV_PI*feat_window*feat_window);
    113. for ( m=0;m<128;++m)
    114. {
    115. orient_wght[m] = max((1.0 - 1.0*fabs(diff[m%8])/orient_bin_spacing),0);
    116. feat_desc[m] = feat_desc[m] + orient_wght[m]*pos_wght[m]*g*mag_sample;
    117. }
    118. free(pos_wght);
    119. }
    120. free(feat);
    121. free(featcenter);
    122. float norm=GetVecNorm( feat_desc, 128);
    123. for (int m=0;m<128;m++)
    124. {
    125. feat_desc[m]/=norm;
    126. if (feat_desc[m]>0.2)
    127. feat_desc[m]=0.2;
    128. }
    129. norm=GetVecNorm( feat_desc, 128);
    130. for ( m=0;m<128;m++)
    131. {
    132. feat_desc[m]/=norm;
    133. printf("%f ",feat_desc[m]);
    134. }
    135. printf("/n");
    136. p->descrip = feat_desc;
    137. p=p->next;
    138. }
    139. free(feat_grid);
    140. free(feat_samples);
    141. }
    142. //为了显示图象金字塔,而作的图像水平拼接
    143. CvMat* MosaicHorizen( CvMat* im1, CvMat* im2 )
    144. {
    145. int row,col;
    146. CvMat *mosaic = cvCreateMat( max(im1->rows,im2->rows),(im1->cols+im2->cols),CV_32FC1);
    147. #define Mosaic(ROW,COL) ((float*)(mosaic->data.fl + mosaic->step/sizeof(float)*(ROW)))[(COL)]
    148. #define Im11Mat(ROW,COL) ((float *)(im1->data.fl + im1->step/sizeof(float) *(ROW)))[(COL)]
    149. #define Im22Mat(ROW,COL) ((float *)(im2->data.fl + im2->step/sizeof(float) *(ROW)))[(COL)]
    150. cvZero(mosaic);
    151. /* Copy images into mosaic1. */
    152. for ( row = 0; row < im1->rows; row++)
    153. for ( col = 0; col < im1->cols; col++)
    154. Mosaic(row,col)=Im11Mat(row,col) ;
    155. for ( row = 0; row < im2->rows; row++)
    156. for ( col = 0; col < im2->cols; col++)
    157. Mosaic(row, (col+im1->cols) )= Im22Mat(row,col) ;
    158. return mosaic;
    159. }
    160. //为了显示图象金字塔,而作的图像垂直拼接
    161. CvMat* MosaicVertical( CvMat* im1, CvMat* im2 )
    162. {
    163. int row,col;
    164. CvMat *mosaic = cvCreateMat(im1->rows+im2->rows,max(im1->cols,im2->cols), CV_32FC1);
    165. #define Mosaic(ROW,COL) ((float*)(mosaic->data.fl + mosaic->step/sizeof(float)*(ROW)))[(COL)]
    166. #define Im11Mat(ROW,COL) ((float *)(im1->data.fl + im1->step/sizeof(float) *(ROW)))[(COL)]
    167. #define Im22Mat(ROW,COL) ((float *)(im2->data.fl + im2->step/sizeof(float) *(ROW)))[(COL)]
    168. cvZero(mosaic);
    169. /* Copy images into mosaic1. */
    170. for ( row = 0; row < im1->rows; row++)
    171. for ( col = 0; col < im1->cols; col++)
    172. Mosaic(row,col)= Im11Mat(row,col) ;
    173. for ( row = 0; row < im2->rows; row++)
    174. for ( col = 0; col < im2->cols; col++)
    175. Mosaic((row+im1->rows),col)=Im22Mat(row,col) ;

    最后,再看一下,运行效果(图中美女为老乡+朋友,何姐08年照):

    教你一步一步用c语言实现sift算法、下 - 图1

    教你一步一步用c语言实现sift算法、下 - 图2

    完。

    updated

    有很多朋友都在本文评论下要求要本程序的完整源码包(注:本文代码未贴全,复制粘贴编译肯定诸多错误),但由于时隔太久,这份代码我自己也找不到了,不过,我可以提供一份sift + KD + BBF,且可以编译正确的代码供大家参考学习,有pudn帐号的朋友可以前去下载:(没有pudn账号的同学请加群:169056165,验证信息:sift,至群共享下载),然后用两幅不同的图片做了下匹配(当然,运行结果显示是不匹配的),效果还不错:http://weibo.com/1580904460/yDmzAEwcV#1348475194313! July、二零一二年十月十一日。