特征点检测学习_1(sift算法)



    sift算法在cv领域的重要性不言而喻,该作者的文章引用率在cv界是number1.本篇博客只是本人把sift算法知识点整理了下,以免忘记。本文比较早的一篇博文opencv源码解析之(3):特征点检查前言1 中有使用opencv自带的sift做了个简单的实验,而这次主要是利用Rob Hess的sift源码来做实验,其实现在的opencv版本中带的sift算法也是Rob Hess的,只是稍微包装了下。

  首先网上有不少文章介绍了sift算法,写得都不错,比如: 

     http://www.cnblogs.com/cfantaisie/archive/2011/06/14/2080917.html

     该博客对sift算法理论做了介绍,且有示意图辅助理解,从该文中可以了解sift算法的大概流程.

     http://www.cnblogs.com/linyunzju/archive/2011/06/14/2080950.html

     这篇文章对sift算法做了通俗易懂的解释.

  http://blog.csdn.net/v_july_v/article/category/795430

  这篇博客有教你怎样用c语言一步一步写sift算法。

  http://underthehood.blog.51cto.com/2531780/658350

  该文也对sift做了详细的介绍,博客的作者还对sift匹配做了讲解。

 

  下面还是简单看下sift算法的理论,具体的内容可以参考上面的几篇文章。

 

  一、Sift描述子形成的步骤

 

  1、 构造高斯差分空间图像。

  Sift特征点的检测时在DOG图像上进行的,DOG图像是将相邻尺度空间图像相减得到的。且金字塔的每一层都要构造一个DOG空间图像。默认参数是金字塔4层,即4个octave,每一个octave中有5张不同尺度的图片,不同octave的图片尺寸大小不同,所以每一层中就会得到4幅DOG图像。

高斯金字塔的第1层第1副原图像是将原图像放大2倍且sigma(sigma=1.6)模糊,第2幅图像是k*sigma(k等于根号2)模糊,第3幅是k*k*sigma模糊,后面类推…

     高斯金字塔第2层第1幅图是选择金字塔上一层(这里是第1层)中尺度空间参数为k*k*sigma的那幅图(实际上是2倍的尺度空间)进行降采样(尺寸大小为原来的1/4倍)得到,如果k不等于根号2,那么取原图的2*sigma降采样得到。第2层第2幅图是在本层第一幅图尺度模糊系数增加k倍模糊后的图像,后面类似…

  示意图如下所示:

  

     尺度不变当然是与图片尺寸有关,即图片的尺寸大小变化,但是其检测结果不变。

 

  2、寻找极大极小值点。

  将每个像素点与其所在的那幅图像邻域的8个像素,它所在的向量尺度空间上下2幅图对应位置邻域各9个点,总共26个点进行像素值比较,如果该点是最大或者最小点,则改点就暂时列为特征点。

  其邻图如下:

  

 

  3、精确定位极值点

  子像素级极值点:

  由于上面找到的近似极值点落在像素点的位置上,实际上我们在像素点附近如果用空间曲面去拟合的话,很多情况下极值点都不是恰好在像素点上,而是在附近。所以sift算法提出的作者用泰勒展开找到了亚像素级的特征点。这种点更稳定,更具有代表性。

  消除对比度低的特征点:

  对求出亮度比较低的那些点直接过滤点,程序中的阈值为0.03.

  消除边界上的点:

  处理方法类似harrs角点,把平坦区域和直线边界上的点去掉,即对于是边界上的点但又不是直角上的点,sift算法是不把这些点作为特征点的。

 

  4、选取特征点主方向

  在特征点附近选取一个区域,该区域大小与图图像的尺度有关,尺度越大,区域越大。并对该区域统计36个bin的方向直方图,将直方图中最大bin的那个方向作为该点的主方向,另外大于最大bin80%的方向也可以同时作为主方向。这样的话,由于1个特征点有可能有多个主方向,所以一个特征点有可能有多个128维的描述子。如下图所示:

  

 

     5、 构造特征点描述算子。

     以特征点为中心,取领域内16*16大小的区域,并把这个区域分成4*4个大小为4*4的小区域,每个小区域内计算加权梯度直方图,该权值分为2部分,其一是该点的梯度大小,其二是改点离特征点的距离(二维高斯的关系),每个小区域直方图分为8个bin,所以一个特征点的维数=4*4*8=128维。示意图如下(该图取的领域为8*8个点,因此描述子向量的维数为32维):

  

 

   6、实验部分

         下面来做下试验,试验sift代码采用Rob Hess的代码,opencv目前版本中的sift源码也是采用Rob Hess的。代码可以在他的主页上下载:http://blogs.oregonstate.edu/hess/code/sift/

这里我下载的是windows版本的,并采用Qt做了个简单的界面。

         环境:WindowsXP+Opencv2.4.2+Qt4.8.2+QtCreator2.5.1,QtCreator内部采用的是vc的编译器。

         运行软件,单击Open Image后选择一张需要进行特征点检测的图片,我这里显示的结果如下:  

    

 

         单击Sift Detect按钮后,检测到的效果如下:

    


   

主要代码部分如下(附录有工程code下载链接):

SiftDetect.h:


点击(此处)折叠或打开

  1. #ifndef SIFTDETECT_H
  2. #define SIFTDETECT_H

  3. #include <QDialog>
  4. #include <opencv2/core/core.hpp>
  5. #include <opencv2/highgui/highgui.hpp>
  6. #include <opencv2/imgproc/imgproc.hpp>
  7. //#include <opencv/cxcore.h>
  8. //#include <opencv/highgui.h>
  9. //#include <opencv/imgproc.h>
  10. #include <stdio.h>
  11. #include <stdio.h>
  12. #include "sift.h"
  13. #include "imgfeatures.h"
  14. #include "utils.h"


  15. using namespace cv;

  16. namespace Ui {
  17. class SiftDetect;
  18. }

  19. class SiftDetect : public QDialog
  20. {
  21.     Q_OBJECT
  22.     
  23. public:
  24.     explicit SiftDetect(QWidget *parent = 0);
  25.     ~SiftDetect();
  26.     
  27. private slots:


  28.     void on_openButton_clicked();

  29.     void on_detectButton_clicked();

  30.     void on_closeButton_clicked();

  31. private:
  32.     Ui::SiftDetect *ui;

  33.     Mat src, dst;
  34.     IplImage* img;
  35.     struct feature* features;
  36.     int n;
  37.     int display;
  38.     int intvls;
  39.     double sigma;
  40.     double contr_thr;
  41.     int curv_thr;
  42.     int img_dbl;
  43.     int descr_width;
  44.     int descr_hist_bins;
  45. };

  46. #endif // SIFTDETECT_H




SiftDetect.cpp:

