## Chapter 5: Storing All the Features in a Single Structure/File

Up to now, all the features have been contained in a feature list, which is overwritten when the features are tracked. Sometimes, however, it is desirable to keep the features from the last frame, or from the last few frames, or from all the frames. In these cases, it would be tedious to have to create a new feature list for each image. Instead, we create what is called a feature table. While a feature list is a one-dimensional array of features from a single image, a feature table is a two-dimensional array of features from many images. Each column of the table is a feature list.

The sample code below shows the use of the sequential mode from the last chapter, as well as the use of a feature table. If the constant `REPLACE` is defined, then lost features are replaced; otherwise they are not. In the former case, new features can be identified in the table because they have positive (rather than zero) values. Now let us examine the unfamiliar lines of code.

KLTCreateFeatureTable() creates a feature table, given the number of frames and the number of features to store. Although in this example the number of frames is the same as the total number of actual images, this does not have to be the case if all the features do not need to be stored.

KLTStoreFeatureList() stores a feature list as the ith column of a feature table, where i is given by the third parameter (i must be between `0` and `ft->nFrames-1`, inclusive). The dimensions of the feature list and feature table must be compatible, meaning that they must both contain the same number of features. It is perfectly legal to overwrite a column that has already been used, although this is not done in the current example.

KLTWriteFeatureTable() writes a feature table to a file, in a manner similar to that of KLTWriteFeatureList(), which was described in Chapter 2.

### Example 3

    /**********************************************************************
    Finds the 150 best features in an image and tracks them through the
    next two images.  The sequential mode is set in order to speed
    processing.  The features are stored in a feature table, which is then
    saved to a text file; each feature list is also written to a PPM file.
    **********************************************************************/

    #include <stdlib.h>
    #include <stdio.h>
    #include "pnmio.h"
    #include "klt.h"

    #define REPLACE

    void main()
    {
         unsigned char *img1, *img2;
         char fnamein[100], fnameout[100];
         KLT_TrackingContext tc;
         KLT_FeatureList fl;
         KLT_FeatureTable ft;
         int nFeatures = 150, nFrames = 10;
         int ncols, nrows;
         int i;

         tc = KLTCreateTrackingContext();
         fl = KLTCreateFeatureList(nFeatures);
         ft = KLTCreateFeatureTable(nFrames, nFeatures);
         tc->sequentialMode = TRUE;

         img1 = pgmReadFile("img0.pgm", NULL, &ncols, &nrows);
         img2 = (unsigned char *) malloc(ncols*nrows*sizeof(unsigned char));

         KLTSelectGoodFeatures(tc, img1, ncols, nrows, fl);
         KLTStoreFeatureList(fl, ft, 0);
         KLTWriteFeatureListToPPM(fl, img1, ncols, nrows, "feat0.ppm");

         for (i = 1 ; i < nFrames ; i++)  {
              sprintf(fnamein, "img%d.pgm", i);
              pgmReadFile(fnamein, img2, &ncols, &nrows);
              KLTTrackFeatures(tc, img1, img2, ncols, nrows, fl);
    #ifdef REPLACE
              KLTReplaceLostFeatures(tc, img2, ncols, nrows, fl);
    #endif
              KLTStoreFeatureList(fl, ft, i);
              sprintf(fnameout, "feat%d.ppm", i);
              KLTWriteFeatureListToPPM(fl, img2, ncols, nrows, fnameout);
         }
         KLTWriteFeatureTable(ft, "features.txt", "%5.1f");
    }