Add text_detection example, fixup other examples
MODIFY
.gitattributes
.gitattributes
-*.py linguist-vendored
*.hpp linguist-vendored
*.rs linguist-language=Rust

MODIFY
Cargo.toml
Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT"
version = "0.50.0"
edition = "2018"
authors = ["Pro <twisted.fall@gmail.com>", "Mathieu Poumeyrol <kali@zoy.org>"]
-autoexamples = false # cuda example doesn't compile on just any system
+autoexamples = false # not all examples compile on just any system
[lib]
doctest = false
@@ -20,9 +20,17 @@ maintenance = { status = "actively-developed" }
[workspace]
members = ["binding-generator"]
+# requires CUDA
+#[[example]]
+#name = "cuda"
+
[[example]]
name = "opencl"
+# requires OpenCV 4.5.1+
+#[[example]]
+#name = "text_detection"
+
[[example]]
name = "video_capture"

MODIFY
binding-generator/src/settings.rs
binding-generator/src/settings.rs
@@ -73,6 +73,7 @@ pub static FUNC_RENAME: Lazy<HashMap<&str, &str>> = Lazy::new(|| hashmap! {
"cv_Mat_Mat_Size_int" => "+_size",
"cv_Mat_Mat_Size_int_const_ScalarR" => "+_size_with_default",
"cv_Mat_Mat_Size_int_voidX_size_t" => "+_size_with_data",
+ "cv_Mat_Mat_const_GpuMatR" => "from_gpumat",
"cv_Mat_Mat_const_MatR_const_RangeR_const_RangeR" => "rowscols",
"cv_Mat_Mat_const_MatR_const_RectR" => "roi",
"cv_Mat_Mat_const_MatR_const_vector_Range_R" => "ranges",
@@ -352,8 +353,11 @@ pub static FUNC_RENAME: Lazy<HashMap<&str, &str>> = Lazy::new(|| hashmap! {
"cv_dnn_Net_connect_String_String" => "+_first_second",
"cv_dnn_Net_forward_const_StringR" => "+_single",
"cv_dnn_Net_forward_const__OutputArrayR_const_StringR" => "+_layer",
- "cv_dnn_Net_getMemoryConsumption_const_const_vector_MatShape_R_vector_int_R_vector_size_t_R_vector_size_t_R" => "+_for_layers",
"cv_dnn_Net_getMemoryConsumption_const_const_int_const_vector_MatShape_R_size_tR_size_tR" => "+_for_layer",
+ "cv_dnn_Net_getMemoryConsumption_const_const_vector_MatShape_R_vector_int_R_vector_size_t_R_vector_size_t_R" => "+_for_layers",
+ "cv_dnn_TextDetectionModel_EAST_TextDetectionModel_EAST_const_stringR_const_stringR" => "from_file",
+ "cv_dnn_TextDetectionModel_detect_const_const__InputArrayR_vector_vector_Point__R_vector_float_R" => "+_with_confidences",
+ "cv_dnn_TextRecognitionModel_TextRecognitionModel_const_stringR_const_stringR" => "from_file",
"cv_dnn_blobFromImage_const__InputArrayR_const__OutputArrayR_double_const_SizeR_const_ScalarR_bool_bool_int" => "+_to",
"cv_dnn_blobFromImages_const__InputArrayR_const__OutputArrayR_double_Size_const_ScalarR_bool_bool_int" => "+_to",
"cv_dnn_readNetFromCaffe_const_charX_size_t_const_charX_size_t" => "+_str",

ADD
examples/text_detection.rs
+//! Port of https://github.com/opencv/opencv/blob/master/samples/dnn/text_detection.cpp
+//! Check the source cpp file for where to get the NN files.
+
+use std::{
+ error::Error,
+ fs::File,
+ io::{BufRead, BufReader},
+ path::PathBuf,
+};
+
+use opencv::{
+ core::{self, Point2f, Scalar, Size},
+ dnn,
+ highgui,
+ imgproc,
+ prelude::*,
+ types::{VectorOfPoint2f, VectorOfString, VectorOfVectorOfPoint},
+ videoio,
+};
+
+type Result<T, E = Box<dyn Error>> = std::result::Result<T, E>;
+
+fn main() -> Result<()> {
+ // Parameters.
+ let conf_threshold = 0.5;
+ let nms_threshold = 0.4;
+ let width = 320;
+ let height = 320;
+ let imread_rgb = false;
+ let det_model_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("frozen_east_text_detection.pb");
+ let rec_model_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("crnn.onnx");
+ let voc_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("alphabet_36.txt");
+
+ // Load networks.
+ let mut detector = dnn::TextDetectionModel_EAST::from_file(det_model_path.to_str().unwrap(), "")?;
+ detector.set_confidence_threshold(conf_threshold)?
+ .set_nms_threshold(nms_threshold)?;
+ let mut recognizer = dnn::TextRecognitionModel::from_file(rec_model_path.to_str().unwrap(), "")?;
+
+ // Load vocabulary
+ let mut vocabulary = VectorOfString::new();
+ let voc_file = BufReader::new(File::open(voc_path)?);
+ for voc_line in voc_file.lines() {
+ vocabulary.push(&voc_line?);
+ }
+ recognizer.set_vocabulary(&vocabulary)?
+ .set_decode_type("CTC-greedy")?;
+
+ // Parameters for Recognition
+ let rec_scale = 1. / 127.5;
+ let rec_mean = Scalar::from((127.5, 127.5, 127.5));
+ let rec_input_size = Size::new(100, 32);
+ recognizer.set_input_params(rec_scale, rec_input_size, rec_mean, false, false)?;
+
+ // Parameters for Detection
+ let det_scale = 1.;
+ let det_input_size = Size::new(width, height);
+ let det_mean = Scalar::from((123.68, 116.78, 103.94));
+ let swap_rb = true;
+ detector.set_input_params(det_scale, det_input_size, det_mean, swap_rb, false)?;
+
+ // Open a video file or an image file or a camera stream.
+ let mut cap = videoio::VideoCapture::new(0, videoio::CAP_ANY)?;
+ let open_success = videoio::VideoCapture::is_opened(&cap)?;
+ if !open_success {
+ panic!("Unable to open default camera!");
+ }
+ let win_name = "EAST: An Efficient and Accurate Scene Text Detector";
+ let mut frame = Mat::default()?;
+ while highgui::wait_key(1)? < 0 {
+ cap.read(&mut frame)?;
+ if frame.empty()? {
+ highgui::wait_key(0)?;
+ break;
+ }
+ println!("Frame size: {:?}", frame.size()?);
+ // Detection
+ let mut det_results = VectorOfVectorOfPoint::new();
+ detector.detect(&frame, &mut det_results)?;
+
+ if !det_results.is_empty() {
+ // Text Recognition
+ let rec_input = if !imread_rgb {
+ let mut rec_input = Mat::default()?;
+ imgproc::cvt_color(&frame, &mut rec_input, imgproc::COLOR_BGR2GRAY, 0)?;
+ Some(rec_input)
+ } else {
+ None
+ };
+ let mut contours = VectorOfVectorOfPoint::new();
+ for quadrangle in &det_results {
+ let mut quadrangle_2f = VectorOfPoint2f::new();
+ for pt in &quadrangle {
+ quadrangle_2f.push(Point2f::new(pt.x as f32, pt.y as f32))
+ }
+ let cropped = four_points_transform(rec_input.as_ref().unwrap_or(&frame), quadrangle_2f.as_slice())?;
+ let recognition_result = recognizer.recognize(&cropped)?;
+ println!("Recognition result: {}", recognition_result);
+ imgproc::put_text(&mut frame, &recognition_result, quadrangle.get(3)?, imgproc::FONT_HERSHEY_SIMPLEX, 1.5, Scalar::from((0., 0., 255.)), 2, imgproc::LINE_8, false)?;
+ contours.push(quadrangle);
+ }
+ imgproc::polylines(&mut frame, &contours, true, Scalar::from((0., 255., 0.)), 2, imgproc::LINE_8, 0)?;
+ }
+ let mut big_frame = Mat::default()?;
+ imgproc::resize(&frame, &mut big_frame, Size::default(), 3., 3., imgproc::INTER_NEAREST)?;
+ highgui::imshow(win_name, &mut big_frame)?;
+ }
+ Ok(())
+}
+
+fn four_points_transform(frame: &Mat, vertices: &[Point2f]) -> Result<Mat> {
+ let output_size = Size::new(100, 32);
+ let target_vertices = [
+ Point2f::new(0., (output_size.height - 1) as f32),
+ Point2f::new(0., 0.),
+ Point2f::new((output_size.width - 1) as f32, 0.),
+ Point2f::new((output_size.width - 1) as f32, (output_size.height - 1) as f32),
+ ];
+ let rotation_matrix = imgproc::get_perspective_transform_slice(&vertices, &target_vertices, core::DECOMP_LU)?;
+ let mut out = Mat::default()?;
+ imgproc::warp_perspective(frame, &mut out, &rotation_matrix, output_size, imgproc::INTER_LINEAR, core::BORDER_CONSTANT, Scalar::default())?;
+ Ok(out)
+}

MODIFY
examples/video_capture.rs
examples/video_capture.rs
-extern crate opencv;
-
use opencv::{
core,
highgui,
prelude::*,
+ Result,
videoio,
};
-fn run() -> opencv::Result<()> {
+fn main() -> Result<()> {
let window = "video capture";
- highgui::named_window(window, 1)?;
+ highgui::named_window(window, highgui::WINDOW_AUTOSIZE)?;
#[cfg(feature = "opencv-32")]
let mut cam = videoio::VideoCapture::new_default(0)?; // 0 is the default camera
#[cfg(not(feature = "opencv-32"))]
@@ -19,7 +18,7 @@ fn run() -> opencv::Result<()> {
panic!("Unable to open default camera!");
}
loop {
- let mut frame = core::Mat::default()?;
+ let mut frame = Mat::default()?;
cam.read(&mut frame)?;
if frame.size()?.width > 0 {
highgui::imshow(window, &mut frame)?;
@@ -31,7 +30,3 @@ fn run() -> opencv::Result<()> {
}
Ok(())
}
-
-fn main() {
- run().unwrap()
-}

MODIFY
examples/video_facedetect.rs
examples/video_facedetect.rs
@@ -6,11 +6,12 @@ use opencv::{
imgproc,
objdetect,
prelude::*,
+ Result,
types,
videoio,
};
-fn run() -> opencv::Result<()> {
+fn main() -> Result<()> {
let window = "video capture";
highgui::named_window(window, 1)?;
#[cfg(feature = "opencv-32")]
@@ -44,7 +45,7 @@ fn run() -> opencv::Result<()> {
&frame,
&mut gray,
imgproc::COLOR_BGR2GRAY,
- 0
+ 0,
)?;
let mut reduced = Mat::default()?;
imgproc::resize(
@@ -52,11 +53,11 @@ fn run() -> opencv::Result<()> {
&mut reduced,
core::Size {
width: 0,
- height: 0
+ height: 0,
},
0.25f64,
0.25f64,
- imgproc::INTER_LINEAR
+ imgproc::INTER_LINEAR,
)?;
let mut faces = types::VectorOfRect::new();
face.detect_multi_scale(
@@ -67,12 +68,12 @@ fn run() -> opencv::Result<()> {
objdetect::CASCADE_SCALE_IMAGE,
core::Size {
width: 30,
- height: 30
+ height: 30,
},
core::Size {
width: 0,
- height: 0
- }
+ height: 0,
+ },
)?;
println!("faces: {}", faces.len());
for face in faces {
@@ -89,7 +90,7 @@ fn run() -> opencv::Result<()> {
core::Scalar::new(0f64, -1f64, -1f64, -1f64),
1,
8,
- 0
+ 0,
)?;
}
highgui::imshow(window, &frame)?;
@@ -99,7 +100,3 @@ fn run() -> opencv::Result<()> {
}
Ok(())
}
-
-fn main() {
- run().unwrap()
-}

MODIFY
examples/video_features.rs
examples/video_features.rs
@@ -5,10 +5,11 @@ use opencv::{
highgui,
imgproc,
prelude::*,
+ Result,
videoio,
};
-fn run() -> opencv::Result<()> {
+fn main() -> Result<()> {
let window = "video capture";
highgui::named_window(window, 1)?;
#[cfg(feature = "opencv-32")]
@@ -21,21 +22,20 @@ fn run() -> opencv::Result<()> {
}
let mut orb = features2d::ORB::default()?;
loop {
- let mut frame = core::Mat::default()?;
+ let mut frame = Mat::default()?;
cam.read(&mut frame)?;
if frame.size()?.width > 0 {
- let mut gray = core::Mat::default()?;
+ let mut gray = Mat::default()?;
imgproc::cvt_color(
&frame,
&mut gray,
imgproc::COLOR_BGR2GRAY,
- 0
+ 0,
)?;
let mut kps = opencv::types::VectorOfKeyPoint::new();
- // let mut desc = try!(core::Mat::new());
- let mask = core::Mat::default()?;
+ let mask = Mat::default()?;
orb.detect(&gray, &mut kps, &mask)?;
- let mut display = core::Mat::default()?;
+ let mut display = Mat::default()?;
#[cfg(not(feature = "opencv-4"))]
let default_draw_matches_flags = features2d::DrawMatchesFlags_DEFAULT;
#[cfg(feature = "opencv-4")]
@@ -45,7 +45,7 @@ fn run() -> opencv::Result<()> {
&kps,
&mut display,
core::Scalar::all(-1f64),
- default_draw_matches_flags
+ default_draw_matches_flags,
)?;
highgui::imshow(window, &display)?;
}
@@ -55,7 +55,3 @@ fn run() -> opencv::Result<()> {
}
Ok(())
}
-
-fn main() {
- run().unwrap()
-}

MODIFY
examples/video_to_gray.rs
examples/video_to_gray.rs
-extern crate opencv;
-
use opencv::{
core,
highgui,
imgproc,
prelude::*,
+ Result,
videoio,
};
-fn run() -> opencv::Result<()> {
+fn main() -> Result<()> {
let window = "video capture";
highgui::named_window(window, 1)?;
#[cfg(feature = "opencv-32")]
@@ -20,15 +19,15 @@ fn run() -> opencv::Result<()> {
panic!("Unable to open default camera!");
}
loop {
- let mut frame = core::Mat::default()?;
+ let mut frame = Mat::default()?;
cam.read(&mut frame)?;
if frame.size()?.width > 0 {
- let mut gray = core::Mat::default()?;
+ let mut gray = Mat::default()?;
imgproc::cvt_color(
&frame,
&mut gray,
imgproc::COLOR_BGR2GRAY,
- 0
+ 0,
)?;
highgui::imshow(window, &gray)?;
}
@@ -38,7 +37,3 @@ fn run() -> opencv::Result<()> {
}
Ok(())
}
-
-fn main() {
- run().unwrap()
-}

MODIFY
examples/warp_perspective_demo.rs
examples/warp_perspective_demo.rs
@@ -4,7 +4,8 @@ use std::{
sync::{
Arc,
atomic::{AtomicBool, Ordering},
- Mutex},
+ Mutex
+ },
};
use opencv::{
@@ -97,7 +98,6 @@ fn main() -> Result<(), Box<dyn Error>> {
roi_corners.set(selected_corner_index, Point::new(x, y)).unwrap();
validation_needed.store(true, Ordering::Relaxed);
}
-
}
}
})))?;

MODIFY
examples/window.rs
examples/window.rs
-extern crate opencv;
-use opencv::highgui;
-use opencv::imgcodecs;
+use opencv::{
+ highgui,
+ imgcodecs,
+ Result,
+};
-#[allow(dead_code)]
-fn main() {
- let image = imgcodecs::imread("lena.jpg", 0).unwrap();
- highgui::named_window("hello opencv!", 0).unwrap();
- highgui::imshow("hello opencv!", &image).unwrap();
- highgui::wait_key(10000).unwrap();
+fn main() -> Result<()> {
+ let image = imgcodecs::imread("lena.jpg", 0)?;
+ highgui::named_window("hello opencv!", 0)?;
+ highgui::imshow("hello opencv!", &image)?;
+ highgui::wait_key(10000)?;
+ Ok(())
}

MODIFY
src/manual/core/vec.rs
src/manual/core/vec.rs
@@ -27,12 +27,14 @@ macro_rules! vec_impl {
pub struct $type<T: $type_trait>(pub [T; $count]);
impl<T: $type_trait> $type<T> {
+ #[inline]
pub fn all(v0: T) -> Self {
Self::from([v0; $count])
}
}
impl<T: $type_trait> From<[T; $count]> for $type<T> {
+ #[inline]
fn from(s: [T; $count]) -> Self {
Self(s)
}
@@ -41,12 +43,14 @@ macro_rules! vec_impl {
impl<T: $type_trait> std::ops::Deref for $type<T> {
type Target = [T; $count];
+ #[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: $type_trait> std::ops::DerefMut for $type<T> {
+ #[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
@@ -65,17 +69,40 @@ vec_impl!(Vec18, 18, ValidVecType);
vec_impl!(Scalar_, 4, ValidScalarType);
impl<T: ValidScalarType> Scalar_<T> {
+ #[inline]
pub fn new(v0: T, v1: T, v2: T, v3: T) -> Self {
Self::from([v0, v1, v2, v3])
}
}
impl<T: ValidScalarType> From<T> for Scalar_<T> {
+ #[inline]
fn from(v0: T) -> Self {
Self::from([v0, T::zero(), T::zero(), T::zero()])
}
}
+impl<T: ValidScalarType> From<(T, T)> for Scalar_<T> {
+ #[inline]
+ fn from(v: (T, T)) -> Self {
+ Self::from([v.0, v.1, T::zero(), T::zero()])
+ }
+}
+
+impl<T: ValidScalarType> From<(T, T, T)> for Scalar_<T> {
+ #[inline]
+ fn from(v: (T, T, T)) -> Self {
+ Self::from([v.0, v.1, v.2, T::zero()])
+ }
+}
+
+impl<T: ValidScalarType> From<(T, T, T, T)> for Scalar_<T> {
+ #[inline]
+ fn from(v: (T, T, T, T)) -> Self {
+ Self::from([v.0, v.1, v.2, v.3])
+ }
+}
+
impl ToInputArray for Scalar_<f64> {
fn input_array(&self) -> Result<_InputArray> {
extern "C" { fn cv_Scalar_input_array(instance: *const Scalar_<f64>) -> sys::Result<*mut c_void>; }

Add text_detection example, fixup other examples