点击(此处)折叠或打开

  1. #include "siftdetect.h"
  2. #include "ui_siftdetect.h"
  3. #include <QtGui>
  4. #include <QtCore>
  5. #include "sift.h"
  6. #include "imgfeatures.h"
  7. #include "utils.h"
  8. //#include <sift.c>

  9. SiftDetect::SiftDetect(QWidget *parent) :
  10.     QDialog(parent),
  11.     ui(new Ui::SiftDetect)
  12. {
  13.     ui->setupUi(this);

  14.     n = 0;
  15.     display = 1;
  16.     intvls = SIFT_INTVLS;
  17.     sigma = SIFT_SIGMA;
  18.     contr_thr = SIFT_CONTR_THR;
  19.     curv_thr = SIFT_CURV_THR;
  20.     img_dbl = SIFT_IMG_DBL;
  21.     descr_width = SIFT_DESCR_WIDTH;
  22.     descr_hist_bins = SIFT_DESCR_HIST_BINS;
  23. }

  24. SiftDetect::~SiftDetect()
  25. {
  26.  // cvReleaseImage( &img );//释放内存退出程序后竟然报错
  27.     delete ui;
  28. }



  29. void SiftDetect::on_openButton_clicked()
  30. {
  31.     QString img_name = QFileDialog::getOpenFileName(this, "Open Image", "../sift_detect",
  32.                                                     tr("Image Files(*.png *.jpeg *.jpg *.bmp)"));
  33.   // img = cvLoadImage( img_name.toAscii().data() );
  34.     src = imread( img_name.toAscii().data() );
  35.     imwrite( "../sift_detect/src.jpg", src );
  36.     ui->textBrowser->clear();
  37.     ui->textBrowser->setFixedSize( src.cols, src.rows );
  38.     ui->textBrowser->append( "" );

  39. }

  40. void SiftDetect::on_detectButton_clicked()
  41. {
  42.     //将Mat型的src转换成IplImage*型的img,因为这里是opencv新老版本混合编程的方法。
  43.      img = &src.operator IplImage();
  44.      n = _sift_features( img, &features, intvls, sigma, contr_thr, curv_thr, img_dbl, descr_width, descr_hist_bins );
  45.      if( display )
  46.          {
  47.              draw_features( img, features, n );
  48.              ui->textBrowser->clear();
  49.              //将IplImage*型的img转换成Mat型的dst,这也是opencv新老版本混合编程的一种方法。
  50.              dst = Mat( img );
  51.              imwrite( "../sift_detect/dst.jpg", dst );
  52.              //cvSaveImage( "../sift_detect/dst.jpg", img );
  53.              ui->textBrowser->append( "" );
  54.          }
  55. }

  56. void SiftDetect::on_closeButton_clicked()
  57. {
  58.     close();
  59. }

 

  二、Sift特征点匹配过程

 

  由步骤一我们已经获得了图片的特征点向量集合。现在来看看特征点匹配,特征点匹配的一个应用就是物体的识别,比如说我有2张图片A和B,图片的内容相同,只是图片的大小尺寸不同。假设A图片尺寸比较大,且我们已经采用sift算法对图片A和B都进行了检测,获得了它们的特征点集合,现在我们的问题是需要把A和B中相应的特征点给对应连线起来。

  既然是匹配,当然每个特征点向量要相似才能匹配到一起,这里采用的是欧式距离来衡量其相似度。

  对B中的特征点x,去寻找A中最相似的点y,最简单的方法就是拿x与A中所有点进行相似度比较,距离最小的那个为匹配点。但是如果图片中特征点数目很多的话,这样效率会很低。所以我们需要把A中特征点向量集合用一种数据结构来描述,这种描述要有利于x在A中的搜索,即减少时间复杂度。在sift匹配中,这种数据结构采用的是kd-tree。

  关于kd-tree的讲解,可以参考博文http://underthehood.blog.51cto.com/2531780/687160

  里面讲得比较详细,且举了例子,很容易理解,这里就没有必要重复了。

     同样,采用Rob Hess的代码做了个sift匹配的实验,开发环境与上面的一样。

     打开软件后,单击Open Image按钮,依次打开需要匹配的2张图片,如下图所示:

  

 

     单击Sift Detect按钮,则程序会单独对这2幅图片进行sift特征点检测,结果如下图所示:

  

 

     单击Sift Match按钮,则会对这2幅图的特征点结果进行匹配,本次实验的匹配图如下所示:

  

 

实验主要部分代码(附录有工程code链接下载):

SiftMatch.h:


点击(此处)折叠或打开

  1. #ifndef SIFTMATCH_H
  2. #define SIFTMATCH_H

  3. #include <QDialog>
  4. #include <opencv2/core/core.hpp>
  5. #include <opencv2/highgui/highgui.hpp>
  6. #include <opencv2/imgproc/imgproc.hpp>

  7. using namespace cv;

  8. namespace Ui {
  9. class SiftMatch;
  10. }

  11. class SiftMatch : public QDialog
  12. {
  13.     Q_OBJECT
  14.     
  15. public:
  16.     explicit SiftMatch(QWidget *parent = 0);
  17.     ~SiftMatch();
  18.     
  19. private slots:
  20.     void on_openButton_clicked();

  21.     void on_detectButton_clicked();

  22.     void on_matchButton_clicked();

  23.     void on_closeButton_clicked();

  24. private:
  25.     Ui::SiftMatch *ui;
  26.     Mat src1, src2, src1_c, src2_c, dst;
  27.     IplImage *img1, *img2, *img3, *stacked;
  28.     Point pt1, pt2;
  29.     double d0, d1;
  30.     struct feature *feat1, *feat2, *feat;
  31.     struct feature **nbrs;
  32.     struct kd_node *kd_root;
  33.     int open_image_number;
  34.     int n1, n2, k, i, m;
  35. };

  36. #endif // SIFTMATCH_H

SiftMatch.cpp:


