MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ fit_box()

BoxExtent MayaFlux::Kinesis::fit_box ( std::span< const Eigen::VectorXd >  samples,
double  coverage = 0.9,
double  softness_fraction = 0.15 
)
inline

Fit a box extent covering a central fraction of a sample set.

Parameters
samplesObservations, all of the same dimension
coverageFraction of observations the bounds should contain per axis, in 0..1. One takes the full min and max
softness_fractionSoft margin per axis, as a fraction of that axis's fitted width
Returns
Bounds at the symmetric quantiles implied by coverage

Quantiles rather than min and max so one badly performed demonstration does not widen the extent to include everything between it and the others. A coverage of one recovers the min and max behaviour for callers who want it.

Definition at line 284 of file FeatureExtent.hpp.

288{
289 if (samples.empty())
290 return {};
291
292 const Eigen::Index n = samples.front().size();
293 BoxExtent extent {
294 .lower = Eigen::VectorXd::Zero(n),
295 .upper = Eigen::VectorXd::Zero(n),
296 .softness = Eigen::VectorXd::Zero(n)
297 };
298
299 const double tail = 0.5 * (1.0 - std::clamp(coverage, 0.0, 1.0));
300 std::vector<double> axis;
301 axis.reserve(samples.size());
302
303 for (Eigen::Index i = 0; i < n; ++i) {
304 axis.clear();
305 for (const auto& s : samples)
306 axis.push_back(s(i));
307 std::ranges::sort(axis);
308
309 const auto last = static_cast<double>(axis.size() - 1);
310 const auto lo_idx = static_cast<size_t>(std::floor(tail * last));
311 const auto hi_idx = static_cast<size_t>(std::ceil((1.0 - tail) * last));
312
313 extent.lower(i) = axis[lo_idx];
314 extent.upper(i) = axis[hi_idx];
315 extent.softness(i) = std::max(
316 (extent.upper(i) - extent.lower(i)) * softness_fraction, 1e-9);
317 }
318
319 return extent;
320}

References MayaFlux::Kinesis::BoxExtent::lower.