Example #1
0
static PyObject *sift(PyObject *self, PyObject *args, PyObject *kwargs)
{
  PyObject *input, *input_frames = NULL;
  PyArrayObject *matin, *out_descr, *out_frames;
  /* Input arguments */
  static char *kwlist[] = {"input", "Octave", "Levels", "FirstOctave", "Frames",
                           "PeakThresh", "EdgeThresh", "NormThresh", "Orientations", "Verbose", NULL};

  enum {IN_I=0,IN_END} ;
  enum {OUT_FRAMES=0, OUT_DESCRIPTORS} ;

  int                verbose = 0 ;
  int                opt ;
  int                next = IN_END ;
  int                nout = 2;
  vl_sift_pix const *data ;
  int                M, N ;

  int                O     = - 1 ;
  int                S     =   3 ;
  int                o_min =   0 ;

  double             edge_thresh = -1 ;
  double             peak_thresh = -1 ;
  double             norm_thresh = -1 ;

  PyArrayObject     *ikeys_array = 0 ;
  double            *ikeys = 0 ;
  int                nikeys = -1 ;
  vl_bool            force_orientations = 0 ;

  //  VL_USE_MATLAB_ENV ;

  /* Parse Python tuples into their appropriate variables */
  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iiiOiiiii", kwlist, &matin, &O, &S, &o_min, &input_frames,
                                   &peak_thresh, &edge_thresh, &norm_thresh, &force_orientations, &verbose))
    return NULL;

  //  matin = (PyArrayObject *) PyArray_ContiguousFromObject(input, PyArray_FLOAT, 2, 2);
  //if (matin == NULL)
  //  return NULL;

  /* -----------------------------------------------------------------
   *                                               Check the arguments
   * -------------------------------------------------------------- */

  if (matin->nd != 2 || matin->descr->type_num != PyArray_FLOAT) {
    printf("I must be a 2d matrix of dtype float32\n") ;
    return NULL;
  }

  // Pointer to the data array in matin
  //data = (vl_sift_pix *) pyvector_to_Carrayptrs(matin);
  // vl_sift_pix is float!
  data = (vl_sift_pix *) matin->data;

  M = matin->dimensions[0];
  N = matin->dimensions[1];

  if (input_frames != NULL) {
    ikeys_array = (PyArrayObject *) PyArray_ContiguousFromObject(input_frames, PyArray_FLOAT, 2, 2);
    if (ikeys_array->dimensions[0] != 4) {
      printf("'Frames' must be a 4 x N matrix.x\n");
      return NULL;
    }
    nikeys = ikeys_array->dimensions[1];
    ikeys = (double *) ikeys_array->data;
    qsort (ikeys, nikeys, 4 * sizeof(double), korder);
  }


  /* -----------------------------------------------------------------
   *                                                            Do job
   * -------------------------------------------------------------- */
  {
    VlSiftFilt        *filt ;
    vl_bool            first ;
    double            *frames = 0 ;
    vl_uint8          *descr  = 0 ;
    int                nframes = 0, reserved = 0, i,j,q ;

    /* create a filter to process the image */
    filt = vl_sift_new (M, N, O, S, o_min) ;

    if (peak_thresh >= 0) vl_sift_set_peak_thresh (filt, peak_thresh) ;
    if (edge_thresh >= 0) vl_sift_set_edge_thresh (filt, edge_thresh) ;
    if (norm_thresh >= 0) vl_sift_set_norm_thresh (filt, norm_thresh) ;

    if (verbose) {
      printf("siftmx: filter settings:\n") ;
      printf("siftpy:   octaves      (O)     = %d\n",
             vl_sift_get_octave_num   (filt)) ;
      printf("siftpy:   levels       (S)     = %d\n",
             vl_sift_get_level_num    (filt)) ;
      printf("siftpy:   first octave (o_min) = %d\n",
             vl_sift_get_octave_first (filt)) ;
      printf("siftpy:   edge thresh           = %g\n",
             vl_sift_get_edge_thresh   (filt)) ;
      printf("siftpy:   peak thresh           = %g\n",
             vl_sift_get_peak_thresh   (filt)) ;
      printf("siftpy:   norm thresh           = %g\n",
             vl_sift_get_norm_thresh   (filt)) ;
      printf("siftpy: will force orientations? %s\n",
             force_orientations ? "yes" : "no") ;
    }
    
    Py_BEGIN_ALLOW_THREADS

    /* ...............................................................
     *                                             Process each octave
     * ............................................................ */
    i     = 0 ;
    first = 1 ;
    while (1) {
      int                   err ;
      VlSiftKeypoint const *keys  = 0 ;
      int                   nkeys = 0 ;

      if (verbose) {
        printf ("siftpy: processing octave %d\n",
                vl_sift_get_octave_index (filt)) ;
      }

      /* Calculate the GSS for the next octave .................... */
      if (first) {
        err   = vl_sift_process_first_octave (filt, data) ;
        first = 0 ;
      } else {
        err   = vl_sift_process_next_octave  (filt) ;
      }

      if (err) break ;

      if (verbose > 1) {
        printf("siftpy: GSS octave %d computed\n",
               vl_sift_get_octave_index (filt));
      }

      /* Run detector ............................................. */
      if (nikeys < 0) {
        vl_sift_detect (filt) ;

        keys  = vl_sift_get_keypoints     (filt) ;
        nkeys = vl_sift_get_keypoints_num (filt) ;
        i     = 0 ;

        if (verbose > 1) {
          printf ("siftpy: detected %d (unoriented) keypoints\n", nkeys) ;
        }
      } else {
        nkeys = nikeys ;
      }

      /* For each keypoint ........................................ */
      for (; i < nkeys ; ++i) {
        double                angles [4] ;
        int                   nangles ;
        VlSiftKeypoint        ik ;
        VlSiftKeypoint const *k ;

        /* Obtain keypoint orientations ........................... */
        if (nikeys >= 0) {
          vl_sift_keypoint_init (filt, &ik,
                                 ikeys [4 * i + 1] - 1,
                                 ikeys [4 * i + 0] - 1,
                                 ikeys [4 * i + 2]) ;

          if (ik.o != vl_sift_get_octave_index (filt)) {
            break ;
          }

          k = &ik ;

          /* optionally compute orientations too */
          if (force_orientations) {
            nangles = vl_sift_calc_keypoint_orientations
              (filt, angles, k) ;
          } else {
            angles [0] = VL_PI / 2 - ikeys [4 * i + 3] ;
            nangles    = 1 ;
          }
        } else {
          k = keys + i ;
          nangles = vl_sift_calc_keypoint_orientations
            (filt, angles, k) ;
        }

        /* For each orientation ................................... */
        for (q = 0 ; q < nangles ; ++q) {
          vl_sift_pix  buf [128] ;
          vl_sift_pix rbuf [128] ;

          /* compute descriptor (if necessary) */
          if (nout > 1) {
            vl_sift_calc_keypoint_descriptor
              (filt, buf, k, angles [q]) ;
            transpose_descriptor (rbuf, buf) ;
          }

          /* make enough room for all these keypoints and more */
          if (reserved < nframes + 1) {
            reserved += 2 * nkeys ;
            frames = malloc (4 * sizeof(double) * reserved) ;
            if (nout > 1) {
              descr  = malloc (128 * sizeof(vl_uint8) * reserved) ;
            }
          }

          /* Save back with MATLAB conventions. Notice tha the input
           * image was the transpose of the actual image. */
          frames [4 * nframes + 0] = k -> y + 1 ;
          frames [4 * nframes + 1] = k -> x + 1 ;
          frames [4 * nframes + 2] = k -> sigma ;
          frames [4 * nframes + 3] = VL_PI / 2 - angles [q] ;

          if (nout > 1) {
            for (j = 0 ; j < 128 ; ++j) {
              double x = 512.0 * rbuf [j] ;
              x = (x < 255.0) ? x : 255.0 ;
              descr [128 * nframes + j] = (vl_uint8) (x) ;
            }
          }

          ++ nframes ;
        } /* next orientation */
      } /* next keypoint */
    } /* next octave */

    if (verbose) {
      printf ("siftpy: found %d keypoints\n", nframes) ;
    }

    /* ...............................................................
     *                                                       Save back
     * ............................................................ */
    Py_END_ALLOW_THREADS

    {
      int dims [2] ;

      /* create an empty array */
      dims [0] = nframes ;
      dims [1] = 4 ;
      // We are allocating new memory here because its the only way to make
      // sure that it will get free()ed when there are no more references
      out_frames = (PyArrayObject*) PyArray_FromDims(2, dims, PyArray_DOUBLE);
      memcpy((double*) out_frames->data, frames, 4 * nframes * sizeof(double));
      dims [0] = nframes ; // Numpy Array uses row format, Matlab uses column format
      dims [1] = 128 ;
      out_descr = (PyArrayObject*) PyArray_FromDims(2, dims, PyArray_UBYTE);
      memcpy((vl_uint8 *) out_descr->data, descr, 128 * nframes * sizeof(vl_uint8) );
    }

    /* cleanup */
    vl_sift_delete (filt) ;
    free(frames);
    free(descr);

  } /* end: do job */
  return Py_BuildValue("(OO)",PyArray_Return(out_frames), PyArray_Return(out_descr));
}
Example #2
0
/** @brief SIFT driver entry point
 **/