点击(此处)折叠或打开

  1. #include "siftmatch.h"
  2. #include "ui_siftmatch.h"

  3. #include <QtCore>
  4. #include <QtGui>
  5. #include "imgfeatures.h"
  6. #include "kdtree.h"
  7. #include "minpq.h"
  8. #include "sift.h"
  9. #include "utils.h"
  10. #include "xform.h"

  11. /* the maximum number of keypoint NN candidates to check during BBF search */
  12. #define KDTREE_BBF_MAX_NN_CHKS 200

  13. /* threshold on squared ratio of distances between NN and 2nd NN */
  14. #define NN_SQ_DIST_RATIO_THR 0.49

  15. SiftMatch::SiftMatch(QWidget *parent) :
  16.     QDialog(parent),
  17.     ui(new Ui::SiftMatch)
  18. {
  19.     open_image_number = 0;
  20.     m = 0;

  21.     ui->setupUi(this);
  22. }

  23. SiftMatch::~SiftMatch()
  24. {
  25.     delete ui;
  26. }

  27. void SiftMatch::on_openButton_clicked()
  28. {
  29.     QString img_name = QFileDialog::getOpenFileName(this, "Open Image", "../sift_detect",
  30.                                                     tr("Image Files(*.png *.jpeg *.jpg *.bmp)"));
  31.     open_image_number++;
  32.     //打开第1张图片
  33.     if( 1 == open_image_number )
  34.         {
  35.             src1 = imread( img_name.toAscii().data() );
  36.             img1 = cvLoadImage( img_name.toAscii().data() );
  37.             //转换成IplImage*类型,但是这样转换过的后面使用起来感觉还是不特别顺利,说明并不是完全100%兼容了。
  38.       // img1 = &src1.operator IplImage();
  39.             imwrite( "../sift_match/src1.jpg", src1 );
  40.             ui->textBrowser->setFixedSize( src1.cols, src1.rows );
  41.             ui->textBrowser->append( "" );
  42.          }
  43.     //打开第2张图片
  44.     else if( 2 == open_image_number )
  45.         {
  46.             src2 = imread( img_name.toAscii().data() );
  47.             img2 = cvLoadImage( img_name.toAscii().data() );
  48.          // img2 = &src2.operator IplImage();
  49.             imwrite( "../sift_match/src2.jpg", src2 );
  50.             ui->textBrowser->setFixedSize( src2.cols+src1.cols, src2.rows+src1.rows );
  51.             ui->textBrowser->append( "" );
  52.         }
  53.     else
  54.         open_image_number = 0;

  55. }

  56. void SiftMatch::on_detectButton_clicked()
  57. {
  58.     //将2幅图片合成1幅图片
  59.     //img1 = cvLoadImage();
  60.     stacked = stack_imgs( img1, img2 );
  61.     ui->textBrowser->clear();

  62.     //显示第1幅图片上的特征点
  63.     n1 = sift_features( img1, &feat1 );
  64.     draw_features( img1, feat1, n1 );
  65.     src1_c = Mat(img1);
  66.     imwrite("../sift_match/src1_c.jpg", src1_c);
  67.     ui->textBrowser->append("");

  68.     //显示第2幅图片上的特征点
  69.     n2 = sift_features( img2, &feat2 );
  70.     draw_features( img2, feat2, n2 );
  71.     src2_c = Mat(img2);
  72.     imwrite("../sift_match/src2_c.jpg", src2_c);
  73.     ui->textBrowser->append("");
  74. }

  75. void SiftMatch::on_matchButton_clicked()
  76. {
  77.     kd_root = kdtree_build( feat2, n2 );
  78.     for( i = 0; i < n1; i++ )
  79.         {
  80.             feat = feat1+i;
  81.             k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );
  82.             if( k == 2 )
  83.                 {
  84.                     d0 = descr_dist_sq( feat, nbrs[0] );
  85.                     d1 = descr_dist_sq( feat, nbrs[1] );
  86.                     if( d0 < d1 * NN_SQ_DIST_RATIO_THR )
  87.                         {
  88.                             pt1 = Point( cvRound( feat->x ), cvRound( feat->y ) );
  89.                             pt2 = Point( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );
  90.                             pt2.y += img1->height;
  91.                             cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );
  92.                             m++;
  93.                             feat1[i].fwd_match = nbrs[0];
  94.                         }
  95.                 }
  96.              free( nbrs );
  97.          }
  98.     dst = Mat( stacked );
  99.     imwrite( "../sift_match/dst.jpg", dst );
  100.     ui->textBrowser->clear();
  101.     ui->textBrowser->setFixedSize( dst.cols, dst.rows );
  102.     ui->textBrowser->append("");

  103. }

  104. void SiftMatch::on_closeButton_clicked()
  105. {
  106.     close();
  107. }

 

   总结:

   通过整理下sift算法知识点,对sift算法有了更全面的认识,另外感谢Rob Hess开源了sift算法的代码,感觉写好这个算法确实不同意的。(另外,本文博客中引用了上面提到的博客中的图片,在此声明一下。)

 

 

         附录一:

         Rob Hess sift的c代码在c++中的使用。

