示例#1
0
/* driver */
void
mexFunction(int nout, mxArray *out[],
            int nin, const mxArray *in[])
{
  enum {
    MANIP_STATE,
    RUN_GENERATOR
  } mode ;

  VlRand * rand ;

  VL_USE_MATLAB_ENV ;

  rand = vl_get_rand() ;

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

  if (nout > 1) {
    vlmxError(vlmxErrTooManyInputArguments, NULL) ;
  }

  if (nin > 0 && ! mxIsNumeric(in[0])) {
    mode = MANIP_STATE ;
  } else {
    mode = RUN_GENERATOR ;
  }

  switch (mode) {
  case RUN_GENERATOR:
    {
      enum { maxNumDimensions = 30 } ;
      vl_size numDimensions = 2, n ;
      vl_uindex k ;
      mwSize dimensions [maxNumDimensions] = {1, 1} ;
      double * x ;

      if (nin > 1) {
        /* TWISTER(N1 N2 ...) style */
        if (nin >= maxNumDimensions) {
          vlmxError(vlmxErrTooManyInputArguments,
                    "Too many dimensions specified.") ;
        }
        for (k = 0 ; k < (unsigned)nin ; ++k) {
          if (! vlmxIsPlainScalar(in[k])) {
            vlmxError(vlmxErrInvalidArgument,
                     "The %d-th argument is not a plain scalar.", k + 1) ;
          }
          if (mxGetScalar(in[k]) < 0) {
            vlmxError(vlmxErrInvalidArgument,
                      "The %d-th argument is negative.", k + 1) ;
          }
          dimensions[k] = mxGetScalar(in[k]) ;
        }
        numDimensions = k ;

      } else if (nin == 1) {
        /* TWISTER([N1 N2 ...]) style */
        if (! vlmxIsPlainVector(in[0], -1)) {
          vlmxError(vlmxErrInvalidArgument,
                   "The argument is not a plain vector.") ;
        }

        x = mxGetPr(in[0]) ;
        n = mxGetNumberOfElements(in[0]) ;
        numDimensions = VL_MAX(2, n) ;

        if (numDimensions > maxNumDimensions) {
          vlmxError(vlmxErrInvalidArgument,
                   "Too many dimensions specified.") ;
        }

        if (n == 1) {
          if (*x < 0) {
            vlmxError(vlmxErrInvalidArgument,
                      "The specified dimension is negative.") ;
          }
          dimensions[0] = dimensions[1] = *x ;
        } else {
          for (k = 0 ; k < n ; ++k) {
            if (x[k] < 0) {
              vlmxError(vlmxErrInvalidArgument,
                        "One of the specified dimensions is negative.") ;
            }
            dimensions[k] = x[k] ;
          }
        }
      }

      out[0] = mxCreateNumericArray (numDimensions, dimensions, mxDOUBLE_CLASS, mxREAL) ;
      n = mxGetNumberOfElements (out[0]) ;
      x = mxGetPr (out[0]) ;
      for (k = 0 ; k < n ; ++k) {
        x[k] = vl_rand_res53(rand) ;
      }
    }
    break ;

  case MANIP_STATE:
    {
      enum { buff_size = 32 } ;
      char buff [buff_size] ;

      /* check for 'state' string */
      if (! vlmxIsString(in[0], -1)                 ||
          mxGetString(in[0], buff, buff_size)       ||
          vl_string_casei_cmp ("state", buff) != 0   ) {
        vlmxError(vlmxErrInvalidArgument, NULL) ;
      }

      /* TWISTER('state') */
      if (nin == 1) {
        vl_uindex i ;
        vl_uint32 * data ;
        out[0] = mxCreateNumericMatrix (625, 1, mxUINT32_CLASS, mxREAL) ;
        data = mxGetData(out[0]) ;
        for (i = 0 ; i < 624 ; ++i) data[i] = rand->mt[i] ;
        data[624] = (vl_uint32) rand->mti ;
      } else {
        if (vlmxIsPlainScalar(in[1])) {
          /* TWISTER('state', X) */
          vl_uint32 x = (vl_uint32) mxGetScalar(in[1]) ;
          vl_rand_seed (rand, x) ;
        } else if (mxIsNumeric(in[1])                                &&
                   mxGetClassID(in[1]) == mxUINT32_CLASS             &&
                   mxGetNumberOfElements(in[1]) == 624+1             &&
                   ((vl_uint32 const*)mxGetData(in[1]))[624] <= 624  ) {
          /* TWISTER('state', STATE) */
          vl_uindex i ;
          vl_uint32 * data = mxGetData(in[1]) ;
          for (i = 0 ; i < 624 ; ++i) rand->mt[i] = data[i] ;
          rand->mti = data [624] ;
        } else if (mxIsNumeric(in[1])                    &&
                   mxGetClassID(in[1]) == mxDOUBLE_CLASS &&
                   mxGetNumberOfElements(in[1]) <= 624) {
          /* TWISTER('state', KEY) */
          vl_uint32 key [624] ;
          double const * x = mxGetPr(in[1]) ;
          vl_size n = mxGetNumberOfElements(in[1]) ;
          vl_uindex k ;
          for (k = 0 ; k < n ; ++k) {
            key [k] = x [k] ;
          }
          vl_rand_seed_by_array (rand, key, n) ;
        }
      }
    }
    break ;

  default:
    abort() ;
  }
}
示例#2
0
void
mexFunction(int nout, mxArray *out[],
            int nin, const mxArray *in[])
{
  vl_size M, N ;
  enum {IN_I = 0, IN_PARAM, IN_END} ;
  enum {OUT_DT = 0, OUT_INDEXES} ;
  vl_uindex * indexes = NULL ;
  mxClassID classId ;
  double const defaultParam [] = {1.0, 0.0, 1.0, 0.0} ;
  double const * param = defaultParam ;

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

  if (nin < 1) {
    vlmxError(vlmxErrNotEnoughInputArguments, NULL) ;
  }
  if (nin > 2) {
    vlmxError(vlmxErrTooManyInputArguments, NULL) ;
  }
  if (nout > 2) {
    vlmxError(vlmxErrTooManyOutputArguments, NULL) ;
  }
  classId = mxGetClassID(IN(I)) ;
  if (! vlmxIsMatrix(IN(I), -1, -1) ||
      (classId != mxSINGLE_CLASS && classId != mxDOUBLE_CLASS)) {
    vlmxError(vlmxErrInvalidArgument,
             "I is not a SINGLE or DOUBLE matrix.") ;
  }
  if (nin == 2) {
    if (! vlmxIsPlainVector(IN(PARAM), 4)) {
      vlmxError(vlmxErrInvalidArgument,
               "PARAM is not a 4-dimensional vector.") ;
    }
    param = mxGetPr (IN(PARAM)) ;
    if (param[0] < 0.0 ||
        param[2] < 0.0) {
      vlmxError(vlmxErrInvalidArgument,
                "Either PARAM[0] or PARAM[2] is negative.") ;
    }
  }

  M = mxGetM (IN(I)) ;
  N = mxGetN (IN(I)) ;

  OUT(DT) = mxCreateNumericMatrix (M, N, classId, mxREAL) ;
  if (nout > 1) {
    vl_uindex i ;
    OUT(INDEXES) = mxCreateDoubleMatrix (M, N, mxREAL) ;
    indexes = mxMalloc(sizeof(vl_uindex) * M * N) ;
    for (i = 0 ; i < M * N ; ++i) indexes[i] = i + 1 ;
  }

  /* -----------------------------------------------------------------
   *                                                        Do the job
   * -------------------------------------------------------------- */

  switch (classId) {
    case mxSINGLE_CLASS:
      vl_image_distance_transform_f((float const*)mxGetData(IN(I)),
                                    M, N,
                                    1, M,
                                    (float*)mxGetPr(OUT(DT)),
                                    indexes,
                                    param[2],
                                    param[3]) ;

      vl_image_distance_transform_f((float*)mxGetPr(OUT(DT)),
                                    N, M,
                                    M, 1,
                                    (float*)mxGetPr(OUT(DT)),
                                    indexes,
                                    param[0],
                                    param[1]) ;
      break ;

    case mxDOUBLE_CLASS:
      vl_image_distance_transform_d((double const*)mxGetData(IN(I)),
                                    M, N,
                                    1, M,
                                    (double*)mxGetPr(OUT(DT)),
                                    indexes,
                                    param[2],
                                    param[3]) ;

      vl_image_distance_transform_d((double*)mxGetPr(OUT(DT)),
                                    N, M,
                                    M, 1,
                                    (double*)mxGetPr(OUT(DT)),
                                    indexes,
                                    param[0],
                                    param[1]) ;
      break;

    default:
      abort() ;
  }

  if (indexes) {
    vl_uindex i ;
    double * pt = mxGetPr(OUT(INDEXES)) ;
    for (i = 0 ; i < M * N ; ++i) pt[i] = indexes[i] ;
    mxFree(indexes) ;
  }
}
void
mexFunction(int nout, mxArray *out[],
            int nin, const mxArray *in[])
{
  enum { X=0,Y,I,iwXp,iwYp } ;
  enum { wI=0, wIx, wIy } ;

  int M, N, Mp, Np, ip, jp ;
  double
    *X_pt,
    *Y_pt,
    *I_pt,
    *iwXp_pt,
    *iwYp_pt,
    *wI_pt,
    *wIx_pt   = 0,
    *wIy_pt   = 0 ;

  double Xmin, Xmax, Ymin, Ymax ;
  const double NaN = mxGetNaN() ;

  /* -----------------------------------------------------------------
   *                                               Check the arguments
   * -------------------------------------------------------------- */
  if (nin < 5) {
    vlmxError (vlmxErrNotEnoughInputArguments, NULL) ;
  }
  if (nin > 5) {
    vlmxError (vlmxErrTooManyOutputArguments, NULL) ;
  }
  if (nout > 3) {
    vlmxError (vlmxErrTooManyOutputArguments, NULL) ;
  }

  if (! vlmxIsPlainMatrix(in[I], -1, -1)) {
    vlmxError (vlmxErrInvalidArgument, "I is not a plain matrix.") ;
  }

  if (! vlmxIsPlainMatrix(in[iwXp], -1, -1)) {
    vlmxError(vlmxErrInvalidArgument, "iwXp is not a plain matrix.") ;
  }

  M = getM(I) ;
  N = getN(I) ;
  Mp = getM(iwXp) ;
  Np = getN(iwXp) ;

  if(!vlmxIsPlainMatrix(in[iwYp], Mp, Np)) {
    vlmxError(vlmxErrInvalidArgument,
              "iwXp is not a plain matrix of the same idmension of iwYp.") ;
  }

  if(!vlmxIsPlainVector(in[X],N) || !vlmxIsPlainVector(in[Y],M)) {
    vlmxError(vlmxErrInvalidArgument,
              "X and Y are not plain vectors with a length equal to the"
	      " number of columns and rows of I.") ;
  }

  X_pt = getPr(X);
  Y_pt = getPr(Y) ;
  I_pt = getPr(I) ;
  iwXp_pt = getPr(iwXp) ;
  iwYp_pt = getPr(iwYp) ;

  /* Allocate the result. */
  out[wI] = mxCreateDoubleMatrix(Mp, Np, mxREAL) ;
  wI_pt = mxGetPr(out[wI]) ;

  if (nout > 1) {
    out[wIx] = mxCreateDoubleMatrix(Mp, Np, mxREAL) ;
    out[wIy] = mxCreateDoubleMatrix(Mp, Np, mxREAL) ;
    wIx_pt = mxGetPr (out[wIx]) ;
    wIy_pt = mxGetPr (out[wIy]) ;
  }

  /* -----------------------------------------------------------------
   *                                                        Do the job
   * -------------------------------------------------------------- */
  Xmin = X_pt [0] ;
  Xmax = X_pt [N - 1] ;
  Ymin = Y_pt [0] ;
  Ymax = Y_pt [M - 1] ;

  if (nout <= 1) {

    /* optimized for only image output */
    for(jp = 0 ; jp < Np ; ++jp) {
      for(ip = 0 ; ip < Mp ; ++ip) {
	/* Search for the four neighbors of the backprojected point. */
	double x = *iwXp_pt++ ;
	double y = *iwYp_pt++ ;
	double z = NaN ;

	/* This messy code allows the identity transformation
	 * to be processed as expected. */
	if(x >= Xmin && x <= Xmax &&
	   y >= Ymin && y <= Ymax) {
	  int j = findNeighbor(x, X_pt, N) ;
	  int i = findNeighbor(y, Y_pt, M) ;
	  double* pt  = I_pt + j*M + i ;

	  /* Weights. */
	  double x0 = X_pt[j] ;
	  double x1 = (j < N-1) ? X_pt[j+1] : x0 + 1;
	  double y0 = Y_pt[i] ;
	  double y1 = (i < M-1) ? Y_pt[i+1] : y0 + 1;
	  double wx = (x-x0)/(x1-x0) ;
	  double wy = (y-y0)/(y1-y0) ;

	  /* Load all possible neighbors. */
	  double z00 = 0.0 ;
	  double z10 = 0.0 ;
	  double z01 = 0.0 ;
	  double z11 = 0.0 ;

	  if(j > -1) {
	    if(i > -1 ) z00 = *pt ;
	    pt++ ;
	    if(i < M-1) z10 = *pt ;
	  } else {
	    pt++ ;
	  }

	  pt += M - 1;

	  if(j < N-1) {
	    if(i > -1 ) z01 = *pt ;
	    pt++ ;
	    if(i < M-1) z11 = *pt ;
	  }

	  /* Bilinear interpolation. */
	  z =
	    (1 - wy) * ((1-wx) * z00 + wx * z01) +
	    (    wy) * ((1-wx) * z10 + wx * z11) ;
	}

	*(wI_pt + jp*Mp + ip) = z ;
      }
    }
  }

  /* do also the derivatives */
  else {

    /* optimized for only image output */
    for(jp = 0 ; jp < Np ; ++jp) {
      for(ip = 0 ; ip < Mp ; ++ip) {
	/* Search for the four neighbors of the backprojected point. */
	double x = *iwXp_pt++ ;
	double y = *iwYp_pt++ ;
	double z = NaN, zx = NaN, zy = NaN ;

	/* This messy code allows the identity transformation
	 * to be processed as expected. */
	if(x >= Xmin && x <= Xmax &&
	   y >= Ymin && y <= Ymax) {
	  int j = findNeighbor(x, X_pt, N) ;
	  int i = findNeighbor(y, Y_pt, M) ;
	  double* pt  = I_pt + j*M + i ;

	  /* Weights. */
	  double x0 = X_pt[j] ;
	  double x1 = X_pt[j+1] ;
	  double y0 = Y_pt[i] ;
	  double y1 = Y_pt[i+1] ;
	  double wx = (x-x0)/(x1-x0) ;
	  double wy = (y-y0)/(y1-y0) ;

	  /* Load all possible neighbors. */
	  double z00 = 0.0 ;
	  double z10 = 0.0 ;
	  double z01 = 0.0 ;
	  double z11 = 0.0 ;

	  if(j > -1) {
	    if(i > -1 ) z00 = *pt ;
	    pt++ ;
	    if(i < M-1) z10 = *pt ;
	  } else {
	    pt++ ;
	  }

	  pt += M - 1;

	  if(j < N-1) {
	    if(i > -1 ) z01 = *pt ;
	    pt++ ;
	    if(i < M-1) z11 = *pt ;
	  }

	  /* Bilinear interpolation. */
	  z =
	    (1-wy)*( (1-wx) * z00 + wx * z01) +
	    wy*( (1-wx) * z10 + wx * z11) ;

	  zx =
	    (1-wy) * (z01 - z00) +
	       wy  * (z11 - z10) ;

	  zy =
	    (1-wx) * (z10 - z00) +
	       wx  * (z11 - z01) ;
	}

	*(wI_pt  + jp*Mp + ip) = z ;
	*(wIx_pt + jp*Mp + ip) = zx ;
	*(wIy_pt + jp*Mp + ip) = zy ;
      }
    }
  }
}
示例#4
0
文件: vl_dsift.c 项目: 19test/sandbox
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 ;

  float const *data ;
  int M, N ;

  int step [2] = {1,1} ;
  vl_bool norm = 0 ;

  vl_bool floatDescriptors = VL_FALSE ;
  vl_bool useFlatWindow = VL_FALSE ;
  double windowSize = -1.0 ;

  double *bounds = NULL ;
  double boundBuffer [4] ;
  VlDsiftDescriptorGeometry geom ;

  VL_USE_MATLAB_ENV ;

  geom.numBinX = 4 ;
  geom.numBinY = 4 ;
  geom.numBinT = 8 ;
  geom.binSizeX = 3 ;
  geom.binSizeY = 3 ;

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

  if (nin < 1) {
    vlmxError(vlmxErrNotEnoughInputArguments, NULL) ;
  } else if (nout > 2) {
    vlmxError(vlmxErrTooManyOutputArguments, NULL) ;
  }

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

  data = (float*) 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_fast :
        useFlatWindow = 1 ;
        break ;

      case opt_norm :
        norm = 1 ;
        break ;

      case opt_bounds :
        if (!vlmxIsPlainVector(optarg, 4)) {
          mexErrMsgTxt("BOUNDS must be a 4-dimensional vector.") ;
        }
        bounds = boundBuffer ;
        bounds [0] = mxGetPr(optarg)[0] - 1 ;
        bounds [1] = mxGetPr(optarg)[1] - 1 ;
        bounds [2] = mxGetPr(optarg)[2] - 1 ;
        bounds [3] = mxGetPr(optarg)[3] - 1 ;
        break ;

      case opt_size :
        if (!vlmxIsPlainVector(optarg,-1)) {
          vlmxError(vlmxErrInvalidArgument,"SIZE is not a plain vector.") ;
        }
        if (mxGetNumberOfElements(optarg) == 1) {
          geom.binSizeX = (int) mxGetPr(optarg)[0] ;
          geom.binSizeY = (int) mxGetPr(optarg)[0] ;
        } else if (mxGetNumberOfElements(optarg) == 2) {
          geom.binSizeX = (int) mxGetPr(optarg)[1] ;
          geom.binSizeY = (int) mxGetPr(optarg)[0] ;
        } else {
          vlmxError(vlmxErrInvalidArgument,"SIZE is neither a scalar or a 2D vector.") ;
        }
        if (geom.binSizeX < 1 || geom.binSizeY < 1) {
          vlmxError(vlmxErrInvalidArgument,"SIZE value is invalid.") ;
        }
        break ;

      case opt_step :
        if (!vlmxIsPlainVector(optarg,-1)) {
          vlmxError(vlmxErrInvalidArgument,"STEP is not a plain vector.") ;
        }
        if (mxGetNumberOfElements(optarg) == 1) {
          step[0] = (int) mxGetPr(optarg)[0] ;
          step[1] = (int) mxGetPr(optarg)[0] ;
        } else if (mxGetNumberOfElements(optarg) == 2) {
          step[0] = (int) mxGetPr(optarg)[1] ;
          step[1] = (int) mxGetPr(optarg)[0] ;
        } else {
          vlmxError(vlmxErrInvalidArgument,"STEP is neither a scalar or a 2D vector.") ;
        }
        if (step[0] < 1 || step[1] < 1) {
          vlmxError(vlmxErrInvalidArgument,"STEP value is invalid.") ;
        }
        break ;

      case opt_window_size :
        if (!vlmxIsPlainScalar(optarg) || (windowSize = *mxGetPr(optarg)) < 0) {
          vlmxError(vlmxErrInvalidArgument,"WINDOWSIZE is not a scalar or it is negative.") ;
        }
        break ;

      case opt_float_descriptors :
        floatDescriptors = VL_TRUE ;
        break ;

      case opt_geometry :
        if (!vlmxIsPlainVector(optarg,3)) {
          vlmxError(vlmxErrInvalidArgument, "GEOMETRY is not a 3D vector.") ;
        }
        geom.numBinY = (int)mxGetPr(optarg)[0] ;
        geom.numBinX = (int)mxGetPr(optarg)[1] ;
        geom.numBinT = (int)mxGetPr(optarg)[2] ;
        if (geom.numBinX < 1 ||
            geom.numBinY < 1 ||
            geom.numBinT < 1) {
          vlmxError(vlmxErrInvalidArgument, "GEOMETRY value is invalid.") ;
        }
        break ;

      default :
        abort() ;
    }
  }

  /* -----------------------------------------------------------------
   *                                                            Do job
   * -------------------------------------------------------------- */
  {
    int numFrames ;
    int descrSize ;
    VlDsiftKeypoint const *frames ;
    float const *descrs ;
    int k, i ;

    VlDsiftFilter *dsift ;

    /* note that the image received from MATLAB is transposed */
    dsift = vl_dsift_new (M, N) ;
    vl_dsift_set_geometry(dsift, &geom) ;
    vl_dsift_set_steps(dsift, step[0], step[1]) ;

    if (bounds) {
      vl_dsift_set_bounds(dsift,
                          VL_MAX(bounds[1], 0),
                          VL_MAX(bounds[0], 0),
                          VL_MIN(bounds[3], M - 1),
                          VL_MIN(bounds[2], N - 1));
    }
    vl_dsift_set_flat_window(dsift, useFlatWindow) ;

    if (windowSize >= 0) {
      vl_dsift_set_window_size(dsift, windowSize) ;
    }

    numFrames = vl_dsift_get_keypoint_num (dsift) ;
    descrSize = vl_dsift_get_descriptor_size (dsift) ;
    geom = *vl_dsift_get_geometry (dsift) ;

    if (verbose) {
      int stepX ;
      int stepY ;
      int minX ;
      int minY ;
      int maxX ;
      int maxY ;
      vl_bool useFlatWindow ;

      vl_dsift_get_steps (dsift, &stepY, &stepX) ;
      vl_dsift_get_bounds (dsift, &minY, &minX, &maxY, &maxX) ;
      useFlatWindow = vl_dsift_get_flat_window(dsift) ;

      mexPrintf("vl_dsift: image size         [W, H] = [%d, %d]\n", N, M) ;
      mexPrintf("vl_dsift: bounds:            [minX,minY,maxX,maxY] = [%d, %d, %d, %d]\n",
                minX+1, minY+1, maxX+1, maxY+1) ;
      mexPrintf("vl_dsift: subsampling steps: stepX=%d, stepY=%d\n", stepX, stepY) ;
      mexPrintf("vl_dsift: num bins:          [numBinT, numBinX, numBinY] = [%d, %d, %d]\n",
                geom.numBinT,
                geom.numBinX,
                geom.numBinY) ;
      mexPrintf("vl_dsift: descriptor size:   %d\n", descrSize) ;
      mexPrintf("vl_dsift: bin sizes:         [binSizeX, binSizeY] = [%d, %d]\n",
                geom.binSizeX,
                geom.binSizeY) ;
      mexPrintf("vl_dsift: flat window:       %s\n", VL_YESNO(useFlatWindow)) ;
      mexPrintf("vl_dsift: window size:       %g\n", vl_dsift_get_window_size(dsift)) ;
      mexPrintf("vl_dsift: num of features:   %d\n", numFrames) ;
    }

    vl_dsift_process (dsift, data) ;

    frames = vl_dsift_get_keypoints (dsift) ;
    descrs = vl_dsift_get_descriptors (dsift) ;

    /* ---------------------------------------------------------------
     *                                            Create output arrays
     * ------------------------------------------------------------ */
    {
      mwSize dims [2] ;

      dims [0] = descrSize ;
      dims [1] = numFrames ;

      if (floatDescriptors) {
        out[OUT_DESCRIPTORS] = mxCreateNumericArray
        (2, dims, mxSINGLE_CLASS, mxREAL) ;
      } else {
        out[OUT_DESCRIPTORS] = mxCreateNumericArray
        (2, dims, mxUINT8_CLASS, mxREAL) ;
      }

      dims [0] = norm ? 3 : 2 ;

      out[OUT_FRAMES] = mxCreateNumericArray
      (2, dims, mxDOUBLE_CLASS, mxREAL) ;
    }

    /* ---------------------------------------------------------------
     *                                                       Copy back
     * ------------------------------------------------------------ */
    {
      float *tmpDescr = mxMalloc(sizeof(float) * descrSize) ;
      double *outFrameIter = mxGetPr(out[OUT_FRAMES]) ;
      void *outDescrIter = mxGetData(out[OUT_DESCRIPTORS]) ;
      for (k = 0 ; k < numFrames ; ++k) {
        *outFrameIter++ = frames[k].y + 1 ;
        *outFrameIter++ = frames[k].x + 1 ;

        /* We have an implied / 2 in the norm, because of the clipping
           below */
        if (norm)
          *outFrameIter++ = frames [k].norm ;

        vl_dsift_transpose_descriptor (tmpDescr,
                                       descrs + descrSize * k,
                                       geom.numBinT,
                                       geom.numBinX,
                                       geom.numBinY) ;

        if (floatDescriptors) {
          for (i = 0 ; i < descrSize ; ++i) {
            float * pt = (float*) outDescrIter ;
            *pt++ = VL_MIN(512.0F * tmpDescr[i], 255.0F) ;
            outDescrIter = pt ;
          }
        } else {
          for (i = 0 ; i < descrSize ; ++i) {
            vl_uint8 * pt = (vl_uint8*) outDescrIter ;
            *pt++ = (vl_uint8) (VL_MIN(512.0F * tmpDescr[i], 255.0F)) ;
            outDescrIter = pt ;

          }
        }
      }
      mxFree(tmpDescr) ;
    }
    vl_dsift_delete (dsift) ;
  }
}