void convertDepth()

in source/mesh_stream/ConvertToBinary.cpp [148:243]


void convertDepth(
    const Camera& cam,
    const std::string& frameName,
    const bool saveIdx,
    const bool saveVtx,
    const bool savePfm,
    const bool saveObj) {
  if (!saveIdx && !saveVtx && !savePfm && !saveObj) {
    return;
  }

  const std::string& camId = cam.id;
  LOG(INFO) << folly::sformat("Converting depth: frame {}, camera {}...", frameName, camId);

  cv::Mat_<float> disparity = image_util::loadPfmImage(FLAGS_disparity, camId, frameName);
  cv::Mat_<float> depth = 1.0f / disparity;
  if (FLAGS_depth_scale < 1) {
    // nearest neighbor resize filter since we don't want to do any averaging of depths here
    cv::resize(depth, depth, cv::Size(), FLAGS_depth_scale, FLAGS_depth_scale, cv::INTER_NEAREST);
  }
  Eigen::MatrixXd vertexes = mesh_util::getVertexesEquiError(depth, cam);
  static const bool kWrapHorizontally = false;
  static const bool kIsSpherical = false;
  Eigen::MatrixXi faces = mesh_util::getFaces(
      vertexes, depth.cols, depth.rows, kWrapHorizontally, kIsSpherical, FLAGS_tear_ratio);

  // Remove geometry where we don't have valid depth data
  cv::Mat_<bool> vertexMask(depth.size());
  for (int i = 0; i < depth.rows; ++i) {
    for (int j = 0; j < depth.cols; ++j) {
      vertexMask(i, j) = !std::isnan(depth(i, j));
    }
  }

  if (!FLAGS_foreground_masks.empty()) {
    cv::Mat_<bool> foregroundMask =
        image_util::loadImage<bool>(FLAGS_foreground_masks, camId, frameName);
    cv::resize(foregroundMask, foregroundMask, depth.size(), 0, 0, cv::INTER_NEAREST);
    vertexMask = vertexMask & foregroundMask;
  }

  const int originalFaceCount = faces.rows();
  mesh_util::applyMaskToVertexesAndFaces(vertexes, faces, vertexMask);
  const int numFacesRemoved = originalFaceCount - faces.rows();
  LOG(INFO) << folly::sformat(
      "Removed {} of {} faces ({:.2f}%) corresponding to invalid depths and masked vertexes",
      numFacesRemoved,
      originalFaceCount,
      100.f * numFacesRemoved / (float)originalFaceCount);

  if (FLAGS_triangles > 0) {
    LOG(INFO) << folly::sformat("Target number of faces: {}", FLAGS_triangles);
    static const bool kIsEquierror = true;
    static const int kThreads = 1;
    render::MeshSimplifier ms(vertexes, faces, kIsEquierror, kThreads);
    static const float kStrictness = 0.2;
    static const bool kRemoveBoundaryEdges = false;
    ms.simplify(FLAGS_triangles, kStrictness, kRemoveBoundaryEdges);
    vertexes = ms.getVertexes();
    faces = ms.getFaces();

    // If depth is slightly negative, the viewer will take it to -infinity (it
    // does the inverse). We force this values to the minimum positive value
    for (int i = 0; i < vertexes.rows(); ++i) {
      if (vertexes.row(i).z() < 0) {
        vertexes.row(i).z() = FLT_MIN;
      }
    }
  }

  const filesystem::path vertexFilename =
      image_util::imagePath(FLAGS_bin, camId, frameName, ".vtx");
  filesystem::create_directories(vertexFilename.parent_path());

  const filesystem::path indexFilename = image_util::imagePath(FLAGS_bin, camId, frameName, ".idx");
  filesystem::create_directories(indexFilename.parent_path());

  if (saveIdx || saveVtx) {
    mesh_util::writeDepth(vertexes, faces, vertexFilename, indexFilename);
  }

  if (savePfm) {
    const filesystem::path depthFilename =
        image_util::imagePath(FLAGS_bin, camId, frameName, ".pfm");
    filesystem::create_directories(depthFilename.parent_path());
    mesh_util::writePfm(depth, cam.resolution, vertexes, faces, depthFilename);
  }

  if (saveObj) {
    LOG(INFO) << folly::sformat("Exporting obj: frame {}, camera {}...", frameName, camId);
    const filesystem::path objFilename = image_util::imagePath(FLAGS_bin, camId, frameName, ".obj");
    filesystem::create_directories(objFilename.parent_path());
    mesh_util::writeObj(
        mesh_util::readVertexes(vertexFilename), mesh_util::readFaces(indexFilename), objFilename);
  }
}