由于Rob Hess的代码是基于c的,如果在其它关于界面开发的c++程序中,比如Qt,MFC等。我这里是Qt,连接时会报如下错误:

siftdetect.obj:-1: error: LNK2019: 无法解析的外部符号 "int __cdecl _sift_features(struct _IplImage *,struct feature * *,int,double,double,int,int,int,int)" (?_sift_features@@YAHPAU_IplImage@@PAPAUfeature@@HNNHHHH@Z),该符号在函数 "private: void __thiscall SiftDetect::on_detectButton_clicked(void)" (?on_detectButton_clicked@SiftDetect@@AAEXXZ) 中被引用

         网上也有不少网友碰到过类似的情况,比如http://www.opencv.org.cn/forum/viewtopic.php?p=53307http://topic.csdn.net/u/20120111/21/0368bba0-54b4-42df-8ed5-8e50920ac197.html 但是他们都没有给出解决办法。

         因此我们要找本质的原因,原因就是c语法和c++语法毕竟不同,所以难免有些兼容性问题。看错误提示我们知道是在函数_sift_features时报的错,该函数在Rob Hess的头文件中是被定义的extern类型。而在c的编译器中,extern的函数文件名编译后会自动在前面加一杆,”_”;而c++语法中会有函数重载的现象,因此它不是像c那样直接在前面加”_”,否则会冲突,因此c++编译器会在其函数名后面加入一些像乱码的东西(反正链接时是机器去寻找,只要能区分即可)。

         具体的内容可以参考博客:http://blog.csdn.net/wujian53/article/details/706975 这里面讲得比较明白,谢谢这位博主。

         本次实验的解决方法是在Rob Hess的sift.h等几个头文件文件开始处加入语句:

#ifdef __cplusplus extern "C" { #endif     

该文件的结处加入语句:

#ifdef __cplusplus

} #endif

 

  这样的话编译器在编译该文件时会知道这是C语法,所以其中间文件命名规则会相应改变,问题也就相应的解决了。

     另外,如果出现错误提示:

  utils.obj:-1: error: LNK2019: 无法解析的外部符号 _va_end,该符号在函数 _fatal_error 中被引用。

    则在utils.c代码中找到va_start( ap, format );和va_end( ap );并将其注释起来即可。

 

 

  附录二:

  这2个实验的工程code下载地址

 

 

 

 

 

 

