Skip to content

Commit c52a904

Browse files
committed
harris, nearest_neighbour, susan and dog functions in vision module
1 parent 8e7c9f4 commit c52a904

File tree

2 files changed

+174
-1
lines changed

2 files changed

+174
-1
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,5 @@ mod statistics;
8888
mod util;
8989

9090
pub use vision::Features;
91-
pub use vision::{fast, orb, hamming_matcher, match_template};
91+
pub use vision::{fast, harris, orb, hamming_matcher, nearest_neighbour, match_template, susan, dog};
9292
mod vision;

src/vision/mod.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,24 @@ extern {
2626
fn af_fast(out: MutFeat, input: AfArray, thr: c_float, arc_len: c_uint, non_max: c_int,
2727
feature_ratio: c_float, edge: c_uint) -> c_int;
2828

29+
fn af_harris(out: MutFeat, input: AfArray, m: c_uint, r: c_float, s: c_float, bs: c_uint, k: c_float) -> c_int;
30+
2931
fn af_orb(out: MutFeat, desc: MutAfArray, arr: AfArray, fast_thr: c_float, max_feat: c_uint,
3032
scl_fctr: c_float, levels: c_uint, blur_img: c_int) -> c_int;
3133

3234
fn af_hamming_matcher(idx: MutAfArray, dist: MutAfArray,
3335
query: AfArray, train: AfArray,
3436
dist_dim: DimT, n_dist: c_uint) -> c_int;
3537

38+
fn af_nearest_neighbour(idx: MutAfArray, dist: MutAfArray, q: AfArray, t: AfArray,
39+
dist_dim: DimT, n_dist: c_uint, dist_type: c_int) -> c_int;
40+
3641
fn af_match_template(out: MutAfArray, search_img: AfArray, template_img: AfArray,
3742
mtype: uint8_t) -> c_int;
43+
44+
fn af_susan(feat: MutFeat, i: AfArray, r: c_uint, d: c_float, g: c_float, f: c_float, e: c_uint) -> c_int;
45+
46+
fn af_dog(out: MutAfArray, i: AfArray, r1: c_int, r2: c_int) -> c_int;
3847
}
3948

4049
/// A set of Array objects (usually, used in Computer vision context)
@@ -174,6 +183,42 @@ pub fn fast(input: &Array, thr: f32, arc_len: u32,
174183
}
175184
}
176185

186+
/// Harris corner detector.
187+
///
188+
/// Compute corners using the Harris corner detector approach. For each pixel, a small window is
189+
/// used to calculate the determinant and trace of such a window, from which a response is
190+
/// calculated. Pixels are considered corners if they are local maximas and have a high positive
191+
/// response.
192+
///
193+
/// # Parameters
194+
///
195+
/// - `input` is the array containing a grayscale image (color images are not supported)
196+
/// - `max_corners` is the maximum number of corners to keep, only retains those with highest Harris responses
197+
/// - `min_response` is the minimum response in order for a corner to be retained, only used if max_corners = 0
198+
/// - `sigma` is the standard deviation of a circular window (its dimensions will be calculated according to the standard deviation), the covariation matrix will be calculated to a circular neighborhood of this standard deviation (only used when block_size == 0, must be >= 0.5f and <= 5.0f)
199+
/// - `block_size` is square window size, the covariation matrix will be calculated to a square neighborhood of this size (must be >= 3 and <= 31)
200+
/// - `k_thr` is the Harris constant, usually set empirically to 0.04f (must be >= 0.01f)
201+
///
202+
/// # Return Values
203+
///
204+
/// This function returns an object of struct [Features](./struct.Features.html) containing Arrays
205+
/// for x and y coordinates and score, while array oreientation & size are set to 0 & 1,
206+
/// respectively, since harris doesn't compute that information
207+
#[allow(unused_mut)]
208+
pub fn harris(input: &Array, max_corners: u32, min_response: f32, sigma: f32, block_size: u32, k_thr: f32) -> Result<Features, AfError> {
209+
unsafe {
210+
let mut temp: i64 = 0;
211+
let err_val = af_harris(&mut temp as *mut c_longlong as MutFeat,
212+
input.get() as AfArray, max_corners as c_uint,
213+
min_response as c_float, sigma as c_float, block_size as c_uint,
214+
k_thr as c_float);
215+
match err_val {
216+
0 => Ok(Features {feat: temp}),
217+
_ => Err(AfError::from(err_val)),
218+
}
219+
}
220+
}
221+
177222
/// ORB feature descriptor
178223
///
179224
/// Extract ORB descriptors from FAST features that hold higher Harris responses. FAST does not
@@ -260,6 +305,53 @@ pub fn hamming_matcher(query: &Array, train: &Array,
260305
}
261306
}
262307

