69 ComputeData InputType = std::shared_ptr<Kakshya::SignalSourceContainer>,
70 ComputeData OutputType = InputType>
116 return Reflect::get_enum_names_lowercase<VisionSortKey>();
122 return "VisionSorter";
129 const auto analysis_it =
input.
metadata.find(
"vision_analysis");
130 if (analysis_it !=
input.metadata.end() && analysis_it->second.has_value()) {
131 auto analysis = safe_any_cast_or_throw<VisionAnalysis>(analysis_it->second);
133 const size_t n = !analysis.frame.boxes.empty()
134 ? analysis.frame.boxes.size()
135 : analysis.frame.contours.size();
139 while (padded <
static_cast<uint32_t
>(n))
142 std::vector<float> keys(padded, std::numeric_limits<float>::infinity());
143 for (
size_t i = 0; i < n; ++i)
146 std::vector<float> indices(padded);
147 for (uint32_t i = 0; i < padded; ++i)
148 indices[i] =
static_cast<float>(i);
150 const auto k =
static_cast<uint32_t
>(
151 std::ceil(std::log2(
static_cast<double>(padded))));
152 const uint32_t total_passes =
k * (
k + 1) / 2;
153 const uint32_t desc = (this->
get_direction() == SortingDirection::DESCENDING) ? 1U : 0U;
154 const uint32_t
count = padded;
162 [
k, desc,
count](uint32_t p,
void* pc_ptr) {
163 uint32_t stage = 0,
pass = 0, remaining = p;
164 for (uint32_t s = 0; s <
k; ++s) {
165 if (remaining <= s) {
170 remaining -= (s + 1);
175 *
static_cast<PC*
>(pc_ptr) = { stage,
pass,
count, desc };
182 std::vector<float> sorted_idx_floats(padded);
183 ctx->download_binding(1, sorted_idx_floats.data(),
184 padded *
sizeof(
float));
186 auto apply_permutation = [&]<
typename T>(std::vector<T>& coll) {
187 std::vector<T> sorted(n);
188 for (
size_t i = 0; i < n; ++i) {
189 const auto src =
static_cast<size_t>(sorted_idx_floats[i]);
191 sorted[i] = coll[src];
193 coll = std::move(sorted);
196 if (!analysis.frame.boxes.empty())
197 apply_permutation(analysis.frame.boxes);
198 if (!analysis.frame.contours.empty())
199 apply_permutation(analysis.frame.contours);
202 out.metadata =
input.metadata;
203 out.metadata[
"vision_analysis"] = std::move(analysis);
215 const auto analysis_it =
input.
metadata.find(
"vision_analysis");
216 if (analysis_it ==
input.metadata.end() || !analysis_it->second.has_value()) {
217 error<std::runtime_error>(
220 std::source_location::current(),
221 "VisionSorter: no vision_analysis in input metadata");
224 auto analysis = safe_any_cast_or_throw<VisionAnalysis>(analysis_it->second);
226 const bool descending = (this->
get_direction() == SortingDirection::DESCENDING);
228 auto sort_collection = [&]<
typename T>(std::vector<T>& coll) {
229 const size_t n = coll.size();
230 std::vector<size_t> idx(n);
231 std::iota(idx.begin(), idx.end(), 0);
232 std::stable_sort(idx.begin(), idx.end(),
233 [&](
size_t a,
size_t b) {
234 const float ka = m_key_fn
235 ? m_key_fn(a, analysis)
236 : key_for(a, coll, analysis);
237 const float kb = m_key_fn
238 ? m_key_fn(b, analysis)
239 : key_for(b, coll, analysis);
240 return descending ? ka > kb : ka < kb;
242 std::vector<T> sorted(n);
243 for (
size_t i = 0; i < n; ++i)
244 sorted[i] = coll[idx[i]];
245 coll = std::move(sorted);
248 if (!analysis.frame.boxes.empty())
249 sort_collection(analysis.frame.boxes);
250 if (!analysis.frame.contours.empty())
251 sort_collection(analysis.frame.contours);
254 out.metadata =
input.metadata;
255 out.metadata[
"vision_analysis"] = std::move(analysis);
274 template <
typename T>
275 [[nodiscard]]
float key_for(
size_t index,
const std::vector<T>& coll,
278 if constexpr (std::is_same_v<T, Kinesis::Vision::BoundingBox>) {
290 return box.
w * box.
h;
292 return 2.F * (box.
w + box.
h);
294 return box.
x + box.
w * 0.5F;
296 return box.
y + box.
h * 0.5F;
316 if (contour.
points.empty())
318 glm::vec2 mn = contour.
points[0], mx = contour.
points[0];
319 for (
const auto& p : contour.
points) {
334 return (mn.x + mx.x) * 0.5F;
335 return (mn.y + mx.y) * 0.5F;
347 std::shared_ptr<Kakshya::SignalSourceContainer>,
348 std::shared_ptr<Kakshya::SignalSourceContainer>>;
351 std::vector<Kakshya::DataVariant>,
352 std::vector<Kakshya::DataVariant>>;
Core::GlobalInputConfig input
Modern, digital-first universal sorting framework for Maya Flux.
std::shared_ptr< GpuExecutionContext< InputType, OutputType > > m_gpu_backend
virtual output_type apply_operation_internal(const input_type &input, const ExecutionContext &context)
Internal execution method - ComputeMatrix can access this.
output_type execute(const input_type &input, const ExecutionContext &ctx) override
Injects multipass configuration into the context before dispatch when set_multipass() has been called...
ShaderExecutionContext & set_multipass(uint32_t pass_count, std::function< void(uint32_t, void *)> pc_updater)
Configure multi-pass (CHAINED) dispatch.
ShaderExecutionContext & in_out(const std::vector< T > &data, GpuBufferBinding::ElementType type=GpuBufferBinding::ElementType::FLOAT32)
Add an INPUT_OUTPUT binding, inferring the next available binding index.
Concrete GpuExecutionContext for a single fixed shader with fixed bindings.
void set_strategy(SortingStrategy strategy)
Configure sorting strategy.
void set_granularity(SortingGranularity granularity)
Configure output granularity.
void set_direction(SortingDirection direction)
Configure sorting direction.
SortingDirection get_direction() const
Template-flexible sorter base with instance-defined I/O types.
float key_for_box(const Kinesis::Vision::BoundingBox &box) const
SortingType get_sorting_type() const override
Gets the sorting type category for this sorter.
output_type sort_implementation(const input_type &input) override
Pure virtual sorting implementation - derived classes implement this.
VisionSorter(KeyFn key_fn, SortingDirection direction=SortingDirection::DESCENDING)
void set_key_fn(KeyFn key_fn)
output_type apply_operation_internal(const input_type &input, const ExecutionContext &context) override
Internal execution method - ComputeMatrix can access this.
VisionSortKey get_key() const
VisionSorter(VisionSortKey key=VisionSortKey::AREA, SortingDirection direction=SortingDirection::DESCENDING)
float compute_key(size_t index, const VisionAnalysis &analysis) const
float key_for_contour(const Kinesis::Vision::Contour &contour) const
std::vector< std::string > get_available_methods() const
std::function< float(size_t index, const VisionAnalysis &)> KeyFn
float key_for(size_t index, const std::vector< T > &coll, const VisionAnalysis &analysis) const
std::string get_sorter_name() const override
Get sorter-specific name (derived classes override this)
void set_key(VisionSortKey key)
Reorders detection results in a VisionAnalysis by a scalar key or callable.
@ ComputeMatrix
Compute operations (Yantra - algorithms, matrices, DSP)
@ Yantra
DSP algorithms, computational units, matrix operations, Grammar.
SortingDirection
Ascending or descending sort order.
@ COPY_SORT
Create sorted copy (preserves input)
SortingType
Categories of sorting operations for discovery and organization.
@ SPATIAL
Multi-dimensional spatial sorting.
VisionSortKey
Named scalar attributes on vision detection results used as sort keys.
@ RAW_DATA
Direct sorted data.
Axis-aligned bounding box in normalised image coordinates.
std::vector< glm::vec2 > points
Closed contour extracted from a binary mask.
T data
The actual computation data.
std::unordered_map< std::string, std::any > metadata
Associated metadata.
Input/Output container for computation pipeline data flow with structure preservation.
std::vector< Kinesis::Vision::Contour > contours
std::vector< Kinesis::Vision::BoundingBox > boxes
Context information controlling how a compute operation executes.
Analysis result produced by VisionAnalyzer for one frame.