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

◆ op_threshold_otsu()

GpuVisionPass::Completed MayaFlux::Yantra::VisionGpuExecutor::op_threshold_otsu ( VisionGpuContexts &  contexts,
const Kinesis::Vision::OtsuParams &  p 
)
private

Apply an Otsu threshold to the current image.

Computes the histogram and threshold on the GPU, then replaces the working image with the binary result and publishes it as VisionResult::images.threshold_otsu.

Returns
The resulting image and the image it was derived from.

Definition at line 37 of file VisionImageDispatch.cpp.

38{
39 auto& pixel_ctx = contexts.pixel;
40 auto w = contexts.pass.w;
41 auto h = contexts.pass.h;
43
44 const auto otsu_input = contexts.pass.current;
45
46 pixel_ctx.ensure_shared_buffer(0, 3, 768, GpuBufferBinding::ElementType::UINT32,
48 pixel_ctx.ensure_shared_buffer(0, 4, 3, GpuBufferBinding::ElementType::UINT32,
50
51 const std::array<uint32_t, 768> histogram_reset {};
52 pixel_ctx.upload_shared_raw(0, 3, reinterpret_cast<const uint8_t*>(histogram_reset.data()), sizeof(histogram_reset));
53
54 const auto channels = static_cast<uint32_t>(p.channels);
55 const OtsuHistPC hist_pc { .width = w, .height = h, .channels = channels };
56 const OtsuApplyPC apply_pc { .channels = channels };
57 const uint32_t select_groups = channels == 0U ? 1U : 3U;
58 const auto otsu_hazard = [](uint32_t binding) {
59 return [binding](GpuDispatchCore& ctx) {
60 return std::vector<HazardResource> {
61 ctx.shared_buffer_hazard({ .set = 0, .binding = binding, .direction = GpuBufferBinding::Direction::INPUT_OUTPUT, .element_type = GpuBufferBinding::ElementType::UINT32 }),
62 };
63 };
64 };
65 const std::array<uint32_t, 3> image_groups { (w + k_wg2d[0] - 1U) / k_wg2d[0], (h + k_wg2d[1] - 1U) / k_wg2d[1], 1U };
66
67 std::shared_ptr<Core::VKImage> thresholded;
68 std::vector<DependencyStage> otsu_stages;
69 otsu_stages.reserve(3);
70 otsu_stages.push_back({
71 .config = { .shader_path = "otsu_histogram.comp.spv", .workgroup_size = k_wg2d, .push_constant_size = sizeof(OtsuHistPC) },
72 .stage_fn = [&pixel_ctx, otsu_input, hist_pc](GpuDispatchCore& ctx) {
73 pixel_ctx.stage_image(otsu_input);
74 ctx.set_push_constants(hist_pc); },
75 .hazard_fn = otsu_hazard(3),
76 .explicit_groups = image_groups,
77 });
78 otsu_stages.push_back({
79 .config = { .shader_path = "otsu_select.comp.spv", .workgroup_size = { 256, 1, 1 } },
80 .stage_fn = [&pixel_ctx, otsu_input](GpuDispatchCore&) { pixel_ctx.stage_image(otsu_input); },
81 .hazard_fn = otsu_hazard(4),
82 .explicit_groups = std::array<uint32_t, 3> { select_groups, 1U, 1U },
83 });
84 otsu_stages.push_back({
85 .config = { .shader_path = "otsu_apply.comp.spv", .workgroup_size = k_wg2d, .push_constant_size = sizeof(OtsuApplyPC) },
86 .stage_fn = [&pixel_ctx, &thresholded, otsu_input, w, h, apply_pc](GpuDispatchCore& ctx) {
87 pixel_ctx.stage_image(otsu_input);
88 ctx.set_push_constants(apply_pc);
89 pixel_ctx.prepare_output_image(w, h);
90 thresholded = pixel_ctx.get_output_image(0); },
91 .explicit_groups = image_groups,
92 });
93
94 {
95 ExecutionContext otsu_ctx;
96 otsu_ctx.mode = ExecutionMode::DEPENDENCY;
97 DependencyParams otsu_params;
98 otsu_params.stages = otsu_stages;
99 otsu_params.async = true;
100 otsu_ctx.parameters = otsu_params;
101 const auto result = pixel_ctx.execute(Datum<> {}, otsu_ctx);
102 const auto f = result.get_metadata<FenceID>("gpu_fence").value_or(INVALID_FENCE);
103 foundry.wait_for_fence(f);
104 foundry.release_fence(f);
105 }
106
107 contexts.pass.result.images.threshold_otsu = thresholded;
108 contexts.pass.current = thresholded;
109 contexts.pass.result.structured = std::monostate {};
110
111 return { .output = thresholded, .input = otsu_input };
112}
uint32_t h
Definition InkPress.cpp:29
uint32_t channels
constexpr FenceID INVALID_FENCE
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
@ COMPUTE
Storage buffer for compute shaders (device-local)
constexpr std::array< uint32_t, 3 > k_wg2d
Standard 2D workgroup used by all pixel-to-pixel vision shaders.
@ DEPENDENCY
Part of dependency graph.

References MayaFlux::Yantra::DependencyParams::async, MayaFlux::Kinesis::Vision::OtsuParams::channels, channels, MayaFlux::Yantra::VisionInternal::OtsuApplyPC::channels, MayaFlux::Portal::Graphics::COMPUTE, MayaFlux::Kinesis::Vision::VisionPass< Handle >::current, MayaFlux::Yantra::DEPENDENCY, MayaFlux::Portal::Graphics::get_shader_foundry(), MayaFlux::Kinesis::Vision::VisionPass< Handle >::h, h, MayaFlux::Kinesis::Vision::VisionResult::images, MayaFlux::Portal::Graphics::GpuBufferBinding::INPUT_OUTPUT, MayaFlux::Portal::Graphics::INVALID_FENCE, MayaFlux::Yantra::VisionInternal::k_wg2d, MayaFlux::Yantra::ExecutionContext::mode, MayaFlux::Yantra::ExecutionContext::parameters, MayaFlux::Yantra::VisionGpuContexts::pass, MayaFlux::Yantra::VisionGpuContexts::pixel, MayaFlux::Kinesis::Vision::VisionPass< Handle >::result, MayaFlux::Yantra::DependencyParams::stages, MayaFlux::Kinesis::Vision::VisionResult::structured, MayaFlux::Kinesis::Vision::ImageOutputs::threshold_otsu, MayaFlux::Portal::Graphics::GpuBufferBinding::UINT32, MayaFlux::Kinesis::Vision::VisionPass< Handle >::w, and MayaFlux::Yantra::VisionInternal::OtsuHistPC::width.

+ Here is the call graph for this function: