-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
172 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "hog-detector" | ||
version = "0.5.0" | ||
version = "0.6.0" | ||
edition = "2021" | ||
description = "Histogram of Oriented Gradients and Object Detection" | ||
authors = ["Christian <[email protected]>"] | ||
|
@@ -24,8 +24,9 @@ name = "bin" | |
path = "src/main.rs" | ||
|
||
[features] | ||
default = ["wasm"] | ||
default = ["wasm", "svm"] | ||
brief = ["dep:brief-rs"] | ||
svm = ["svm-burns"] | ||
mnist = ["dep:mnist"] | ||
eyes = ["reqwest", "zip"] | ||
wasm = [ | ||
|
@@ -68,6 +69,7 @@ smartcore = { version = "0.3.0", features = [ | |
"ndarray-bindings", | ||
"serde", | ||
], default-features = false, git = "https://github.com/smartcorelib/smartcore", branch = "fix-245" } | ||
svm-burns = { git = "https://github.com/chriamue/svm-burns", optional = true} | ||
zip = { version = "0.6.6", default-features = false, features = [ | ||
"deflate", | ||
], optional = true } | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
/// naive bayes classifier module | ||
pub mod bayes; | ||
|
||
#[cfg(feature = "svm")] | ||
/// svm classifier module | ||
pub mod svm; | ||
pub use bayes::BayesClassifier; | ||
pub use object_detector_rust::prelude::Classifier; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
use std::fmt::Debug; | ||
|
||
use ndarray::{Array1, ArrayView1, ArrayView2}; | ||
use object_detector_rust::{ | ||
classifier::Classifier, predictable::Predictable, trainable::Trainable, | ||
window_generator::PyramidWindow, | ||
}; | ||
use serde::{Serialize, Deserialize}; | ||
use svm_burns::{svm::SVM, Parameters, RBFKernel, SVC}; | ||
|
||
use crate::HogDetector; | ||
|
||
/// A support vector machine classifier | ||
#[derive(Default, Serialize, Deserialize)] | ||
pub struct SVMClassifier { | ||
model: Option<SVC>, | ||
} | ||
|
||
impl Debug for SVMClassifier { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
f.debug_struct("SVMClassifier").finish() | ||
} | ||
} | ||
|
||
impl SVMClassifier { | ||
/// Creates a new `SVMClassifier` | ||
pub fn new() -> Self { | ||
SVMClassifier { model: None } | ||
} | ||
} | ||
|
||
impl PartialEq for SVMClassifier { | ||
fn eq(&self, other: &SVMClassifier) -> bool { | ||
self.model.is_none() && other.model.is_none() | ||
|| self.model.is_some() && other.model.is_some() | ||
} | ||
} | ||
|
||
impl HogDetector<f32, usize, SVMClassifier, PyramidWindow> { | ||
/// new default svm detector | ||
pub fn svm() -> Self { | ||
HogDetector::<f32, usize, SVMClassifier, PyramidWindow>::default() | ||
} | ||
} | ||
|
||
impl Trainable<f32, usize> for SVMClassifier { | ||
fn fit(&mut self, x: &ArrayView2<f32>, y: &ArrayView1<usize>) -> Result<(), String> { | ||
let x_vec: Vec<Vec<f64>> = x | ||
.outer_iter() | ||
.map(|row| row.iter().map(|&elem| elem as f64).collect()) | ||
.collect(); | ||
|
||
let y_vec: Vec<i32> = y.iter().map(|&elem| elem as i32).collect(); | ||
|
||
let mut parameters = Parameters::default(); | ||
parameters.with_kernel(Box::new(RBFKernel::new(0.7))); | ||
let mut svc = SVC::new(parameters); | ||
|
||
svc.fit(&x_vec, &y_vec); | ||
self.model = Some(svc); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl Predictable<f32, usize> for SVMClassifier { | ||
fn predict(&self, x: &ArrayView2<f32>) -> Result<Array1<usize>, String> { | ||
let x_vec: Vec<Vec<f64>> = x | ||
.outer_iter() | ||
.map(|row| row.iter().map(|&elem| elem as f64).collect()) | ||
.collect(); | ||
let prediction = self.model.as_ref().unwrap().predict(&x_vec); | ||
let prediction: Vec<usize> = prediction | ||
.iter() | ||
.map(|&x| if x > 0 { 1 } else { 0 }) | ||
.collect(); | ||
Ok(Array1::from(prediction)) | ||
} | ||
} | ||
|
||
impl Classifier<f32, usize> for SVMClassifier {} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::hogdetector::HogDetectorTrait; | ||
use image::Rgb; | ||
use object_detector_rust::dataset::DataSet; | ||
use object_detector_rust::detector::Detector; | ||
use object_detector_rust::{prelude::MemoryDataSet, tests::test_image}; | ||
|
||
#[test] | ||
fn test_default() { | ||
let classifier = super::SVMClassifier::default(); | ||
assert!(classifier.model.is_none()); | ||
} | ||
|
||
#[test] | ||
fn test_partial_eq() { | ||
let detector1 = HogDetector::<f32, usize, super::SVMClassifier, _>::default(); | ||
let detector2 = HogDetector::<f32, usize, super::SVMClassifier, _>::svm(); | ||
assert!(detector1.eq(&detector2)); | ||
} | ||
|
||
#[test] | ||
fn test_detector() { | ||
let img = test_image(); | ||
let mut dataset = MemoryDataSet::new_test(); | ||
dataset.load().unwrap(); | ||
let (x, y) = dataset.get_data(); | ||
let x = x.into_iter().map(|x| x.thumbnail_exact(32, 32)).collect(); | ||
let y = y.into_iter().map(|y| y as usize).collect::<Vec<_>>(); | ||
|
||
let mut detector: HogDetector<f32, usize, super::SVMClassifier, _> = HogDetector::default(); | ||
detector.fit_class(&x, &y, 1).unwrap(); | ||
let detections = detector.detect(&img); | ||
assert!(detections.is_empty()); | ||
let visualization = detector.visualize_detections(&img).to_rgb8(); | ||
assert_eq!(&Rgb([0, 0, 0]), visualization.get_pixel(55, 0)); | ||
assert_eq!(&Rgb([255, 0, 0]), visualization.get_pixel(75, 0)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters