Esempio n. 1
0
//Main function
int main(int argc, char* argv[])
{
    if (argc != 2) {
        std::cout << "Usage: colorcanny image" << std::endl;
        return(0);
    }

    //CImg for output
    cimg_library::CImg <unsigned char> image(argv[1]);
    cimg_library::CImg <unsigned char> image_copy(image.width(), image.height(), image.depth(), image.spectrum());
    cimg_library::CImg <unsigned char> image_qwaf(image.width(), image.height(), image.depth(), image.spectrum());
    cimg_library::CImg <unsigned char> sobel(image.width(), image.height(), image.depth(), image.spectrum());
    cimg_library::CImg <unsigned char> sobel_dir(image.width(), image.height(), image.depth(), image.spectrum());
    cimg_library::CImg <unsigned char> nms_image(image.width(), image.height(), image.depth(), image.spectrum());
    cimg_library::CImg <unsigned char> nms_image_dir(image.width(), image.height(), image.depth(), image.spectrum());

    //Do a copy for testing
    for (int x=0; x<image.width(); x++) {
        for (int y=0; y<image.height(); y++) {
            unsigned char col[] = {image(x,y,0,0), image(x,y,0,1), image(x,y,0,2)};
            image_copy.draw_point(x,y,col);
        }
    }

    applyQWAF(image, image_qwaf);
    image_qwaf.save("image_qwaf.bmp");

    //Copy to see if everything is working properly
    image_copy.save("image_copy.bmp");

    //Apply a gaussian blur
    image.blur(1.6);

    //Vectors
    std::vector<unsigned char> magnitude;
    std::vector<unsigned char> nms;
    std::vector<float> direction;

    //Apply the sobel operator to the image and then non-maximum supression
    sobelOperator(image, magnitude, direction);
    NMS(nms, magnitude, direction, image.width(), image.height());

    //Write the magnitude and direction out to images
    writeMagnitude(sobel, magnitude);
    writeMagnitudeDirection(sobel_dir, magnitude, direction);
    writeMagnitude(nms_image, nms);
    writeMagnitudeDirection(nms_image_dir, nms, direction);

    //Write the images out to files
    sobel.save("sobel.bmp");
    sobel_dir.save("sobel_direction.bmp");
    nms_image.save("non_maxima.bmp");
    nms_image_dir.save("non_maxima_dir.bmp");

    //Return successful
    return 0;
}
Esempio n. 2
0
void DetectMTCNN::Process_net_p(const float *data, const VecInt &in_shape,
                                float threshold, float scale,
                                VecBoxInfo *boxes) {
  std::map<std::string, float *> data_map;
  std::map<std::string, VecInt> shape_map;
  data_map[in_p_str_] = const_cast<float *>(data);
  shape_map[in_p_str_] = in_shape;

  net_p_.Forward(data_map, shape_map);

  const auto &loc_shape = net_p_.GetBlobShapeByName<float>(net_p_conv4_2_);
  const auto *loc_data = net_p_.GetBlobDataByName<float>(net_p_conv4_2_);
  const auto *conf_data = net_p_.GetBlobDataByName<float>(net_p_prob1_);

  int out_h = loc_shape[2], out_w = loc_shape[3];
  int out_spatial_dim = out_h * out_w;

  boxes->clear();
  for (int i = 0; i < out_spatial_dim; ++i) {
    int h = i / out_w, w = i % out_w;
    float conf = conf_data[out_spatial_dim + i];
    if (conf > threshold) {
      float x_min = (net_p_stride_ * h) / scale;
      float y_min = (net_p_stride_ * w) / scale;
      float x_max = (net_p_stride_ * h + net_p_cell_size_ - 1) / scale;
      float y_max = (net_p_stride_ * w + net_p_cell_size_ - 1) / scale;
      BoxF box(x_min, y_min, x_max, y_max);
      BoxInfo box_info;
      box_info.box = box;
      box_info.box.score = conf;
      box_info.box.label = 1;
      for (int k = 0; k < 4; ++k) {
        box_info.box_reg[k] = loc_data[k * out_spatial_dim + i];
      }
      boxes->push_back(box_info);
    }
  }
  *boxes = NMS(*boxes, 0.5);
}
Esempio n. 3
0
  //! 使用非极大值抑制的车牌判断
  int PlateJudge::plateJudgeUsingNMS(const std::vector<CPlate> &inVec, std::vector<CPlate> &resultVec, int maxPlates) {
    std::vector<CPlate> plateVec;
    int num = inVec.size();
    bool outputResult = false;

    bool useCascadeJudge = true;
    bool useShirkMat = true;

    for (int j = 0; j < num; j++) {
      CPlate plate = inVec[j];
      Mat inMat = plate.getPlateMat();

      int result = plateSetScore(plate);

      if (result == 0) {
        if (0) {
          imshow("inMat", inMat);
          waitKey(0);
          destroyWindow("inMat");
        }

          int w = inMat.cols;
          int h = inMat.rows;

          Mat tmpmat = inMat(Rect_<double>(w * 0.05, h * 0.1, w * 0.9, h * 0.8));
          Mat tmpDes = inMat.clone();
          resize(tmpmat, tmpDes, Size(inMat.size()));

          plate.setPlateMat(tmpDes);

          if (useCascadeJudge) {
            int resultCascade = plateSetScore(plate);

            if (resultCascade == 0) {
              if (0) {
                imshow("inMat", inMat);
                waitKey(0);
                destroyWindow("inMat");
              }
              plateVec.push_back(plate);
            }
          }
          else {
            plateVec.push_back(plate);
          }
          
      }

      //if (result == 0) {
      //  plateVec.push_back(plate);
      //  if (outputResult) {
      //    std::stringstream ss(std::stringstream::in | std::stringstream::out);
      //    ss << "resources/image/tmp/plate/has" << "/" << plate.getPlatePos().center << "_"
      //      << plate.getPlatePos().size << "_" << plate.getPlatePos().angle << "_"
      //      << plate.getPlateScore() << ".jpg";
      //    imwrite(ss.str(), inMat);
      //  }
      //}
      //else {
      //  int w = inMat.cols;
      //  int h = inMat.rows;

      //  //再取中间部分判断一次

      //  Mat tmpmat = inMat(Rect_<double>(w * 0.05, h * 0.1, w * 0.9, h * 0.8));
      //  Mat tmpDes = inMat.clone();
      //  resize(tmpmat, tmpDes, Size(inMat.size()));

      //  plate.setPlateMat(tmpDes);

      //  int resultCascade = plateSetScore(plate);

      //  if (resultCascade == 0) {
      //    plateVec.push_back(plate);
      //    if (outputResult) {
      //      std::stringstream ss(std::stringstream::in | std::stringstream::out);
      //      ss << "resources/image/tmp/plate/has" << "/" << plate.getPlatePos().center << "_" 
      //        << plate.getPlatePos().size << "_" << plate.getPlatePos().angle << "_" 
      //        << plate.getPlateScore() << ".jpg";
      //      imwrite(ss.str(), tmpDes);
      //    }
      //  }
      //  else {
      //    if (outputResult) {
      //      std::stringstream ss(std::stringstream::in | std::stringstream::out);
      //      ss << "resources/image/tmp/plate/no" << "/" << plate.getPlatePos().center << "_"
      //        << plate.getPlatePos().size << "_" << plate.getPlatePos().angle << "_"
      //        << plate.getPlateScore() << ".jpg";
      //      imwrite(ss.str(), tmpDes);
      //    }
      //  }
      //}

    }

    std::vector<CPlate> reDupPlateVec;

    // 使用非极大值抑制来去除那些重叠的车牌
    // overlap阈值设置为0.5
    double overlap = 0.5;
    NMS(plateVec, reDupPlateVec, overlap);
  
    std::vector<CPlate>::iterator it = reDupPlateVec.begin();
    int count = 0;
    for (; it != reDupPlateVec.end(); ++it) {
      resultVec.push_back(*it);

      if (0) {
        imshow("plateMat", it->getPlateMat());
        waitKey(0);
        destroyWindow("plateMat");
      }

      count++;
      if (count >= maxPlates)
        break;
    }


    return 0;
  }