int
main(int argc, char **argv)
{
  /* algorithm parameters */
  double   edge_thresh  = -1 ;
  double   peak_thresh  = -1 ;
  double   magnif       = -1 ;
  int      O = -1, S = 3, omin = -1 ;

  vl_bool  err    = VL_ERR_OK ;
  char     err_msg [1024] ;
  int      n ;
  int      exit_code          = 0 ;
  int      verbose            = 0 ;
  vl_bool  force_output       = 0 ;
  vl_bool  force_orientations = 0 ;

  VlFileMeta out  = {1, "%.sift",  VL_PROT_ASCII, "", 0} ;
  VlFileMeta frm  = {0, "%.frame", VL_PROT_ASCII, "", 0} ;
  VlFileMeta dsc  = {0, "%.descr", VL_PROT_ASCII, "", 0} ;
  VlFileMeta met  = {0, "%.meta",  VL_PROT_ASCII, "", 0} ;
  VlFileMeta gss  = {0, "%.pgm",   VL_PROT_ASCII, "", 0} ;
  VlFileMeta ifr  = {0, "%.frame", VL_PROT_ASCII, "", 0} ;

#define ERRF(msg, arg) {                                        \
    err = VL_ERR_BAD_ARG ;                                      \
    snprintf(err_msg, sizeof(err_msg), msg, arg) ;              \
    break ;                                                     \
  }