作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(3) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
<p> <span style="color:#4d4d4d;">当前课程中博客项目的实战源码是我在 GitHub上开源项目 My-Blog,目前已有 2000 多个 star:</span> </p> <p> <span style="color:#4d4d4d;"><img src="https://img-bss.csdnimg.cn/202103310649344285.png" alt="" /><br /> </span> </p> <p> <span style="color:#4d4d4d;">本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 大部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 个人博客项目功能的讲解,<span style="color:#565656;">通过本课程的学习,不仅仅让你掌握基本的 Spring Boot 开发能力以及 Spring Boot 项目的大部分开发使用场景,同时帮你提前甄别和处理掉将要遇到的技术难点,认真学完这个课程后,你将会对 Spring Boot 有更加深入而全面的了解,同时你也会得到一个大家都在使用的博客系统源码,你可以根据自己的需求和想法进行改造,也可以直接使用它来作为自己的个人网站,这个课程一定会给你带来巨大的收获。</span></span> </p> <p> <span style="color:#4d4d4d;"><span style="color:#565656;"> </span></span> </p> <p> <span style="color:#e53333;"><span style="color:#e53333;"><strong>课程特色</strong></span></span> </p> <p> <span style="color:#e53333;"><span style="color:#e53333;"><strong> </strong></span></span> </p> <p> <span style="color:#4d4d4d;"><span style="color:#565656;"> </span></span> </p> <ol> <li> <span style="color:#565656;">课程内容紧贴 Spring Boot 技术栈,涵盖大部分 Spring Boot 使用场景。</span> </li> <li> <span style="color:#565656;">开发教程详细完整、文档资源齐全、实验过程循序渐进简单明了。</span> </li> <li> <span style="color:#565656;">实践项目页面美观且实用,交互效果完美。</span> </li> <li> <span style="color:#565656;">包含从零搭建项目、以及完整的后台管理系统和博客展示系统两个系统的功能开发流程。</span> </li> <li> <span style="color:#565656;">技术栈新颖且知识点丰富,学习后可以提升大家对于知识的理解和掌握,对于提升你的市场竞争力有一定的帮助。</span> </li> </ol> <p> <strong>实战项目预览</strong> </p> <p> <span style="color:#4d4d4d;"><span style="color:#565656;"><span style="color:#e53333;"><strong> </strong></span></span></span> </p> <p> <span style="color:#4d4d4d;"><img src="https://img-bss.csdn.net/202005150303066258.png" alt="" /><br /> </span> </p> <p>   </p> <p> <span style="color:#4d4d4d;"> </span> </p> <p> <span style="color:#4d4d4d;"><img src="https://img-bss.csdn.net/202005150305396930.png" alt="" /><br /> </span> </p> <p> <span style="color:#4d4d4d;"> </span> </p> <p> <span style="color:#4d4d4d;"><img src="https://img-bss.csdn.net/202005150305528842.png" alt="" /><br /> </span> </p> <p> <span style="color:#4d4d4d;"> </span> </p> <p> <span style="color:#4d4d4d;"><img src="https://img-bss.csdn.net/202005150306056323.png" alt="" /><br /> </span> </p>
包含以下内容: 第一部分 基础篇 001 第一个C程序 002 运行多个源文件 003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 013 用二维数组实现矩阵转置 014 求解二维数组的最大/最小元素 015 利用数组求前n个质数 016 编制万年历 017 对数组元素排序 018 任意进制数的转换 019 判断回文数 020 求数组前n元素之和 021 求解钢材切割的最佳订单 022 通过指针比较整数大小 023 指向数组的指针 024 寻找指定元素的指针 025 寻找相同元素的指针 026 阿拉伯数字转换为罗马数字 027 字符替换 028 从键盘读入实数 029 字符行排版 030 字符排列 031 判断字符串是否回文 032 通讯录的输入输出 033 扑克牌的结构表示 034 用“结构”统计学生成绩 035 报数游戏 036 模拟社会关系 037 统计文件的字符数 038 同时显示两个文件的内容 039 简单的文本编辑器 040 文件的字数统计程序 041 学生成绩管理程序 第二部分 数据结构篇 042 插入排序 043 希尔排序 044 冒泡排序 045 快速排序 046 选择排序 047 堆排序 048 归并排序 049 基数排序 050 二叉搜索树操作 051 二项式系数递归 052 背包问题 053 顺序表插入和删除 054 链表操作(1) 055 链表操作(2) 056 单链表就地逆置 057 运动会分数统计 058 双链表 059 约瑟夫环 060 记录个人资料 061 二叉树遍利 062 浮点数转换为字符串 063 汉诺塔问题 064 哈夫曼编码 065 图的深度优先遍利 066 图的广度优先遍利 067 求解最优交通路径 068 八皇后问题 069 骑士巡游 070 用栈设置密码 071 魔王语言翻译 072 火车车厢重排 073 队列实例 074 K阶斐波那契序列 第三部分 数值计算与趣味数学篇 075 绘制余弦曲线和直线的迭加 076 计算高次方数的尾数 077 打鱼还是晒网 078 怎样存钱以获取最大利息 079 阿姆斯特朗数 080 亲密数 081 自守数 082 具有abcd=(ab+cd)2性质的数 083 验证歌德巴赫猜想 084 素数幻方 085 百钱百鸡问题 086 爱因斯坦的数学题 087 三色球问题 088 马克思手稿中的数学题 089 配对新郎和新娘 090 约瑟夫问题 091 邮票组合 092 分糖果 093 波瓦松的分酒趣题 094 求π的近似值 095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式乘法 106 产生随机数 107 堆栈四则运算 108 递归整数四则运算 109 复平面作图 110 绘制彩色抛物线 111 绘制正态分布曲线 112 求解非线性方程 113 实矩阵乘法运算 114 求解线性方程 115 n阶方阵求逆 116 复矩阵乘法 117 求定积分 118 求满足特异条件的数列 119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 129 飘带图案 130 圆环图案 131 肾形图案 132 心脏形图案 133 渔网图案 134 沙丘图案 135 设置图形方式下的文本类型 136 绘制正多边形 137 正六边形螺旋图案 138 正方形螺旋拼块图案 139 图形法绘制圆 140 递归法绘制三角形图案 141 图形法绘制椭圆 142 抛物样条曲线 14
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页