Esempio n. 4
0
void ncp_pathsearch(NonlinearComplementarityProblem* problem, double* z, double* F, int *info , SolverOptions* options)
{
/* Main step of the algorithm:
 * - compute jacobians
 * - call modified lemke
*/

  unsigned int n = problem->n;
  unsigned int preAlloc = options->iparam[SICONOS_IPARAM_PREALLOC];
  int itermax = options->iparam[SICONOS_IPARAM_MAX_ITER];

  double merit_norm = 1.0;
  double nn_tol = options->dparam[SICONOS_DPARAM_TOL];
  int nbiter = 0;

  /* declare a LinearComplementarityProblem on the stack*/
  LinearComplementarityProblem lcp_subproblem;
  lcp_subproblem.size = n;


  /* do some allocation if required
   * - nabla_F (used also as M for the LCP subproblem)
   * - q for the LCP subproblem
   *
   * Then fill the LCP subproblem
   */
  if (!preAlloc || (preAlloc && !options->internalSolvers))
  {
    options->internalSolvers = (SolverOptions *) malloc(sizeof(SolverOptions));
    solver_options_set(options->internalSolvers, SICONOS_LCP_PIVOT);
    options->numberOfInternalSolvers = 1;

    SolverOptions * lcp_options = options->internalSolvers;

    /* We always allocation once and for all since we are supposed to solve
     * many LCPs */
    lcp_options->iparam[SICONOS_IPARAM_PREALLOC] = 1;
    /* set the right pivot rule */
    lcp_options->iparam[SICONOS_IPARAM_PIVOT_RULE] = SICONOS_LCP_PIVOT_PATHSEARCH;
    /* set the right stacksize */
    lcp_options->iparam[SICONOS_IPARAM_PATHSEARCH_STACKSIZE] = options->iparam[SICONOS_IPARAM_PATHSEARCH_STACKSIZE];
  }


  assert(problem->nabla_F);
  lcp_subproblem.M = problem->nabla_F;


  if (!preAlloc || (preAlloc && !options->dWork))
  {
    options->dWork = (double *) malloc(4*n*sizeof(double));
  }
  lcp_subproblem.q = options->dWork;
  double* x = &options->dWork[n];
  double* x_plus = &options->dWork[2*n];
  double* r = &options->dWork[3*n];

  NMS_data* data_NMS;
  functions_LSA* functions;

  if (!preAlloc || (preAlloc && !options->solverData))
  {
    options->solverData = malloc(sizeof(pathsearch_data));
    pathsearch_data* solverData = (pathsearch_data*) options->solverData;

    /* do all the allocation */
    solverData->data_NMS = create_NMS_data(n, NM_DENSE, options->iparam, options->dparam);
    solverData->lsa_functions = (functions_LSA*) malloc(sizeof(functions_LSA));
    solverData->data_NMS->set = malloc(sizeof(positive_orthant));

    data_NMS = solverData->data_NMS;
    functions = solverData->lsa_functions;
    /* for use in NMS;  only those 3 functions are called */
    init_lsa_functions(functions, &FB_compute_F_ncp, &ncp_FB);
    functions->compute_H = &FB_compute_H_ncp;

    set_set_id(data_NMS->set, SICONOS_SET_POSITIVE_ORTHANT);

    /* fill ls_data */
    data_NMS->ls_data->compute_F = functions->compute_F;
    data_NMS->ls_data->compute_F_merit = functions->compute_F_merit;
    data_NMS->ls_data->z = NULL; /* XXX to check -- xhub */
    data_NMS->ls_data->zc = NMS_get_generic_workV(data_NMS->workspace, n);
    data_NMS->ls_data->F = NMS_get_F(data_NMS->workspace, n);
    data_NMS->ls_data->F_merit = NMS_get_F_merit(data_NMS->workspace, n);
    data_NMS->ls_data->desc_dir = NMS_get_dir(data_NMS->workspace, n);
    /** \todo this value should be settable by the user with a default value*/
    data_NMS->ls_data->alpha_min = fmin(data_NMS->alpha_min_watchdog, data_NMS->alpha_min_pgrad);
    data_NMS->ls_data->data = (void*)problem;
    data_NMS->ls_data->set = data_NMS->set;
    data_NMS->ls_data->sigma = options->dparam[SICONOS_DPARAM_NMS_SIGMA];
    /* data_NMS->ls_data->searchtype is set in the NMS code */
  }
  else
  {
    pathsearch_data* solverData = (pathsearch_data*) options->solverData;
    data_NMS = solverData->data_NMS;
    functions = solverData->lsa_functions;
  }

  /* initial value for ref_merit */
  problem->compute_F(problem->env, n, z, F);
  functions->compute_F_merit(problem, z, F, data_NMS->ls_data->F_merit);

  data_NMS->ref_merit = .5 * cblas_ddot(n, data_NMS->ls_data->F_merit, 1, data_NMS->ls_data->F_merit, 1);
  data_NMS->merit_bestpoint = data_NMS->ref_merit;
  cblas_dcopy(n, z, 1, NMS_checkpoint_0(data_NMS, n), 1);
  cblas_dcopy(n, z, 1, NMS_checkpoint_T(data_NMS, n), 1);
  cblas_dcopy(n, z, 1, NMS_bestpoint(data_NMS, n), 1);
  /* -------------------- end init ---------------------------*/

  int nms_failed = 0;
  double err = 10*nn_tol;

  /* to check the solution */
  LinearComplementarityProblem lcp_subproblem_check;
  int check_lcp_solution = 1; /* XXX add config for that */

  double normal_norm2_newton_point;

  /* F is already computed here at z */

  while ((err > nn_tol) && (nbiter < itermax) && !nms_failed)
  {
    int force_watchdog_step = 0;
    int force_d_step_merit_check = 0;
    double check_ratio = 0.0;
    nbiter++;
    /* update M, q and r */

    /* First find x */
    ncp_pathsearch_compute_x_from_z(n, z, F, x);
    pos_part(n, x, x_plus); /* update x_plus */

    ncp_pathsearch_update_lcp_data(problem, &lcp_subproblem, n, x_plus, x, r);

    if (check_lcp_solution)
    {
      lcp_subproblem_check.size = n;
      lcp_subproblem_check.M = problem->nabla_F;
      lcp_subproblem_check.q = lcp_subproblem.q;
      //cblas_dcopy(n, x, 1, lcp_subproblem_check.q , 1);
      //prodNumericsMatrix(n, n, -1.0, problem->nabla_F, x_plus, 0.0, lcp_subproblem.q);
    }

    double norm_r2 = cblas_ddot(n, r, 1, r, 1);
    if (norm_r2 < DBL_EPSILON*DBL_EPSILON) /* ||r|| < 1e-15 */
    {
      DEBUG_PRINTF("ncp_pathsearch :: ||r||  = %e < %e; path search procedure was successful!\n", norm_r2, DBL_EPSILON*DBL_EPSILON);
      (*info) = 0;
      ncp_compute_error(n, z, F, nn_tol, &err); /* XXX F should be up-to-date, we should check only CC*/
      break;
    }

    /* end update M, q and r */

    lcp_pivot_covering_vector(&lcp_subproblem, x_plus, x, info, options->internalSolvers, r);

    switch (*info)
    {
      case LCP_PIVOT_SUCCESS:
        DEBUG_PRINT("ncp_pathsearch :: path search procedure was successful!\n");
        if (check_lcp_solution)
        {
          double err_lcp = 0.0;
          cblas_daxpy(n, 1.0, r, 1, lcp_subproblem_check.q, 1);
          lcp_compute_error(&lcp_subproblem_check, x_plus, x, 1e-14, &err_lcp);
          double local_tol = fmax(1e-14, DBL_EPSILON*sqrt(norm_r2));
          printf("ncp_pathsearch :: lcp solved with error = %e; local_tol = %e\n", err_lcp, local_tol);
          //assert(err_lcp < local_tol && "ncp_pathsearch :: lcp solved with very bad precision");
          if (err_lcp > local_tol)
          {
            printf("ncp_pathsearch :: lcp solved with very bad precision\n");
            NM_display(lcp_subproblem.M);
            printf("z r q x_plus\n");
            for (unsigned i = 0; i < n; ++i) printf("%e %e %e %e\n", z[i], r[i], lcp_subproblem.q[i], x_plus[i]);
            options->internalSolvers->iparam[SICONOS_IPARAM_PIVOT_RULE] = 0;
            lcp_pivot(&lcp_subproblem, x_plus, x, info, options->internalSolvers);
            options->internalSolvers->iparam[SICONOS_IPARAM_PIVOT_RULE] = SICONOS_LCP_PIVOT_PATHSEARCH;
            lcp_compute_error(&lcp_subproblem_check, x_plus, x, 1e-14, &err_lcp);
            printf("ncp_pathsearch :: lcp resolved with error = %e; local_tol = %e\n", err_lcp, local_tol);
          }


          /* XXX missing recompute x ?*/
          /* recompute the normal norm */
          problem->compute_F(problem->env, n, x_plus, r);
          cblas_daxpy(n, -1.0, x, 1, r, 1);
          normal_norm2_newton_point = cblas_ddot(n, r, 1, r, 1);
          if (normal_norm2_newton_point > norm_r2)
          {
            printf("ncp_pathsearch :: lcp successfully solved, but the norm of the normal map increased! %e > %e\n", normal_norm2_newton_point, norm_r2);
            //assert(normal_norm2_newton_point <= norm_r2);
          }
          else
          {
            printf("ncp_pathsearch :: lcp successfully solved, norm of the normal map decreased! %e < %e\n", normal_norm2_newton_point, norm_r2);
            //check_ratio = norm_r2/normal_norm2_newton_point;
          }
          if (50*normal_norm2_newton_point < norm_r2)
          {
            force_d_step_merit_check = 1;
          }
          else if (10*normal_norm2_newton_point < norm_r2)
          {
//            check_ratio = sqrt(norm_r2/normal_norm2_newton_point);
          }
        }
        break;
      case LCP_PIVOT_RAY_TERMINATION:
        DEBUG_PRINT("ncp_pathsearch :: ray termination, let's fastened your seat belt!\n");
        break;
      case LCP_PATHSEARCH_LEAVING_T:
        DEBUG_PRINT("ncp_pathsearch :: leaving t, fastened your seat belt!\n");
        DEBUG_PRINTF("ncp_pathsearch :: max t value = %e\n", options->internalSolvers->dparam[2]); /* XXX fix 2 */
        /* try to retry solving the problem */
        /* XXX keep or not ? */
        /* recompute the normal norm */
        problem->compute_F(problem->env, n, x_plus, r);
        cblas_daxpy(n, -1.0, x, 1, r, 1);
        normal_norm2_newton_point = cblas_ddot(n, r, 1, r, 1);
        if (normal_norm2_newton_point > norm_r2)
        {
          printf("ncp_pathsearch :: lcp successfully solved, but the norm of the normal map increased! %e > %e\n", normal_norm2_newton_point, norm_r2);
          //assert(normal_norm2_newton_point <= norm_r2);
        }
        else
        {
          printf("ncp_pathsearch :: lcp successfully solved, norm of the normal map decreased! %e < %e\n", normal_norm2_newton_point, norm_r2);
          check_ratio = 5.0*norm_r2/normal_norm2_newton_point;
        }
        if (options->internalSolvers->dparam[2] > 1e-5) break;
        memset(x_plus, 0, sizeof(double) * n);
        problem->compute_F(problem->env, n, x_plus, r);
        ncp_pathsearch_compute_x_from_z(n, x_plus, r, x);
        ncp_pathsearch_update_lcp_data(problem, &lcp_subproblem, n, x_plus, x, r);
        lcp_pivot_covering_vector(&lcp_subproblem, x_plus, x, info, options->internalSolvers, r);
        if (*info == LCP_PIVOT_SUCCESS)
        {
           DEBUG_PRINT("ncp_pathsearch :: Lemke start worked !\n");
           double err_lcp = 0.0;
           cblas_daxpy(n, 1.0, r, 1, lcp_subproblem_check.q, 1);
           lcp_compute_error(&lcp_subproblem_check, x_plus, x, 1e-14, &err_lcp);
           double local_tol = fmax(1e-14, DBL_EPSILON*sqrt(norm_r2));
           printf("ncp_pathsearch :: lcp solved with error = %e; local_tol = %e\n", err_lcp, local_tol);
           assert(err_lcp < local_tol);
        }
        else
        {
          NM_display(lcp_subproblem.M);
          printf("z r q x_plus\n");
          for (unsigned i = 0; i < n; ++i) printf("%e %e %e %e\n", z[i], r[i], lcp_subproblem.q[i], x_plus[i]);
          DEBUG_PRINT("ncp_pathsearch :: Lemke start did not succeeded !\n");
          lcp_pivot_diagnose_info(*info);
          if (*info == LCP_PATHSEARCH_LEAVING_T)
          {
            DEBUG_PRINTF("ncp_pathsearch :: max t value after Lemke start = %e\n", options->internalSolvers->dparam[2]);
          }
          options->internalSolvers->iparam[SICONOS_IPARAM_PIVOT_RULE] = 0;
          lcp_pivot(&lcp_subproblem, x_plus, x, info, options->internalSolvers);
          options->internalSolvers->iparam[SICONOS_IPARAM_PIVOT_RULE] = SICONOS_LCP_PIVOT_PATHSEARCH;
          double err_lcp = 0.0;
          lcp_compute_error(&lcp_subproblem, x_plus, x, 1e-14, &err_lcp);
          printf("ncp_pathsearch :: lemke start resolved with info = %d; error = %e\n", *info, err_lcp);
          printf("x_plus x_minus\n");
          for (unsigned i = 0; i < n; ++i) printf("%e %e\n", x_plus[i], x[i]);
          /* recompute the normal norm */
          problem->compute_F(problem->env, n, x_plus, r);
          cblas_daxpy(n, -1.0, x, 1, r, 1);
          double normal_norm2_newton_point = cblas_ddot(n, r, 1, r, 1);
          if (normal_norm2_newton_point > norm_r2)
          {
            printf("ncp_pathsearch :: lcp successfully solved, but the norm of the normal map increased! %e > %e\n", normal_norm2_newton_point, norm_r2);
            //assert(normal_norm2_newton_point <= norm_r2);
          }
          else
          {
             printf("ncp_pathsearch :: lcp successfully solved, norm of the normal map decreased! %.*e < %.*e\n", DECIMAL_DIG, normal_norm2_newton_point, DECIMAL_DIG, norm_r2);
          }
          if (100*normal_norm2_newton_point < norm_r2)
          {
            force_d_step_merit_check = 1;
          }
        }
        break;
      case LCP_PIVOT_NUL:
        printf("ncp_pathsearch :: kaboom, kaboom still more work needs to be done\n");
        lcp_pivot_diagnose_info(*info);
//        exit(EXIT_FAILURE);
        force_watchdog_step = 1;
        break;
      case LCP_PATHSEARCH_NON_ENTERING_T:
        DEBUG_PRINT("ncp_pathsearch :: non entering t, something is wrong here. Fix the f****** code!\n");
        assert(0 && "ncp_pathsearch :: non entering t, something is wrong here\n"); 
        force_watchdog_step = 1;
        break;
      default:
        printf("ncp_pathsearch :: unknown code returned by the path search\n");
        exit(EXIT_FAILURE);
    }

    nms_failed = NMS(data_NMS, problem, functions, z, x_plus, force_watchdog_step, force_d_step_merit_check, check_ratio);
    /* at this point z has been updated */

    /* recompute the normal norm */
    problem->compute_F(problem->env, n, z, F);
    functions->compute_F_merit(problem, z, F, data_NMS->ls_data->F_merit);

    /* XXX is this correct ? */
    merit_norm = .5 * cblas_ddot(n, data_NMS->ls_data->F_merit, 1, data_NMS->ls_data->F_merit, 1);

    ncp_compute_error(n, z, F, nn_tol, &err); /* XXX F should be up-to-date, we should check only CC*/
    DEBUG_PRINTF("ncp_pathsearch :: iter = %d, ncp_error = %e; merit_norm^2 = %e\n", nbiter, err, merit_norm);

  }

  options->iparam[1] = nbiter;
  options->dparam[1] = err;
  if (nbiter == itermax)
  {
    *info = 1;
  }
  else if (nms_failed)
  {
    *info = 2;
  }
  else
  {
    *info = 0;
  }

  DEBUG_PRINTF("ncp_pathsearch procedure finished :: info = %d; iter = %d; ncp_error = %e; merit_norm^2 = %e\n", *info, nbiter, err, merit_norm);

  if (!preAlloc)
  {
    freeNumericsMatrix(problem->nabla_F);
    free(problem->nabla_F);
    problem->nabla_F = NULL;
    free(options->dWork);
    options->dWork = NULL;
    solver_options_delete(options->internalSolvers);
    free(options->internalSolvers);
    options->internalSolvers = NULL;
    free_NMS_data(data_NMS);
    free(functions);
    free(options->solverData);
    options->solverData = NULL;
  }
}
Esempio n. 5
0
void DetectMTCNN::Predict(const JImage &im_src, const RectF &roi,
                          VecBoxF *boxes, std::vector<VecPointF> *Gpoints) {
  boxes->clear(), Gpoints->clear();
  net_p_boxes_.clear(), net_r_boxes_.clear(), net_o_boxes_.clear();
  float crop_h = roi.h <= 1 ? roi.h * im_src.h_ : roi.h;
  float crop_w = roi.w <= 1 ? roi.w * im_src.w_ : roi.w;
  CalculateScales(crop_h, crop_w, factor_, max_side_, min_side_, &scales_);

  for (auto scale : scales_) {
    auto scale_h = static_cast<int>(std::ceil(crop_h * scale));
    auto scale_w = static_cast<int>(std::ceil(crop_w * scale));
    net_p_in_shape_[2] = scale_w, net_p_in_shape_[3] = scale_h;
    net_p_in_data_.resize(1 * 3 * scale_w * scale_h);
    ConvertData(im_src, net_p_in_data_.data(), roi, 3, scale_h, scale_w, 1,
                true);
    VecBoxInfo boxes_p;
    Process_net_p(net_p_in_data_.data(), net_p_in_shape_, thresholds_[0], scale,
                  &boxes_p);
    net_p_boxes_.insert(net_p_boxes_.end(), boxes_p.begin(), boxes_p.end());
  }
  net_p_boxes_ = NMS(net_p_boxes_, 0.7);
  BoxRegression(net_p_boxes_);
  Box2SquareWithConstrain(net_p_boxes_, crop_h, crop_w);
  if (net_p_boxes_.empty()) {
    return;
  }

  net_r_in_shape_[0] = static_cast<int>(net_p_boxes_.size());
  net_r_in_data_.resize(net_r_in_shape_[0] * net_r_in_num_);
  for (int n = 0; n < net_p_boxes_.size(); ++n) {
    const auto &net_12_box = net_p_boxes_[n].box;
    ConvertData(im_src, net_r_in_data_.data() + n * net_r_in_num_,
                net_12_box.RectFloat(), net_r_in_c_, net_r_in_h_, net_r_in_w_,
                1, true);
  }
  Process_net_r(net_r_in_data_.data(), net_r_in_shape_, thresholds_[1],
                net_p_boxes_, &net_r_boxes_);
  net_r_boxes_ = NMS(net_r_boxes_, 0.7);
  BoxRegression(net_r_boxes_);
  Box2SquareWithConstrain(net_r_boxes_, crop_h, crop_w);
  if (net_r_boxes_.empty()) {
    return;
  }

  net_o_in_shape_[0] = static_cast<int>(net_r_boxes_.size());
  net_o_in_data_.resize(net_o_in_shape_[0] * net_o_in_num_);
  for (int n = 0; n < net_r_boxes_.size(); ++n) {
    const auto &net_24_box = net_r_boxes_[n].box;
    ConvertData(im_src, net_o_in_data_.data() + n * net_o_in_num_,
                net_24_box.RectFloat(), net_o_in_c_, net_o_in_h_, net_o_in_w_,
                1, true);
  }
  Process_net_o(net_o_in_data_.data(), net_o_in_shape_, thresholds_[2],
                net_r_boxes_, &net_o_boxes_);
  BoxRegression(net_o_boxes_);
  net_o_boxes_ = NMS(net_o_boxes_, 0.7, true);
  BoxWithConstrain(net_o_boxes_, crop_h, crop_w);

  for (const auto &box_info : net_o_boxes_) {
    boxes->push_back(box_info.box);
    VecPointF mark_points;
    for (int k = 0; k < 5; ++k) {
      mark_points.emplace_back(box_info.landmark[2 * k],
                               box_info.landmark[2 * k + 1]);
    }
    Gpoints->push_back(mark_points);
  }
}