#define ERR(msg) {                                              \
    err = VL_ERR_BAD_ARG ;                                      \
    snprintf(err_msg, sizeof(err_msg), msg) ;                   \
    break ;                                                     \
}

  /* -----------------------------------------------------------------
   *                                                     Parse options
   * -------------------------------------------------------------- */

  while (!err) {
    int ch = getopt_long(argc, argv, opts, longopts, 0) ;

    /* If there are no files passed as input, print the help and settings */
    if (ch == -1 && argc - optind == 0)
      ch = 'h';

    /* end of option list? */
    if (ch == -1) break;

    switch (ch) {

    case '?' :
      /* unkown option ............................................ */
      ERRF("Invalid option '%s'.", argv [optind - 1]) ;
      break ;

    case ':' :
      /* missing argument ......................................... */
      ERRF("Missing mandatory argument for option '%s'.",
          argv [optind - 1]) ;
      break ;

    case 'h' :
      /* --help ................................................... */
      printf (help_message, argv [0]) ;
      printf ("SIFT         filespec: `%s'\n", out.pattern) ;
      printf ("Frames       filespec: `%s'\n", frm.pattern) ;
      printf ("Descriptors  filespec: `%s'\n", dsc.pattern) ;
      printf ("Meta         filespec: `%s'\n", met.pattern) ;
      printf ("GSS          filespec: '%s'\n", gss.pattern) ;
      printf ("Read frames  filespec: '%s'\n", ifr.pattern) ;
      printf ("Version: driver %s; libvl %s\n",
              VL_XSTRINGIFY(VL_SIFT_DRIVER_VERSION),
              vl_get_version_string()) ;
      exit (0) ;
      break ;

    case 'v' :
      /* --verbose ................................................ */
      ++ verbose ;
      break ;

    case 'o' :
      /* --output  ................................................ */
      err = vl_file_meta_parse (&out, optarg) ;
      if (err)
        ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
      force_output = 1 ;
      break ;

    case opt_frames :
      /* --frames  ................................................ */
      err = vl_file_meta_parse (&frm, optarg) ;
      if (err)
        ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
      break ;

    case opt_descriptors :
      /* --descriptor ............................................. */
      err = vl_file_meta_parse (&dsc, optarg) ;
      if (err)
        ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
      break;

    case opt_meta :
      /* --meta ................................................... */
      err = vl_file_meta_parse (&met, optarg) ;
      if (err)
        ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;

      if (met.protocol != VL_PROT_ASCII)
        ERR("meta file supports only ASCII protocol") ;
      break ;

    case opt_read_frames :
      /* --read_frames ............................................ */
      err = vl_file_meta_parse (&ifr, optarg) ;
      if (err)
        ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
      break ;

    case opt_gss :
      /* --gss .................................................... */
      err = vl_file_meta_parse (&gss, optarg) ;
      if (err)
        ERRF("The arguments of '%s' is invalid.", argv [optind - 1]) ;
      break ;



    case 'O' :
      /* --octaves ............................................... */
      n = sscanf (optarg, "%d", &O) ;
      if (n == 0 || O < 0)
        ERRF("The argument of '%s' must be a non-negative integer.",
            argv [optind - 1]) ;
      break ;

    case 'S' :
      /* --levels ............................................... */
      n = sscanf (optarg, "%d", &S) ;
      if (n == 0 || S < 0)
        ERRF("The argument of '%s' must be a non-negative integer.",
            argv [optind - 1]) ;
      break ;

    case opt_first_octave :
      /* --first-octave ......................................... */
      n = sscanf (optarg, "%d", &omin) ;
      if (n == 0)
        ERRF("The argument of '%s' must be an integer.",
            argv [optind - 1]) ;
      break ;



    case opt_edge_thresh :
      /* --edge-thresh ........................................... */
      n = sscanf (optarg, "%lf", &edge_thresh) ;
      if (n == 0 || edge_thresh < 1)
        ERRF("The argument of '%s' must be not smaller than 1.",
            argv [optind - 1]) ;
      break ;

    case opt_peak_thresh :
      /* --edge-thresh ........................................... */
      n = sscanf (optarg, "%lf", &peak_thresh) ;
      if (n == 0 || peak_thresh < 0)
        ERRF("The argument of '%s' must be a non-negative float.",
            argv [optind - 1]) ;
      break ;

    case opt_magnif :
      /* --magnif  .............................................. */
      n = sscanf (optarg, "%lf", &magnif) ;
      if (n == 0 || magnif < 1)
        ERRF("The argument of '%s' must be a non-negative float.",
            argv [optind - 1]) ;
      break ;


    case opt_orientations :
      /* --orientations ......................................... */
      force_orientations = 1 ;
      break ;

    case 0 :
    default :
      /* should not get here ...................................... */
      assert (0) ;
      break ;
    }
  }

  /* check for parsing errors */
  if (err) {
    fprintf(stderr, "%s: error: %s (%d)\n",
            argv [0],
            err_msg, err) ;
    exit (1) ;
  }

  /* parse other arguments (filenames) */
  argc -= optind ;
  argv += optind ;

  /*
     if --output is not specified, specifying --frames or --descriptors
     prevent the aggregate outout file to be produced.
  */
  if (! force_output && (frm.active || dsc.active)) {
    out.active = 0 ;
  }

  if (verbose > 1) {
#define PRNFO(name,fm)                                                  \
    printf("sift: " name) ;                                             \
    printf("%3s ",  (fm).active ? "yes" : "no") ;                       \
    printf("%-6s ", vl_string_protocol_name ((fm).protocol)) ;          \
    printf("%-10s\n", (fm).pattern) ;

    PRNFO("write aggregate . ", out) ;
    PRNFO("write frames .... ", frm) ;
    PRNFO("write descriptors ", dsc) ;
    PRNFO("write meta ...... ", met) ;
    PRNFO("write GSS ....... ", gss) ;
    PRNFO("read  frames .... ", ifr) ;

    if (force_orientations)
      printf("sift: will compute orientations\n") ;
  }

  /* ------------------------------------------------------------------
   *                                         Process one image per time
   * --------------------------------------------------------------- */

  while (argc--) {

    char             basename [1024] ;
    char const      *name = *argv++ ;

    FILE            *in    = 0 ;
    vl_uint8        *data  = 0 ;
    vl_sift_pix     *fdata = 0 ;
    VlPgmImage       pim ;

    VlSiftFilt      *filt = 0 ;
    int              q, i ;
    vl_bool          first ;

    double           *ikeys = 0 ;
    int              nikeys = 0, ikeys_size = 0 ;

    /* ...............................................................
     *                                                 Determine files
     * ............................................................ */

    /* get basenmae from filename */
    q = vl_string_basename (basename, sizeof(basename), name, 1) ;

    err = (q >= sizeof(basename)) ;

    if (err) {
      snprintf(err_msg, sizeof(err_msg),
               "Basename of '%s' is too long", name);
      err = VL_ERR_OVERFLOW ;
      goto done ;
    }

    if (verbose) {
      printf ("sift: <== '%s'\n", name) ;
    }

    if (verbose > 1) {
      printf ("sift: basename is '%s'\n", basename) ;
    }

    /* open input file */
    in = fopen (name, "rb") ;
    if (!in) {
      err = VL_ERR_IO ;
      snprintf(err_msg, sizeof(err_msg),
               "Could not open '%s' for reading.", name) ;
      goto done ;
    }

    /* ...............................................................
     *                                                       Read data
     * ............................................................ */

    /* read PGM header */
    err = vl_pgm_extract_head (in, &pim) ;

    if (err) {
      switch (vl_err_no) {
      case  VL_ERR_PGM_IO :
        snprintf(err_msg, sizeof(err_msg),
                 "Cannot read from '%s'.", name) ;
        err = VL_ERR_IO ;
        break ;

      case VL_ERR_PGM_INV_HEAD :
        snprintf(err_msg, sizeof(err_msg),
                 "'%s' contains a malformed PGM header.", name) ;
        err = VL_ERR_IO ;
        goto done ;
      }
    }

    if (verbose)
      printf ("sift: image is %d by %d pixels\n",
              pim. width,
              pim. height) ;

    /* allocate buffer */
    data  = malloc(vl_pgm_get_npixels (&pim) *
                   vl_pgm_get_bpp       (&pim) * sizeof (vl_uint8)   ) ;
    fdata = malloc(vl_pgm_get_npixels (&pim) *
                   vl_pgm_get_bpp       (&pim) * sizeof (vl_sift_pix)) ;

    if (!data || !fdata) {
      err = VL_ERR_ALLOC ;
      snprintf(err_msg, sizeof(err_msg),
               "Could not allocate enough memory.") ;
      goto done ;
    }

    /* read PGM body */
    err  = vl_pgm_extract_data (in, &pim, data) ;

    if (err) {
      snprintf(err_msg, sizeof(err_msg), "PGM body malformed.") ;
      err = VL_ERR_IO ;
      goto done ;
    }

    /* convert data type */
    for (q = 0 ; q < pim.width * pim.height ; ++q)
      fdata [q] = data [q] ;

    /* ...............................................................
     *                                     Optionally source keypoints
     * ............................................................ */

#define WERR(name,op)                                           \
    if (err == VL_ERR_OVERFLOW) {                               \
      snprintf(err_msg, sizeof(err_msg),                        \
               "Output file name too long.") ;                  \
      goto done ;                                               \
    } else if (err) {                                           \
      snprintf(err_msg, sizeof(err_msg),                        \
               "Could not open '%s' for " #op, name) ;          \
      goto done ;                                               \
    }

    if (ifr.active) {

      /* open file */
      err = vl_file_meta_open (&ifr, basename, "rb") ;
      WERR(ifr.name, reading) ;

#define QERR                                                            \
      if (err ) {                                                       \
        snprintf (err_msg, sizeof(err_msg),                             \
                  "'%s' malformed", ifr.name) ;                         \
        err = VL_ERR_IO ;                                               \
        goto done ;                                                     \
      }

      while (1) {
        double x, y, s, th ;

        /* read next guy */
        err = vl_file_meta_get_double (&ifr, &x) ;
        if   (err == VL_ERR_EOF) break;
        else QERR ;
        err = vl_file_meta_get_double (&ifr, &y ) ; QERR ;
        err = vl_file_meta_get_double (&ifr, &s ) ; QERR ;
        err = vl_file_meta_get_double (&ifr, &th) ;
        if   (err == VL_ERR_EOF) break;
        else QERR ;

        /* make enough space */
        if (ikeys_size < nikeys + 1) {
          ikeys_size += 10000 ;
          ikeys       = realloc (ikeys, 4 * sizeof(double) * ikeys_size) ;
        }

        /* add the guy to the buffer */
        ikeys [4 * nikeys + 0]  = x ;
        ikeys [4 * nikeys + 1]  = y ;
        ikeys [4 * nikeys + 2]  = s ;
        ikeys [4 * nikeys + 3]  = th ;

        ++ nikeys ;
      }

      /* now order by scale */
      qsort (ikeys, nikeys, 4 * sizeof(double), korder) ;

      if (verbose) {
        printf ("sift: read %d keypoints from '%s'\n", nikeys, ifr.name) ;
      }

      /* close file */
      vl_file_meta_close (&ifr) ;
    }

    /* ...............................................................
     *                                               Open output files
     * ............................................................ */

    err = vl_file_meta_open (&out, basename, "wb") ; WERR(out.name, writing) ;
    err = vl_file_meta_open (&dsc, basename, "wb") ; WERR(dsc.name, writing) ;
    err = vl_file_meta_open (&frm, basename, "wb") ; WERR(frm.name, writing) ;
    err = vl_file_meta_open (&met, basename, "wb") ; WERR(met.name, writing) ;

    if (verbose > 1) {
      if (out.active) printf("sift: writing all ....... to . '%s'\n", out.name);
      if (frm.active) printf("sift: writing frames .... to . '%s'\n", frm.name);
      if (dsc.active) printf("sift: writing descriptors to . '%s'\n", dsc.name);
      if (met.active) printf("sift: writign meta ...... to . '%s'\n", met.name);
    }

    /* ...............................................................
     *                                                     Make filter
     * ............................................................ */

    filt = vl_sift_new (pim.width, pim.height, O, S, omin) ;

    if (edge_thresh >= 0) vl_sift_set_edge_thresh (filt, edge_thresh) ;
    if (peak_thresh >= 0) vl_sift_set_peak_thresh (filt, peak_thresh) ;
    if (magnif      >= 0) vl_sift_set_magnif      (filt, magnif) ;

    if (!filt) {
      snprintf (err_msg, sizeof(err_msg),
                "Could not create SIFT filter.") ;
      err = VL_ERR_ALLOC ;
      goto done ;
    }

    if (verbose > 1) {
      printf ("sift: filter settings:\n") ;
      printf ("sift:   octaves      (O)     = %d\n",
              vl_sift_get_noctaves     (filt)) ;
      printf ("sift:   levels       (S)     = %d\n",
              vl_sift_get_nlevels      (filt)) ;
      printf ("sift:   first octave (o_min) = %d\n",
              vl_sift_get_octave_first (filt)) ;
      printf ("sift:   edge thresh           = %g\n",
              vl_sift_get_edge_thresh  (filt)) ;
      printf ("sift:   peak thresh           = %g\n",
              vl_sift_get_peak_thresh  (filt)) ;
      printf ("sift:   magnif                = %g\n",
              vl_sift_get_magnif       (filt)) ;
      printf ("sift: will source frames? %s\n",
              ikeys ? "yes" : "no") ;
      printf ("sift: will force orientations? %s\n",
              force_orientations ? "yes" : "no") ;
    }

    /* ...............................................................
     *                                             Process each octave
     * ............................................................ */
    i     = 0 ;
    first = 1 ;
    while (1) {
      VlSiftKeypoint const *keys ;
      int                   nkeys ;

      /* calculate the GSS for the next octave .................... */
      if (first) {
        first = 0 ;
        err = vl_sift_process_first_octave (filt, fdata) ;
      } else {
        err = vl_sift_process_next_octave  (filt) ;
      }

      if (err) {
        err = VL_ERR_OK ;
        break ;
      }

      if (verbose > 1) {
        printf("sift: GSS octave %d computed\n",
               vl_sift_get_octave_index (filt));
      }

      /* optionally save GSS */
      if (gss.active) {
        err = save_gss (filt, &gss, basename, verbose) ;
        if (err) {
          snprintf (err_msg, sizeof(err_msg),
                    "Could not write GSS to PGM file.") ;
          goto done ;
        }
      }

      /* run detector ............................................. */
      if (ikeys == 0) {
        vl_sift_detect (filt) ;

        keys  = vl_sift_get_keypoints     (filt) ;
        nkeys = vl_sift_get_nkeypoints (filt) ;
        i     = 0 ;

        if (verbose > 1) {
          printf ("sift: detected %d (unoriented) keypoints\n", nkeys) ;
        }
      } else {
        nkeys = nikeys ;
      }

      /* for each keypoint ........................................ */
      for (; i < nkeys ; ++i) {
        double                angles [4] ;
        int                   nangles ;
        VlSiftKeypoint        ik ;
        VlSiftKeypoint const *k ;

        /* obtain keypoint orientations ........................... */
        if (ikeys) {
          vl_sift_keypoint_init (filt, &ik,
                                 ikeys [4 * i + 0],
                                 ikeys [4 * i + 1],
                                 ikeys [4 * i + 2]) ;

          if (ik.o != vl_sift_get_octave_index (filt)) {
            break ;
          }

          k          = &ik ;

          /* optionally compute orientations too */
          if (force_orientations) {
            nangles = vl_sift_calc_keypoint_orientations
              (filt, angles, k) ;
          } else {
            angles [0] = ikeys [4 * i + 3] ;
            nangles    = 1 ;
          }
        } else {
          k = keys + i ;
          nangles = vl_sift_calc_keypoint_orientations
            (filt, angles, k) ;
        }

        /* for each orientation ................................... */
        for (q = 0 ; q < nangles ; ++q) {
          vl_sift_pix descr [128] ;

          /* compute descriptor (if necessary) */
          if (out.active || dsc.active) {
            vl_sift_calc_keypoint_descriptor
              (filt, descr, k, angles [q]) ;
          }

          if (out.active) {
            int l ;
            vl_file_meta_put_double (&out, k -> x     ) ;
            vl_file_meta_put_double (&out, k -> y     ) ;
            vl_file_meta_put_double (&out, k -> sigma ) ;
            vl_file_meta_put_double (&out, angles [q] ) ;
            for (l = 0 ; l < 128 ; ++l) {
              vl_file_meta_put_uint8 (&out, (vl_uint8) (512.0 * descr [l])) ;
            }
            if (out.protocol == VL_PROT_ASCII) fprintf(out.file, "\n") ;
          }

          if (frm.active) {
            vl_file_meta_put_double (&frm, k -> x     ) ;
            vl_file_meta_put_double (&frm, k -> y     ) ;
            vl_file_meta_put_double (&frm, k -> sigma ) ;
            vl_file_meta_put_double (&frm, angles [q] ) ;
            if (frm.protocol == VL_PROT_ASCII) fprintf(frm.file, "\n") ;
          }

          if (dsc.active) {
            int l ;
            for (l = 0 ; l < 128 ; ++l) {
              double x = 512.0 * descr[l] ;
              x = (x < 255.0) ? x : 255.0 ;
              vl_file_meta_put_uint8 (&dsc, (vl_uint8) (x)) ;
            }
            if (dsc.protocol == VL_PROT_ASCII) fprintf(dsc.file, "\n") ;
          }
        }
      }
    }

    /* ...............................................................
     *                                                       Finish up
     * ............................................................ */

    if (met.active) {
      fprintf(met.file, "<sift\n") ;
      fprintf(met.file, "  input       = '%s'\n", name) ;
      if (dsc.active) {
        fprintf(met.file, "  descriptors = '%s'\n", dsc.name) ;
      }
      if (frm.active) {
        fprintf(met.file,"  frames      = '%s'\n", frm.name) ;
      }
      fprintf(met.file, ">\n") ;
    }

  done :
    /* release input keys buffer */
    if (ikeys) {
      free (ikeys) ;
      ikeys_size = nikeys = 0 ;
      ikeys = 0 ;
    }

    /* release filter */
    if (filt) {
      vl_sift_delete (filt) ;
      filt = 0 ;
    }

    /* release image data */
    if (fdata) {
      free (fdata) ;
      fdata = 0 ;
    }

    /* release image data */
    if (data) {
      free (data) ;
      data = 0 ;
    }

    /* close files */
    if (in) {
      fclose (in) ;
      in = 0 ;
    }

    vl_file_meta_close (&out) ;
    vl_file_meta_close (&frm) ;
    vl_file_meta_close (&dsc) ;
    vl_file_meta_close (&met) ;
    vl_file_meta_close (&gss) ;
    vl_file_meta_close (&ifr) ;

    /* if bad print error message */
    if (err) {
      fprintf
        (stderr,
         "sift: err: %s (%d)\n",
         err_msg,
         err) ;
      exit_code = 1 ;
    }
  }

  /* quit */
  return exit_code ;
}
Example #3
0
void
mexFunction(int nout, mxArray *out[],
            int nin, const mxArray *in[])
{
  enum {IN_I=0,IN_END} ;
  enum {OUT_FRAMES=0, OUT_DESCRIPTORS} ;

  int                verbose = 0 ;
  int                opt ;
  int                next = IN_END ;
  mxArray const     *optarg ;

  vl_sift_pix const *data ;
  int                M, N ;

  int                O     = - 1 ;
  int                S     =   3 ;
  int                o_min =   0 ;

  double             edge_thresh = -1 ;
  double             peak_thresh = -1 ;
  double             norm_thresh = -1 ;
  double             magnif      = -1 ;
  double             window_size = -1 ;

  mxArray           *ikeys_array = 0 ;
  double            *ikeys = 0 ;
  int                nikeys = -1 ;
  vl_bool            force_orientations = 0 ;
  vl_bool            floatDescriptors = 0 ;

  VL_USE_MATLAB_ENV ;

  /* -----------------------------------------------------------------
   *                                               Check the arguments
   * -------------------------------------------------------------- */

  if (nin < 1) {
    mexErrMsgTxt("One argument required.") ;
  } else if (nout > 2) {
    mexErrMsgTxt("Too many output arguments.");
  }

  if (mxGetNumberOfDimensions (in[IN_I]) != 2              ||
      mxGetClassID            (in[IN_I]) != mxSINGLE_CLASS  ) {
    mexErrMsgTxt("I must be a matrix of class SINGLE") ;
  }

  data = (vl_sift_pix*) mxGetData (in[IN_I]) ;
  M    = mxGetM (in[IN_I]) ;
  N    = mxGetN (in[IN_I]) ;

  while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) {
    switch (opt) {

    case opt_verbose :
      ++ verbose ;
      break ;

    case opt_octaves :
      if (!vlmxIsPlainScalar(optarg) || (O = (int) *mxGetPr(optarg)) < 0) {
        mexErrMsgTxt("'Octaves' must be a positive integer.") ;
      }
      break ;

    case opt_levels :
      if (! vlmxIsPlainScalar(optarg) || (S = (int) *mxGetPr(optarg)) < 1) {
        mexErrMsgTxt("'Levels' must be a positive integer.") ;
      }
      break ;

    case opt_first_octave :
      if (!vlmxIsPlainScalar(optarg)) {
        mexErrMsgTxt("'FirstOctave' must be an integer") ;
      }
      o_min = (int) *mxGetPr(optarg) ;
      break ;

    case opt_edge_thresh :
      if (!vlmxIsPlainScalar(optarg) || (edge_thresh = *mxGetPr(optarg)) < 1) {
        mexErrMsgTxt("'EdgeThresh' must be not smaller than 1.") ;
      }
      break ;

    case opt_peak_thresh :
      if (!vlmxIsPlainScalar(optarg) || (peak_thresh = *mxGetPr(optarg)) < 0) {
        mexErrMsgTxt("'PeakThresh' must be a non-negative real.") ;
      }
      break ;

    case opt_norm_thresh :
      if (!vlmxIsPlainScalar(optarg) || (norm_thresh = *mxGetPr(optarg)) < 0) {
        mexErrMsgTxt("'NormThresh' must be a non-negative real.") ;
      }
      break ;

    case opt_magnif :
      if (!vlmxIsPlainScalar(optarg) || (magnif = *mxGetPr(optarg)) < 0) {
        mexErrMsgTxt("'Magnif' must be a non-negative real.") ;
      }
      break ;

    case opt_window_size :
      if (!vlmxIsPlainScalar(optarg) || (window_size = *mxGetPr(optarg)) < 0) {
        mexErrMsgTxt("'WindowSize' must be a non-negative real.") ;
      }
      break ;

    case opt_frames :
      if (!vlmxIsMatrix(optarg, 4, -1)) {
        mexErrMsgTxt("'Frames' must be a 4 x N matrix.x") ;
      }
      ikeys_array = mxDuplicateArray (optarg) ;
      nikeys      = mxGetN (optarg) ;
      ikeys       = mxGetPr (ikeys_array) ;
      if (! check_sorted (ikeys, nikeys)) {
        qsort (ikeys, nikeys, 4 * sizeof(double), korder) ;
      }
      break ;

    case opt_orientations :
      force_orientations = 1 ;
      break ;

    case opt_float_descriptors :
      floatDescriptors = 1 ;
      break ;

    default :
      abort() ;
    }
  }

  /* -----------------------------------------------------------------
   *                                                            Do job
   * -------------------------------------------------------------- */
  {
    VlSiftFilt        *filt ;
    vl_bool            first ;
    double            *frames = 0 ;
    void              *descr  = 0 ;
    int                nframes = 0, reserved = 0, i,j,q ;

    /* create a filter to process the image */
    filt = vl_sift_new (M, N, O, S, o_min) ;

    if (peak_thresh >= 0) vl_sift_set_peak_thresh (filt, peak_thresh) ;
    if (edge_thresh >= 0) vl_sift_set_edge_thresh (filt, edge_thresh) ;
    if (norm_thresh >= 0) vl_sift_set_norm_thresh (filt, norm_thresh) ;
    if (magnif      >= 0) vl_sift_set_magnif      (filt, magnif) ;
    if (window_size >= 0) vl_sift_set_window_size (filt, window_size) ;

    if (verbose) {
      mexPrintf("vl_sift: filter settings:\n") ;
      mexPrintf("vl_sift:   octaves      (O)      = %d\n",
                vl_sift_get_noctaves      (filt)) ;
      mexPrintf("vl_sift:   levels       (S)      = %d\n",
                vl_sift_get_nlevels       (filt)) ;
      mexPrintf("vl_sift:   first octave (o_min)  = %d\n",
                vl_sift_get_octave_first  (filt)) ;
      mexPrintf("vl_sift:   edge thresh           = %g\n",
                vl_sift_get_edge_thresh   (filt)) ;
      mexPrintf("vl_sift:   peak thresh           = %g\n",
                vl_sift_get_peak_thresh   (filt)) ;
      mexPrintf("vl_sift:   norm thresh           = %g\n",
                vl_sift_get_norm_thresh   (filt)) ;
      mexPrintf("vl_sift:   window size           = %g\n",
                vl_sift_get_window_size   (filt)) ;
      mexPrintf("vl_sift:   float descriptor      = %d\n",
                floatDescriptors) ;

      mexPrintf((nikeys >= 0) ?
                "vl_sift: will source frames? yes (%d read)\n" :
                "vl_sift: will source frames? no\n", nikeys) ;
      mexPrintf("vl_sift: will force orientations? %s\n",
                force_orientations ? "yes" : "no") ;
    }

    /* ...............................................................
     *                                             Process each octave
     * ............................................................ */
    i     = 0 ;
    first = 1 ;
    while (1) {
      int                   err ;
      VlSiftKeypoint const* keys  = 0 ;
      int                   nkeys = 0 ;

      if (verbose) {
        mexPrintf ("vl_sift: processing octave %d\n",
                   vl_sift_get_octave_index (filt)) ;
      }

      /* Calculate the GSS for the next octave .................... */
      if (first) {
        err   = vl_sift_process_first_octave (filt, data) ;
        first = 0 ;
      } else {
        err   = vl_sift_process_next_octave  (filt) ;
      }

      if (err) break ;

      if (verbose > 1) {
        mexPrintf("vl_sift: GSS octave %d computed\n",
                  vl_sift_get_octave_index (filt));
      }

      /* Run detector ............................................. */
      if (nikeys < 0) {
        vl_sift_detect (filt) ;

        keys  = vl_sift_get_keypoints  (filt) ;
        nkeys = vl_sift_get_nkeypoints (filt) ;
        i     = 0 ;

        if (verbose > 1) {
          printf ("vl_sift: detected %d (unoriented) keypoints\n", nkeys) ;
        }
      } else {
        nkeys = nikeys ;
      }

      /* For each keypoint ........................................ */
      for (; i < nkeys ; ++i) {
        double                angles [4] ;
        int                   nangles ;
        VlSiftKeypoint        ik ;
        VlSiftKeypoint const *k ;

        /* Obtain keypoint orientations ........................... */
        if (nikeys >= 0) {
          vl_sift_keypoint_init (filt, &ik,
                                 ikeys [4 * i + 1] - 1,
                                 ikeys [4 * i + 0] - 1,
                                 ikeys [4 * i + 2]) ;

          if (ik.o != vl_sift_get_octave_index (filt)) {
            break ;
          }

          k = &ik ;

          /* optionally compute orientations too */
          if (force_orientations) {
            nangles = vl_sift_calc_keypoint_orientations
              (filt, angles, k) ;
          } else {
            angles [0] = VL_PI / 2 - ikeys [4 * i + 3] ;
            nangles    = 1 ;
          }
        } else {
          k = keys + i ;
          nangles = vl_sift_calc_keypoint_orientations
            (filt, angles, k) ;
        }

        /* For each orientation ................................... */
        for (q = 0 ; q < nangles ; ++q) {
          vl_sift_pix  buf [128] ;
          vl_sift_pix rbuf [128] ;

          /* compute descriptor (if necessary) */
          if (nout > 1) {
            vl_sift_calc_keypoint_descriptor (filt, buf, k, angles [q]) ;
            transpose_descriptor (rbuf, buf) ;
          }

          /* make enough room for all these keypoints and more */
          if (reserved < nframes + 1) {
            reserved += 2 * nkeys ;
            frames = mxRealloc (frames, 4 * sizeof(double) * reserved) ;
            if (nout > 1) {
              if (! floatDescriptors) {
                descr  = mxRealloc (descr,  128 * sizeof(vl_uint8) * reserved) ;
              } else {
                descr  = mxRealloc (descr,  128 * sizeof(float) * reserved) ;
              }
            }
          }

          /* Save back with MATLAB conventions. Notice tha the input
           * image was the transpose of the actual image. */
          frames [4 * nframes + 0] = k -> y + 1 ;
          frames [4 * nframes + 1] = k -> x + 1 ;
          frames [4 * nframes + 2] = k -> sigma ;
          frames [4 * nframes + 3] = VL_PI / 2 - angles [q] ;

          if (nout > 1) {
            if (! floatDescriptors) {
              for (j = 0 ; j < 128 ; ++j) {
                float x = 512.0F * rbuf [j] ;
                x = (x < 255.0F) ? x : 255.0F ;
                ((vl_uint8*)descr) [128 * nframes + j] = (vl_uint8) x ;
              }
            } else {
              for (j = 0 ; j < 128 ; ++j) {
                float x = 512.0F * rbuf [j] ;
                ((float*)descr) [128 * nframes + j] = x ;
              }
            }
          }

          ++ nframes ;
        } /* next orientation */
      } /* next keypoint */
    } /* next octave */

    if (verbose) {
      mexPrintf ("vl_sift: found %d keypoints\n", nframes) ;
    }

    /* ...............................................................
     *                                                       Save back
     * ............................................................ */

    {
      mwSize dims [2] ;

      /* create an empty array */
      dims [0] = 0 ;
      dims [1] = 0 ;
      out[OUT_FRAMES] = mxCreateNumericArray
        (2, dims, mxDOUBLE_CLASS, mxREAL) ;

      /* set array content to be the frames buffer */
      dims [0] = 4 ;
      dims [1] = nframes ;
      mxSetPr         (out[OUT_FRAMES], frames) ;
      mxSetDimensions (out[OUT_FRAMES], dims, 2) ;

      if (nout > 1) {

        /* create an empty array */
        dims [0] = 0 ;
        dims [1] = 0 ;
        out[OUT_DESCRIPTORS]= mxCreateNumericArray
          (2, dims,
           floatDescriptors ? mxSINGLE_CLASS : mxUINT8_CLASS,
           mxREAL) ;

        /* set array content to be the descriptors buffer */
        dims [0] = 128 ;
        dims [1] = nframes ;
        mxSetData       (out[OUT_DESCRIPTORS], descr) ;
        mxSetDimensions (out[OUT_DESCRIPTORS], dims, 2) ;
      }
    }

    /* cleanup */
    vl_sift_delete (filt) ;

    if (ikeys_array)
      mxDestroyArray(ikeys_array) ;

  } /* end: do job */
}
void
mexFunction(int nout, mxArray *out[],
            int nin, const mxArray *in[])
{

  enum {IN_I=0,IN_END} ;
  enum {OUT_FRAMES=0, OUT_DESCRIPTORS} ;

  int                verbose = 0 ;
  int                opt ;
  int                next = IN_END ;
  mxArray const     *optarg ;

  vl_sift_pix const *data ;
  int                M, N ;

  int                O     = - 1 ;
  int                S     =   3 ;
  int                o_min =   0 ;

  double             edge_thresh = -1 ;
  double             peak_thresh = -1 ;
  double             norm_thresh = -1 ;
  double             magnif      = -1 ;
  double             window_size = -1 ;

  mxArray           *ikeys_array = 0 ;
  double            *ikeys = 0 ;
  int                nikeys = -1 ;
  vl_bool            force_orientations = 0 ;
  vl_bool            floatDescriptors = 0 ;

  VL_USE_MATLAB_ENV ;

  /* -----------------------------------------------------------------
   *                                               Check the arguments
   * -------------------------------------------------------------- */

  if (nin < 1) {
    mexErrMsgTxt("One argument required.") ;
  } else if (nout > 2) {
    mexErrMsgTxt("Too many output arguments.");
  }

  if (mxGetNumberOfDimensions (in[IN_I]) != 2              ||
      mxGetClassID            (in[IN_I]) != mxSINGLE_CLASS  ) {
    mexErrMsgTxt("I must be a matrix of class SINGLE") ;
  }

  data = (vl_sift_pix*) mxGetData (in[IN_I]) ;
  M    = mxGetM (in[IN_I]) ;
  N    = mxGetN (in[IN_I]) ;

  while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) {
    switch (opt) {

    case opt_verbose :
      ++ verbose ;
      break ;

    case opt_frames :
      if (!vlmxIsMatrix(optarg, 4, -1)) {
        mexErrMsgTxt("'Frames' must be a 4 x N matrix.") ;
      }
      ikeys_array = mxDuplicateArray (optarg) ;
      nikeys      = mxGetN (optarg) ;
      ikeys       = mxGetPr (ikeys_array) ;
      if (! check_sorted (ikeys, nikeys)) {
        qsort (ikeys, nikeys, 4 * sizeof(double), korder) ;
      }
      break ;

    default :
		mexPrintf("F**k you!");
      abort() ;
    }
  }
  
  /* -----------------------------------------------------------------
   *                                                            Do job
   * -------------------------------------------------------------- */
  {
    VlSiftFilt        *filt ;
    vl_bool            first ;
    double            *frames = 0 ;
    void              *descr  = 0 ;
    int                nframes = 0, reserved = 0, i,j,q ;

    /* create a filter to process the image */
    filt = vl_sift_new (M, N, O, S, o_min) ;

	//mexPrintf("%f %f %f \n%f %f %f %f %f\n",(float)O,(float)S,(float)o_min,(float)peak_thresh
	//	,(float)edge_thresh,(float)norm_thresh,(float)magnif,(float)window_size);


    /* ...............................................................
     *                                             Process each octave
     * ............................................................ */
    i     = 0 ;
    first = 1 ;
    while (first == 1) {
      int                   err ;
      VlSiftKeypoint const *keys  = 0 ;
      int                   nkeys = 0 ;


        err   = vl_sift_process_first_octave (filt, data) ;
        first = 0 ;

      if (err) break ;

      /* Run detector ............................................. */
        nkeys = nikeys ;

	  //mexPrintf("Zhu: entering sweeping nkeys, nkeys = %d, i = %d \n", nkeys, i);

      /* For each keypoint ........................................ */
		for (; i < nkeys ; ++i) {
			int h;
			vl_sift_pix  buf[128];
			vl_sift_pix rbuf[128];
        double                angle;
        VlSiftKeypoint        ik ;
        VlSiftKeypoint const *k ;

        /* Obtain keypoint orientations ........................... */
          vl_sift_keypoint_init (filt, &ik,
                                 ikeys [4 * i + 1] - 1,
                                 ikeys [4 * i + 0] - 1,
                                 ikeys [4 * i + 2]) ;
		  //mexPrintf("ikeys: [%f, %f, %f]\n", (float)(ikeys [4 * i + 1] - 1), (float)(ikeys [4 * i + 0] - 1), (float)(ikeys [4 * i + 2]) );

          k = &ik ;

          /* optionally compute orientations too */
            angle = VL_PI / 2 - ikeys [4 * i + 3] ;
			q = 0;

		  
		  /* compute descriptor (if necessary) */
		  //int h;
		  //mexPrintf("M = %d, N = %d.\n",M,N);
		  //for (h = 0; h < 300; h++) 
		  //{
			//  mexPrintf("%f ",data[h]);
			//  if (h % 8 == 7) mexPrintf("\n");
		  //}
          if (nout > 1) {
			  //mexPrintf("angles = %f, x = %f(%d), y = %f(%d), s = %f(%d), o = %d, sigma = %f.\n buf = [", 
				  //angle,k->x,k->ix,k->y,k->iy,k->s,k->is,k->o,k->sigma);
			  vl_sift_calc_keypoint_descriptor (filt, buf, k, angle) ;
			  //for (h = 0; h < 128; h++) 
			  //{
				//  mexPrintf("%f ",(float)buf[h]);
				//  if (h % 8 == 7) mexPrintf("\n");
			  //}
			  //mexPrintf("...].\nrbuf = [");
			  transpose_descriptor (rbuf, buf) ;
			  //for (h = 0; h < 128; h++) 
			  //{
				//  mexPrintf("%f ",(float)rbuf[h]);
				//  if (h % 8 == 7) mexPrintf("\n");
			  //}
			  //mexPrintf("...].\n");
          }

          /* make enough room for all these keypoints and more */
          if (reserved < nframes + 1) {
            reserved += 2 * nkeys ;
            frames = mxRealloc (frames, 4 * sizeof(double) * reserved) ;
            if (nout > 1) {
              if (! floatDescriptors) {
                descr  = mxRealloc (descr,  128 * sizeof(vl_uint8) * reserved) ;
              } else {
                descr  = mxRealloc (descr,  128 * sizeof(float) * reserved) ;
              }
            }
          }

          /* Save back with MATLAB conventions. Notice tha the input
           * image was the transpose of the actual image. */
          frames [4 * nframes + 0] = k -> y + 1 ;
          frames [4 * nframes + 1] = k -> x + 1 ;
          frames [4 * nframes + 2] = k -> sigma ;
          frames [4 * nframes + 3] = VL_PI / 2 - angle;

		  //mexPrintf("Zhu: %d\n", nframes);
          if (nout > 1) {
            if (! floatDescriptors) {
              for (j = 0 ; j < 128 ; ++j) {
                float x = 512.0F * rbuf [j] ;
                x = (x < 255.0F) ? x : 255.0F ;
                ((vl_uint8*)descr) [128 * nframes + j] = (vl_uint8) x ;
              }
            } else {
              for (j = 0 ; j < 128 ; ++j) {
                float x = 512.0F * rbuf [j] ;
                ((float*)descr) [128 * nframes + j] = x ;
              }
            }
          }

          ++ nframes ;
         /* next orientation */
      } /* next keypoint */
	  //break;
	  //mexPrintf("Zhu: skip subsequent octave\n");
    } /* next octave */

	//mexPrintf("nframes_tot = %d\n",nframes);

    /* ...............................................................
     *                                                       Save back
     * ............................................................ */

    {
      mwSize dims [2] ;

      /* create an empty array */
      dims [0] = 0 ;
      dims [1] = 0 ;
      out[OUT_FRAMES] = mxCreateNumericArray
        (2, dims, mxDOUBLE_CLASS, mxREAL) ;

      /* set array content to be the frames buffer */
      dims [0] = 4 ;
      dims [1] = nframes ;
      mxSetPr         (out[OUT_FRAMES], frames) ;
      mxSetDimensions (out[OUT_FRAMES], dims, 2) ;

      if (nout > 1) {

        /* create an empty array */
        dims [0] = 0 ;
        dims [1] = 0 ;
        out[OUT_DESCRIPTORS]= mxCreateNumericArray
          (2, dims,
           floatDescriptors ? mxSINGLE_CLASS : mxUINT8_CLASS,
           mxREAL) ;

        /* set array content to be the descriptors buffer */
        dims [0] = 128 ;
        dims [1] = nframes ;
        mxSetData       (out[OUT_DESCRIPTORS], descr) ;
        mxSetDimensions (out[OUT_DESCRIPTORS], dims, 2) ;
      }
    }

    /* cleanup */
    vl_sift_delete (filt) ;

    if (ikeys_array)
      mxDestroyArray(ikeys_array) ;

  } /* end: do job */
}