std::size_t SeparableFiltersResampler::prepareContributorLists()

in cpp/spectrum/core/proc/legacy/SeparableFiltersResampler.cpp [164:246]


std::size_t SeparableFiltersResampler::prepareContributorLists() {
  // count number of rows that need to be buffered to allow y resizing
  std::size_t nRowsBuffered = 0;

  // for each direction
  for (int d = 1; d >= 0; --d) {
    const std::uint32_t& dst = (d ? mDstWidth : mDstHeight);
    const std::uint32_t& src = (d ? mSrcWidth : mSrcHeight);
    const double scale = static_cast<double>(dst) / src;
    const double filterHalfWidth = ((MK_SUPPORT * 0.5f) / scale);

    // for each dst coordinate, identify the src coordinates which contribute
    // to it
    for (std::uint32_t c = 0; c < dst; ++c) {
      vector<Contrib>& contrib = (d ? mXContributors[c] : mYContributors[c]);

      // convert from discrete to continuous coordinates, scale, then
      // convert back to discrete.
      float center = ((static_cast<float>(c) + 0.5f) / scale) - 0.5f;
      int left = static_cast<int>(floor(center - filterHalfWidth));
      int right = static_cast<int>(ceil(center + filterHalfWidth));

      // calculate index and weight for each contributor
      float totalWeight = 0.0f;
      float maxWeight = -INFINITY;
      std::size_t maxWeightIndex = 0;
      for (int j = left; j <= right; ++j) {
        // get the weight associated with this index
        float weight = magicKernelWeight((center - j) * scale);
        if (weight == 0.0f) {
          continue;
        }
        totalWeight += weight;

        // ensure index is valid (clamp if necessary)
        int index = j;
        if (index < 0) {
          index = 0;
        } else if (index >= (int)src) {
          index = src - 1;
        }

        // record this contributor
        contrib.push_back(Contrib(index, weight));
        if (weight > maxWeight) {
          maxWeight = weight;
          maxWeightIndex = contrib.size() - 1;
        }
      }

      // normalize
      const double norm = (1.0f / totalWeight);
      totalWeight = 0.0f;
      for (std::size_t j = 0; j < contrib.size(); ++j) {
        contrib[j].weight *= norm;
        contrib[j].wQ = FltToFixQ11(contrib[j].weight);
        totalWeight += contrib[j].weight;
      }

      // ensure filtered values add up to 1
      if (totalWeight != 1.0f) {
        contrib[maxWeightIndex].weight += (1.0f - totalWeight);
        contrib[maxWeightIndex].wQ =
            FltToFixQ11(contrib[maxWeightIndex].weight);
      }

      // buffered rows logic
      if (d == 0) {
        nRowsBuffered = std::max(nRowsBuffered, contrib.size());
      }
    }
  }

  // for each src row, count how many times it contributes to dst
  for (std::uint32_t r = 0; r < mDstHeight; ++r) {
    for (std::size_t k = 0; k < mYContributors[r].size(); ++k) {
      SPECTRUM_ENFORCE_IF(mYContributors[r][k].index < 0);
      SPECTRUM_ENFORCE_IF(mYContributors[r][k].index >= (int)mSrcHeight);
      mSrcRowInfo[mYContributors[r][k].index].second++;
    }
  }
  return nRowsBuffered;
}