void DepthVideoProcessor::gridXformSplit()

in lib/Processor.cpp [888:985]


void DepthVideoProcessor::gridXformSplit(const Params& params) {
  // Validate compatibility of old and new xform types.
  if (params.depthXformDesc.depthType != DepthXformType::Grid) {
    throw std::runtime_error("Transform type must be a grid type.");
  }

  DepthStream& ds = video_->depthStream(params.depthStream);
  const XformDescriptor prevDesc = ds.depthXformDesc();
  if (prevDesc.depthType != DepthXformType::Global &&
      prevDesc.depthType != DepthXformType::Grid) {
    throw std::runtime_error("Can only split global or grid type transforms.");
  }

  if (params.depthXformDesc.valueXform != prevDesc.valueXform) {
    throw std::runtime_error(
        "Old and new transforms must use same value transform.");
  }

  if (prevDesc.depthType != DepthXformType::Global && (
      prevDesc.gridSize.x() > params.depthXformDesc.gridSize.x() ||
      prevDesc.gridSize.y() > params.depthXformDesc.gridSize.y())) {
    throw std::runtime_error(
        "New transform must have at least the same number"
        " of rows and columns as the old transform.");
  }

  // Create a copy of the current transforms
  std::vector<std::unique_ptr<Xform>> prevXforms;
  for (int frame = 0; frame < video_->numFrames(); ++frame) {
    prevXforms.push_back(ds.frame(frame).depthXform().clone());
  }

  ds.resetDepthXforms(params.depthXformDesc);

  for (int frame = 0; frame < video_->numFrames(); ++frame) {
    const std::vector<double*>& prevParamBlocks =
        prevXforms[frame]->paramBlocks();
    const std::vector<int>& prevParamBlockSizes =
        prevXforms[frame]->paramBlockSizes();

    const DepthXform& newXform = ds.frame(frame).depthXform();
    const std::vector<double*>& newParamBlocks = newXform.paramBlocks();
    const std::vector<int>& newParamBlockSizes = newXform.paramBlockSizes();

    for (int row = 0; row < params.depthXformDesc.gridSize.y(); ++row) {
      for (int col = 0; col < params.depthXformDesc.gridSize.x(); ++col) {
        const int idx = col + row * params.depthXformDesc.gridSize.x();
        const int N = newParamBlockSizes[idx];
        if (prevDesc.depthType == DepthXformType::Global) {
          assert(prevParamBlocks.size() == 1);
          assert(prevParamBlockSizes[0] == N);
          memcpy(newParamBlocks[idx], prevParamBlocks[0], N * sizeof(double));
        } else if (prevDesc.depthType == DepthXformType::Grid) {
          const int prevRows = prevDesc.gridSize.y();
          const int prevCols = prevDesc.gridSize.x();
          assert(prevRows >= 2);
          assert(prevCols >= 2);

          const int newRows = params.depthXformDesc.gridSize.y();
          const int newCols = params.depthXformDesc.gridSize.x();

          const double maxx = std::nextafter(prevCols - 1, 0.0);
          const double maxy = std::nextafter(prevRows - 1, 0.0);

          const double sx = std::min(
              col / double(newCols - 1) * (prevCols - 1), maxx);
          const double sy = std::min(
              row / double(newRows - 1) * (prevRows - 1), maxy);

          const int ix = static_cast<int>(sx);
          const int iy = static_cast<int>(sy);
          assert(ix >= 0 && ix < newCols - 1);
          assert(iy >= 0 && iy < newRows - 1);

          const double rx = sx - ix;
          const double ry = sy - iy;

          double* b0 = prevParamBlocks[ix + iy * prevCols];
          double* b1 = prevParamBlocks[(ix + 1) + iy * prevCols];
          double* b2 = prevParamBlocks[ix + (iy + 1) * prevCols];
          double* b3 = prevParamBlocks[(ix + 1) + (iy + 1) * prevCols];

          const double w0 = (1.f - rx) * (1.f - ry);
          const double w1 = rx * (1.f - ry);
          const double w2 = (1.f - rx) * ry;
          const double w3 = rx * ry;

          for (int i = 0; i < N; ++i) {
            newParamBlocks[idx][i] =
                b0[i] * w0 + b1[i] * w1 + b2[i] * w2 + b3[i] * w3;
          }
        } else {
          throw std::runtime_error("Unsupported transform type.");
        }
      }
    }
  }
}