use bytes::{self, ByteOrder};
use errors::*;
use failure::Error;
use num;
use std::ffi::CString;
use std::mem;
use std::os::raw::{c_char, c_double, c_int, c_uchar, c_void};
use std::slice;
#[derive(Clone, Copy, Debug)]
pub enum CMat {}
unsafe impl Send for CMat {}
impl CMat {
pub fn new() -> *mut CMat {
unsafe { cv_mat_new() }
}
}
#[derive(Debug)]
pub struct Mat {
pub inner: *mut CMat,
pub cols: i32,
pub rows: i32,
pub depth: i32,
pub channels: i32,
}
unsafe impl Send for Mat {}
#[derive(Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct Scalar {
v0: i32,
v1: i32,
v2: i32,
v3: i32,
}
impl Scalar {
pub fn new(v0: i32, v1: i32, v2: i32, v3: i32) -> Self {
Scalar {
v0: v0,
v1: v1,
v2: v2,
v3: v3,
}
}
pub fn all(v: i32) -> Self {
Scalar {
v0: v,
v1: v,
v2: v,
v3: v,
}
}
}
#[derive(Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct Point2i {
pub x: i32,
pub y: i32,
}
impl Point2i {
pub fn new(x: i32, y: i32) -> Self {
Point2i { x: x, y: y }
}
}
#[derive(Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct Point2f {
pub x: f32,
pub y: f32,
}
impl Point2f {
pub fn new(x: f32, y: f32) -> Self {
Point2f { x: x, y: y }
}
}
#[derive(Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct Size2i {
pub width: i32,
pub height: i32,
}
impl Size2i {
pub fn new(width: i32, height: i32) -> Self {
Size2i {
width: width,
height: height,
}
}
}
#[derive(Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct Size2f {
pub width: f32,
pub height: f32,
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct Rect {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
}
impl Rect {
pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self {
Rect {
x: x,
y: y,
width: width,
height: height,
}
}
pub fn scale(&self, ratio: f32) -> Rect {
let new_x = ((1.0 - ratio) * (self.width as f32) / 2.0) as i32 + self.x;
let new_y = ((1.0 - ratio) * (self.height as f32) / 2.0) as i32 + self.y;
let new_w = ((self.width as f32) * ratio) as i32;
let new_h = ((self.height as f32) * ratio) as i32;
Rect {
x: new_x,
y: new_y,
width: new_w,
height: new_h,
}
}
pub fn normalize_to_mat(&self, mat: &Mat) -> Rect2f {
Rect2f {
x: (self.x as f32) / (mat.cols as f32),
y: (self.y as f32) / (mat.rows as f32),
width: (self.width as f32) / (mat.cols as f32),
height: (self.height as f32) / (mat.rows as f32),
}
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct Rect2f {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
impl Rect2f {
pub fn normalize_to_mat(&self, mat: &Mat) -> Rect {
Rect {
x: (self.x * mat.cols as f32) as i32,
y: (self.y * mat.rows as f32) as i32,
width: (self.width * mat.cols as f32) as i32,
height: (self.height * mat.rows as f32) as i32,
}
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct CVec<T: Sized + NestedVec> {
array: *mut T,
size: usize,
}
unsafe fn unpack<T: NestedVec, U, F>(v: &CVec<T>, mut f: F) -> Vec<U>
where
F: FnMut(&T) -> U,
{
(0..v.size)
.map(|i| f(&*v.array.offset(i as isize)))
.collect()
}
pub trait Unpack {
type Out;
fn unpack(&self) -> Self::Out;
}
impl<T: Unpack + NestedVec> Unpack for CVec<T> {
type Out = Vec<T::Out>;
fn unpack(&self) -> Self::Out {
unsafe { unpack(self, |e| e.unpack()) }
}
}
impl<T: Copy> Unpack for T {
type Out = T;
fn unpack(&self) -> Self::Out {
*self
}
}
pub trait NestedVec {
const LEVEL: u32;
}
impl<T: NestedVec> NestedVec for CVec<T> {
const LEVEL: u32 = T::LEVEL + 1;
}
impl<T: Copy> NestedVec for T {
const LEVEL: u32 = 0;
}
impl<T: NestedVec> Default for CVec<T> {
fn default() -> Self {
CVec {
array: ::std::ptr::null_mut::<T>(),
size: 0,
}
}
}
impl<T: NestedVec> Drop for CVec<T> {
fn drop(&mut self) {
extern "C" {
fn cv_vec_drop(vec: *mut c_void, depth: u32);
}
unsafe {
let depth = CVec::<T>::LEVEL;
let self_ptr: *mut _ = self;
let self_ptr: *mut c_void = self_ptr as *mut _;
cv_vec_drop(self_ptr, depth);
}
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum LineTypes {
Filled = -1,
Line4 = 4,
Line8 = 8,
LineAA = 16,
}
extern "C" {
fn cv_mat_new() -> *mut CMat;
fn cv_mat_new_with_size(rows: c_int, cols: c_int, t: i32) -> *mut CMat;
fn cv_mat_zeros(rows: c_int, cols: c_int, t: i32) -> *mut CMat;
fn cv_mat_from_buffer(rows: c_int, cols: c_int, t: i32, buffer: *const c_uchar) -> *mut CMat;
fn cv_mat_is_valid(mat: *mut CMat) -> bool;
fn cv_mat_rows(cmat: *const CMat) -> c_int;
fn cv_mat_cols(cmat: *const CMat) -> c_int;
fn cv_mat_depth(cmat: *const CMat) -> c_int;
fn cv_mat_channels(cmat: *const CMat) -> c_int;
fn cv_mat_data(cmat: *const CMat) -> *const c_uchar;
fn cv_mat_total(cmat: *const CMat) -> usize;
fn cv_mat_step1(cmat: *const CMat, i: c_int) -> usize;
fn cv_mat_elem_size(cmat: *const CMat) -> usize;
fn cv_mat_elem_size1(cmat: *const CMat) -> usize;
fn cv_mat_type(cmat: *const CMat) -> c_int;
fn cv_mat_roi(cmat: *const CMat, rect: Rect) -> *mut CMat;
fn cv_mat_logic_and(cimage: *mut CMat, cmask: *const CMat);
fn cv_mat_flip(src: *mut CMat, code: c_int);
fn cv_mat_drop(mat: *mut CMat);
}
#[derive(Debug, Clone, Copy)]
pub enum FlipCode {
XAxis,
YAxis,
XYAxis,
}
impl Mat {
#[inline]
pub fn from_raw(raw: *mut CMat) -> Mat {
Mat {
inner: raw,
rows: unsafe { cv_mat_rows(raw) },
cols: unsafe { cv_mat_cols(raw) },
depth: unsafe { cv_mat_depth(raw) },
channels: unsafe { cv_mat_channels(raw) },
}
}
pub fn new() -> Mat {
let m = unsafe { cv_mat_new() };
Mat::from_raw(m)
}
pub fn from_buffer(rows: i32, cols: i32, cv_type: i32, buf: &Vec<u8>) -> Mat {
let raw = unsafe { cv_mat_from_buffer(rows, cols, cv_type, buf.as_ptr()) };
Mat::from_raw(raw)
}
pub fn with_size(rows: i32, cols: i32, t: i32) -> Self {
let m = unsafe { cv_mat_new_with_size(rows, cols, t) };
Mat::from_raw(m)
}
pub fn zeros(rows: i32, cols: i32, t: i32) -> Self {
let m = unsafe { cv_mat_zeros(rows, cols, t) };
Mat::from_raw(m)
}
pub fn data(&self) -> *const u8 {
unsafe { cv_mat_data(self.inner) }
}
pub fn total(&self) -> usize {
unsafe { cv_mat_total(self.inner) }
}
pub fn elem_size(&self) -> usize {
unsafe { cv_mat_elem_size(self.inner) }
}
pub fn elem_size1(&self) -> usize {
unsafe { cv_mat_elem_size1(self.inner) }
}
pub fn step1(&self, i: c_int) -> usize {
unsafe { cv_mat_step1(self.inner, i) }
}
pub fn size(&self) -> Size2i {
Size2i::new(self.cols, self.rows)
}
pub fn is_valid(&self) -> bool {
unsafe { cv_mat_is_valid(self.inner) }
}
pub fn roi(&self, rect: Rect) -> Mat {
let cmat = unsafe { cv_mat_roi(self.inner, rect) };
Mat::from_raw(cmat)
}
pub fn logic_and(&mut self, mask: Mat) {
unsafe {
cv_mat_logic_and(self.inner, mask.inner);
}
}
pub fn flip(&mut self, code: FlipCode) {
let code = match code {
FlipCode::XAxis => 0,
FlipCode::YAxis => 1,
FlipCode::XYAxis => -1,
};
unsafe {
cv_mat_flip(self.inner, code);
}
}
pub fn show(&self, name: &str, delay: i32) -> Result<(), Error> {
extern "C" {
fn cv_imshow(name: *const c_char, cmat: *mut CMat);
fn cv_wait_key(delay_ms: c_int) -> c_int;
}
let s = CString::new(name)?;
unsafe {
cv_imshow((&s).as_ptr(), self.inner);
cv_wait_key(delay);
}
Ok(())
}
pub fn cv_type(&self) -> Result<CvType, Error> {
let t = unsafe { cv_mat_type(self.inner) };
num::FromPrimitive::from_i32(t).ok_or(CvError::EnumFromPrimitiveConversionError { value: t }.into())
}
}
pub trait FromBytes {
fn from_bytes(bytes: &[u8]) -> Self;
}
impl<T: FromBytes> FromBytes for (T, T, T) {
fn from_bytes(bytes: &[u8]) -> (T, T, T) {
let size = mem::size_of::<T>();
(
T::from_bytes(&bytes[(0 * size)..(1 * size)]),
T::from_bytes(&bytes[(1 * size)..(2 * size)]),
T::from_bytes(&bytes[(2 * size)..(3 * size)]),
)
}
}
impl FromBytes for u8 {
fn from_bytes(bytes: &[u8]) -> u8 {
bytes[0]
}
}
impl FromBytes for i8 {
fn from_bytes(bytes: &[u8]) -> i8 {
bytes[0] as i8
}
}
impl FromBytes for u16 {
#[cfg(target_endian = "big")]
fn from_bytes(bytes: &[u8]) -> u16 {
bytes::BigEndian::read_u16(bytes)
}
#[cfg(target_endian = "little")]
fn from_bytes(bytes: &[u8]) -> u16 {
bytes::LittleEndian::read_u16(bytes)
}
}
impl FromBytes for i16 {
#[cfg(target_endian = "big")]
fn from_bytes(bytes: &[u8]) -> i16 {
bytes::BigEndian::read_i16(bytes)
}
#[cfg(target_endian = "little")]
fn from_bytes(bytes: &[u8]) -> i16 {
bytes::LittleEndian::read_i16(bytes)
}
}
impl FromBytes for f32 {
#[cfg(target_endian = "big")]
fn from_bytes(bytes: &[u8]) -> f32 {
bytes::BigEndian::read_f32(bytes)
}
#[cfg(target_endian = "little")]
fn from_bytes(bytes: &[u8]) -> f32 {
bytes::LittleEndian::read_f32(bytes)
}
}
impl FromBytes for i32 {
#[cfg(target_endian = "big")]
fn from_bytes(bytes: &[u8]) -> i32 {
bytes::BigEndian::read_i32(bytes)
}
#[cfg(target_endian = "little")]
fn from_bytes(bytes: &[u8]) -> i32 {
bytes::LittleEndian::read_i32(bytes)
}
}
impl FromBytes for f64 {
#[cfg(target_endian = "big")]
fn from_bytes(bytes: &[u8]) -> f64 {
bytes::BigEndian::read_f64(bytes)
}
#[cfg(target_endian = "little")]
fn from_bytes(bytes: &[u8]) -> f64 {
bytes::LittleEndian::read_f64(bytes)
}
}
impl Mat {
pub fn at<T: FromBytes>(&self, i0: i32) -> T {
let data: *const u8 = self.data();
let size = self.size();
let pos = {
if size.height == 1 {
i0
} else if size.width == 1 {
i0 * (self.step1(1) * self.elem_size1()) as i32
} else {
unimplemented!{};
}
} as isize;
unsafe {
let ptr: *const u8 = data.offset(pos);
let slice = slice::from_raw_parts(ptr, mem::size_of::<T>());
T::from_bytes(slice)
}
}
pub fn at2<T: FromBytes>(&self, i0: i32, i1: i32) -> T {
let data: *const u8 = self.data();
let pos = (i0 as isize) * ((self.step1(0) * self.elem_size1()) as isize)
+ (i1 as isize) * ((self.step1(1) * self.elem_size1()) as isize);
unsafe {
let ptr: *const u8 = data.offset(pos);
let slice = slice::from_raw_parts(ptr, mem::size_of::<T>());
T::from_bytes(slice)
}
}
pub fn at3<T: FromBytes>(&self, i0: i32, i1: i32, i2: i32) -> T {
let data: *const u8 = self.data();
let pos = (i0 as isize) * ((self.step1(0) * self.elem_size1()) as isize)
+ (i1 as isize) * ((self.step1(1) * self.elem_size1()) as isize) + i2 as isize;
unsafe {
let ptr: *const u8 = data.offset(pos);
let slice = slice::from_raw_parts(ptr, mem::size_of::<T>());
T::from_bytes(slice)
}
}
}
impl Drop for Mat {
fn drop(&mut self) {
unsafe {
cv_mat_drop(self.inner);
}
}
}
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
pub enum CvType {
Cv8UC1 = 0,
Cv8SC1 = 1,
Cv16UC1 = 2,
Cv16SC1 = 3,
Cv32SC1 = 4,
Cv32FC1 = 5,
Cv64FC1 = 6,
Cv8UC2 = 8,
Cv8UC3 = 16,
Cv8SC3 = 17,
Cv16UC3 = 18,
Cv16SC3 = 19,
Cv32SC3 = 20,
Cv32FC3 = 21,
Cv64FC3 = 22,
}
#[derive(Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct RotatedRect {
center: Point2f,
size: Size2f,
angle: f32,
}
impl RotatedRect {
pub fn points(&self) -> [Point2f; 4] {
let angle = self.angle * ::std::f32::consts::PI / 180.0;
let b = angle.cos() * 0.5;
let a = angle.sin() * 0.5;
let mut pts: [Point2f; 4] = [Point2f::default(); 4];
pts[0].x = self.center.x - a * self.size.height - b * self.size.width;
pts[0].y = self.center.y + b * self.size.height - a * self.size.width;
pts[1].x = self.center.x + a * self.size.height - b * self.size.width;
pts[1].y = self.center.y - b * self.size.height - a * self.size.width;
pts[2].x = 2.0 * self.center.x - pts[0].x;
pts[2].y = 2.0 * self.center.y - pts[0].y;
pts[3].x = 2.0 * self.center.x - pts[1].x;
pts[3].y = 2.0 * self.center.y - pts[1].y;
pts
}
pub fn bounding_rect(&self) -> Rect {
let pt = self.points();
let x = pt.iter().map(|p| p.x).fold(0. / 0., f32::min).floor() as i32;
let y = pt.iter().map(|p| p.y).fold(0. / 0., f32::min).floor() as i32;
let width = pt.iter().map(|p| p.x).fold(0. / 0., f32::max).ceil() as i32 - x + 1;
let height = pt.iter().map(|p| p.y).fold(0. / 0., f32::max).ceil() as i32 - y + 1;
Rect::new(x, y, width, height)
}
}
extern "C" {
fn cv_in_range(cmat: *const CMat, lowerb: Scalar, upperb: Scalar, dst: *mut CMat);
fn cv_min_max_loc(
cmat: *const CMat,
min: *mut f64,
max: *mut f64,
min_loc: *mut Point2i,
max_loc: *mut Point2i,
cmask: *const CMat,
);
fn cv_mix_channels(
cmat: *const CMat,
nsrcs: isize,
dst: *mut CMat,
ndsts: isize,
from_to: *const i32,
npairs: isize,
);
fn cv_normalize(csrc: *const CMat, cdst: *mut CMat, alpha: c_double, beta: c_double, norm_type: c_int);
fn cv_bitwise_and(src1: *const CMat, src2: *const CMat, dst: *mut CMat);
fn cv_bitwise_not(src: *const CMat, dst: *mut CMat);
fn cv_bitwise_or(src1: *const CMat, src2: *const CMat, dst: *mut CMat);
fn cv_bitwise_xor(src1: *const CMat, src2: *const CMat, dst: *mut CMat);
fn cv_count_non_zero(src: *const CMat) -> i32;
}
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
pub enum NormTypes {
NormInf = 1,
NormL1 = 2,
NormL2 = 4,
NormL2Sqr = 5,
NormHamming = 6,
NormHamming2 = 7,
NormRelative = 8,
NormMinMax = 32,
}
impl Mat {
pub fn in_range(&self, lowerb: Scalar, upperb: Scalar) -> Mat {
let m = CMat::new();
unsafe { cv_in_range(self.inner, lowerb, upperb, m) }
Mat::from_raw(m)
}
pub fn min_max_loc(&self, mask: Mat) -> (f64, f64, Point2i, Point2i) {
let mut min = 0.0;
let mut max = 0.0;
let mut min_loc = Point2i::new(0, 0);
let mut max_loc = Point2i::new(0, 0);
unsafe {
cv_min_max_loc(
self.inner,
&mut min,
&mut max,
&mut min_loc,
&mut max_loc,
mask.inner,
)
}
(min, max, min_loc, max_loc)
}
pub fn mix_channels(&self, nsrcs: isize, ndsts: isize, from_to: *const i32, npairs: isize) -> Mat {
let m = Mat::with_size(self.rows, self.cols, self.depth);
unsafe {
cv_mix_channels(self.inner, nsrcs, m.inner, ndsts, from_to, npairs);
}
m
}
pub fn normalize(&self, alpha: f64, beta: f64, t: NormTypes) -> Mat {
let m = CMat::new();
unsafe { cv_normalize(self.inner, m, alpha, beta, t as i32) }
Mat::from_raw(m)
}
pub fn and(&self, another: &Mat) -> Mat {
let m = CMat::new();
unsafe { cv_bitwise_and(self.inner, another.inner, m) }
Mat::from_raw(m)
}
pub fn or(&self, another: &Mat) -> Mat {
let m = CMat::new();
unsafe { cv_bitwise_or(self.inner, another.inner, m) }
Mat::from_raw(m)
}
pub fn xor(&self, another: &Mat) -> Mat {
let m = CMat::new();
unsafe { cv_bitwise_xor(self.inner, another.inner, m) }
Mat::from_raw(m)
}
pub fn not(&self) -> Mat {
let m = CMat::new();
unsafe { cv_bitwise_not(self.inner, m) }
Mat::from_raw(m)
}
pub fn count_non_zero(&self) -> i32 {
unsafe { cv_count_non_zero(self.inner) }
}
}