Skip to content

Commit 9cd3491

Browse files
author
Kiriti
committed
feat(enhanced-vision): implement BilateralFilter kernel
- vxu_bilateral_filter_impl: spatial + range Gaussian filter for U8/S16 tensors - vxBilateralFilterNode: graph node constructor (5 params: src, diameter, sigma_space, sigma_values, dst) - vxuBilateralFilter: immediate-mode wrapper - Register kernel (0x38) in c_api.rs - Add dispatch in unified_c_api.rs + output param tracking - Builds clean, no regressions
1 parent 4258032 commit 9cd3491

3 files changed

Lines changed: 842 additions & 7 deletions

File tree

openvx-core/src/c_api.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ fn register_standard_kernels(context_id: u32) {
359359
("org.khronos.openvx.hough_lines_p", 0x34, 8),
360360
("org.khronos.openvx.match_template", 0x2D, 4),
361361
("org.khronos.openvx.lbp", 0x2E, 4),
362+
("org.khronos.openvx.bilateral_filter", 0x38, 5),
362363
// OpenVX 1.0.2 addition
363364
("org.khronos.openvx.weighted_average", 0x40, 4),
364365
// OpenVX 1.1 extensions

openvx-core/src/unified_c_api.rs

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,34 @@ fn read_scalar_enum(scalar: vx_scalar) -> Option<vx_enum> {
638638
}
639639
}
640640

641+
fn read_scalar_i32(scalar: vx_scalar) -> Option<i32> {
642+
if scalar.is_null() {
643+
return None;
644+
}
645+
unsafe {
646+
let s = &*(scalar as *const crate::c_api_data::VxCScalarData);
647+
if s.data.len() >= 4 {
648+
Some(i32::from_le_bytes([s.data[0], s.data[1], s.data[2], s.data[3]]))
649+
} else {
650+
None
651+
}
652+
}
653+
}
654+
655+
fn read_scalar_f32(scalar: vx_scalar) -> Option<f32> {
656+
if scalar.is_null() {
657+
return None;
658+
}
659+
unsafe {
660+
let s = &*(scalar as *const crate::c_api_data::VxCScalarData);
661+
if s.data.len() >= 4 {
662+
Some(f32::from_le_bytes([s.data[0], s.data[1], s.data[2], s.data[3]]))
663+
} else {
664+
None
665+
}
666+
}
667+
}
668+
641669
fn is_image_reference(ref_id: u64) -> bool {
642670
if let Ok(types) = REFERENCE_TYPES.lock() {
643671
if let Some(ref_type) = types.get(&(ref_id as usize)) {
@@ -1090,6 +1118,7 @@ pub extern "C" fn vxVerifyGraph(graph: vx_graph) -> vx_status {
10901118
("org.khronos.openvx.non_linear_filter", vec![3]), // [input, matrix, border, output]
10911119
// Enhanced Vision kernels
10921120
("org.khronos.openvx.copy", vec![1]), // [input, output] - param 1 is output
1121+
("org.khronos.openvx.bilateral_filter", vec![4]), // [src, diameter, sigma_space, sigma_values, dst]
10931122
("org.khronos.openvx.non_max_suppression", vec![3]), // [input, mask, win_size, output]
10941123
("org.khronos.openvx.hough_lines_p", vec![6, 7]), // [input, rho, theta, threshold, line_length, line_gap, lines_array, num_lines]
10951124
("org.khronos.openvx.match_template", vec![3]), // [src, templ, matching_method, output]
@@ -3272,6 +3301,33 @@ fn dispatch_kernel_with_border_impl(
32723301
VX_ERROR_INVALID_PARAMETERS
32733302
}
32743303
}
3304+
// BilateralFilter (Enhanced Vision)
3305+
"org.khronos.openvx.bilateral_filter" => {
3306+
if params.len() >= 5 {
3307+
let src = params[0] as vx_tensor;
3308+
let diameter_scalar = params[1] as vx_scalar;
3309+
let sigma_space_scalar = params[2] as vx_scalar;
3310+
let sigma_values_scalar = params[3] as vx_scalar;
3311+
let dst = params[4] as vx_tensor;
3312+
if !src.is_null() && !dst.is_null() {
3313+
let diameter = read_scalar_i32(diameter_scalar).unwrap_or(0);
3314+
let sigma_space = read_scalar_f32(sigma_space_scalar).unwrap_or(0.0);
3315+
let sigma_values = read_scalar_f32(sigma_values_scalar).unwrap_or(0.0);
3316+
crate::vxu_impl::vxu_bilateral_filter_impl(
3317+
unsafe { crate::c_api::vxGetContext(src as vx_reference) },
3318+
src as vx_reference,
3319+
diameter,
3320+
sigma_space,
3321+
sigma_values,
3322+
dst as vx_reference,
3323+
)
3324+
} else {
3325+
VX_ERROR_INVALID_PARAMETERS
3326+
}
3327+
} else {
3328+
VX_ERROR_INVALID_PARAMETERS
3329+
}
3330+
}
32753331
// Multiply
32763332
"org.khronos.openvx.multiply" => {
32773333
if params.len() >= 6 {
@@ -5148,11 +5204,11 @@ pub extern "C" fn vxRegisterPyramidLevelImage(
51485204
}
51495205

51505206
// Tensor registry
5151-
static TENSORS: Lazy<Mutex<HashMap<usize, Arc<VxCTensor>>>> =
5207+
pub static TENSORS: Lazy<Mutex<HashMap<usize, Arc<VxCTensor>>>> =
51525208
Lazy::new(|| Mutex::new(HashMap::new()));
51535209

51545210
// Tensor data storage (raw bytes keyed by tensor address)
5155-
static TENSOR_DATA: Lazy<Mutex<HashMap<usize, Vec<u8>>>> =
5211+
pub static TENSOR_DATA: Lazy<Mutex<HashMap<usize, Vec<u8>>>> =
51565212
Lazy::new(|| Mutex::new(HashMap::new()));
51575213

51585214
// Tensor context association
@@ -13258,22 +13314,61 @@ macro_rules! ev_vxu_stub {
1325813314
}
1325913315

1326013316
// ---- Image kernels still missing ----
13261-
ev_node_stub!(vxBilateralFilterNode(
13317+
#[no_mangle]
13318+
pub extern "C" fn vxBilateralFilterNode(
1326213319
graph: vx_graph,
1326313320
src: vx_tensor,
1326413321
diameter: vx_int32,
1326513322
sigma_space: vx_float32,
1326613323
sigma_values: vx_float32,
1326713324
dst: vx_tensor,
13268-
));
13269-
ev_vxu_stub!(vxuBilateralFilter(
13270-
context: vx_context,
13325+
) -> vx_node {
13326+
if graph.is_null() || src.is_null() || dst.is_null() {
13327+
return std::ptr::null_mut();
13328+
}
13329+
let context = crate::c_api::vxGetContext(graph as vx_reference);
13330+
if context.is_null() {
13331+
return std::ptr::null_mut();
13332+
}
13333+
unsafe {
13334+
let mut diameter_scalar = vxCreateScalar(context, VX_TYPE_INT32, &diameter as *const _ as *const c_void);
13335+
let mut sigma_space_scalar = vxCreateScalar(context, VX_TYPE_FLOAT32, &sigma_space as *const _ as *const c_void);
13336+
let mut sigma_values_scalar = vxCreateScalar(context, VX_TYPE_FLOAT32, &sigma_values as *const _ as *const c_void);
13337+
if diameter_scalar.is_null() || sigma_space_scalar.is_null() || sigma_values_scalar.is_null() {
13338+
vxReleaseScalar(&mut diameter_scalar);
13339+
vxReleaseScalar(&mut sigma_space_scalar);
13340+
vxReleaseScalar(&mut sigma_values_scalar);
13341+
return std::ptr::null_mut();
13342+
}
13343+
let node = create_node_with_params(
13344+
graph,
13345+
"org.khronos.openvx.bilateral_filter",
13346+
&[
13347+
src as vx_reference,
13348+
diameter_scalar as vx_reference,
13349+
sigma_space_scalar as vx_reference,
13350+
sigma_values_scalar as vx_reference,
13351+
dst as vx_reference,
13352+
],
13353+
);
13354+
vxReleaseScalar(&mut diameter_scalar);
13355+
vxReleaseScalar(&mut sigma_space_scalar);
13356+
vxReleaseScalar(&mut sigma_values_scalar);
13357+
node
13358+
}
13359+
}
13360+
13361+
#[no_mangle]
13362+
pub extern "C" fn vxuBilateralFilter(
13363+
_context: vx_context,
1327113364
src: vx_tensor,
1327213365
diameter: vx_int32,
1327313366
sigma_space: vx_float32,
1327413367
sigma_values: vx_float32,
1327513368
dst: vx_tensor,
13276-
));
13369+
) -> vx_status {
13370+
unsafe { crate::vxu_impl::vxu_bilateral_filter_impl(_context, src as vx_reference, diameter, sigma_space, sigma_values, dst as vx_reference) }
13371+
}
1327713372

1327813373
#[no_mangle]
1327913374
pub extern "C" fn vxLBPNode(

0 commit comments

Comments
 (0)