308+
/// Nearest Neighbour.
309+
///
310+
/// Calculates nearest distances between two 2-dimensional arrays containing features based on the
311+
/// type of distance computation chosen. Currently, AF_SAD (sum of absolute differences), AF_SSD
312+
/// (sum of squared differences) and AF_SHD (hamming distance) are supported. One of the arrays
313+
/// containing the training data and the other the query data. One of the dimensions of the both
314+
/// arrays must be equal among them, identifying the length of each feature. The other dimension
315+
/// indicates the total number of features in each of the training and query arrays. Two
316+
/// 1-dimensional arrays are created as results, one containg the smallest N distances of the query
317+
/// array and another containing the indices of these distances in the training array. The resulting
318+
/// 1-dimensional arrays have length equal to the number of features contained in the query array.
319+
///
320+
/// # Parameters
321+
///
322+
/// - `query` is the array containing the data to be queried
323+
/// - `train` is the array containing the data used as training data
324+
/// - `dist_dim` indicates the dimension to analyze for distance (the dimension indicated here must be of equal length for both query and train arrays)
325+
/// - `n_dist` is the number of smallest distances to return (currently, only 1 is supported)
326+
/// - `dist_type` is the distance computation type. Currently [`MatchType::SAD`](./enum.MatchType.html), [`MatchType::SSD`](./enum.MatchType.html), and [`MatchType::SHD`](./enum.MatchType.html) are supported.
327+
///
328+
/// # Return Values
329+
///
330+
/// A tuple of Arrays.
331+
///
332+
/// The first Array is is an array of MxN size, where M is equal to the number of query features
333+
/// and N is equal to `n_dist`. The value at position IxJ indicates the index of the Jth smallest
334+
/// distance to the Ith query value in the train data array. the index of the Ith smallest distance
335+
/// of the Mth query.
336+
///
337+
/// The second Array is is an array of MxN size, where M is equal to the number of query features
338+
/// and N is equal to `n_dist`. The value at position IxJ indicates the distance of the Jth smallest
339+
/// distance to the Ith query value in the train data array based on the `dist_type` chosen.
340+
#[allow(unused_mut)]
341+
pub fn nearest_neighbour(query: &Array, train: &Array, dist_dim: i64, n_dist: u32, dist_type: MatchType) -> Result<(Array, Array), AfError> {
342+
unsafe {
343+
let mut idx: i64 = 0;
344+
let mut dist: i64 = 0;
345+
let err_val = af_nearest_neighbour(&mut idx as MutAfArray, &mut dist as MutAfArray,
346+
query.get() as AfArray, train.get() as AfArray,
347+
dist_dim as DimT, n_dist as c_uint, dist_type as c_int);
348+
match err_val {
349+
0 => Ok((Array::from(idx), Array::from(dist))),
350+
_ => Err(AfError::from(err_val)),
351+
}
352+
}
353+
}
354+
263355
/// Image matching
264356
///
265357
/// Template matching is an image processing technique to find small patches of an image which
@@ -288,3 +380,84 @@ pub fn match_template(search_img: &Array, template_img: &Array,
288380
}
289381
}
290382
}
383+
384+
/// SUSAN corner detector.
385+
///
386+
/// SUSAN is an acronym standing for Smallest Univalue Segment Assimilating Nucleus. This method
387+
/// places a circular disc over the pixel to be tested (a.k.a nucleus) to compute the corner
388+
/// measure of that corresponding pixel. The region covered by the circular disc is M, and a pixel
389+
/// in this region is represented by m⃗ ∈M where m⃗ 0 is the nucleus. Every pixel in the region is
390+
/// compared to the nucleus using the following comparison function:
391+
///
392+
/// c(m⃗ )=e^−((I(m⃗)−I(m⃗_0))/t)^6
393+
///
394+
/// where t is radius of the region, I is the brightness of the pixel.
395+
///
396+
/// Response of SUSAN operator is given by the following equation:
397+
///
398+
/// R(M) = g−n(M) if n(M) < g
399+
///
400+
/// R(M) = 0 otherwise,
401+
///
402+
/// where n(M)=∑c(m⃗) m⃗∈M, g is named the geometric threshold and n is the number of pixels in the
403+
/// mask which are within t of the nucleus.
404+
///
405+
/// Importance of the parameters, t and g is explained below:
406+
///
407+
/// - t determines how similar points have to be to the nucleusbefore they are considered to be a
408+
/// part of the univalue segment
409+
/// - g determines the minimum size of the univalue segment. For a large enough g, SUSAN operator
410+
/// becomes an edge dectector.
411+
///
412+
/// # Parameters
413+
///
414+
/// - `input` is input grayscale/intensity image
415+
/// - `radius` is the nucleus radius for each pixel neighborhood
416+
/// - `diff_thr` is intensity difference threshold a.k.a **t** from equations in description
417+
/// - `geom_thr` is the geometric threshold
418+
/// - `feature_ratio` is maximum number of features that will be returned by the function
419+
/// - `edge` indicates how many pixels width area should be skipped for corner detection
420+
///
421+
/// # Return Values
422+
/// An object of type [Features](./struct.Features.html) composed of arrays for x and y coordinates, score, orientation and size of selected features.
423+
#[allow(unused_mut)]
424+
pub fn susan(input: &Array, radius: u32, diff_thr: f32, geom_thr: f32, feature_ratio: f32, edge: u32) -> Result<Features, AfError> {
425+
unsafe {
426+
let mut temp: i64 = 0;
427+
let err_val = af_susan(&mut temp as *mut c_longlong as MutFeat,
428+
input.get() as AfArray, radius as c_uint,
429+
diff_thr as c_float, geom_thr as c_float, feature_ratio as c_float,
430+
edge as c_uint);
431+
match err_val {
432+
0 => Ok(Features {feat: temp}),
433+
_ => Err(AfError::from(err_val)),
434+
}
435+
}
436+
}
437+
438+
/// Difference of Gaussians.
439+
///
440+
/// Given an image, this function computes two different versions of smoothed input image using the
441+
/// difference smoothing parameters and subtracts one from the other and returns the result.
442+
///
443+
/// # Parameters
444+
///
445+
/// - `input` is the input image
446+
/// - `radius1` is the radius of the first gaussian kernel
447+
/// - `radius2` is the radius of the second gaussian kernel
448+
///
449+
/// # Return Values
450+
///
451+
/// Difference of smoothed inputs - An Array.
452+
#[allow(unused_mut)]
453+
pub fn dog(input: &Array, radius1: i32, radius2: i32) -> Result<Array, AfError> {
454+
unsafe {
455+
let mut temp: i64 = 0;
456+
let err_val = af_dog(&mut temp as MutAfArray, input.get() as AfArray,
457+
radius1 as c_int, radius2 as c_int);
458+
match err_val {
459+
0 => Ok(Array::from(temp)),
460+
_ => Err(AfError::from(err_val)),
461+
}
462+
}
463+
}

0 commit comments

Comments
 (0)