opencv-rust安装与使用

最近在尝试用rust写视频处理代码,用到了opencv-rust这个库,这儿记录下安装过程。另外这个库说明文档比较欠缺,有些opencv接口不容易找到rust对应的调用名称或者方式,这儿将之前整理的接口查找的方法汇总了下。

1.windows下安装

1.1 llvm

这个是动态生成代码需要用到,安装好就行

https://releases.llvm.org/download.html

1.2 opencv

下载opencv安装即可,我安装的是opencv4.4版本。opencv-rust github主页用的choco安装,这个并不是必须的,可以手动安装llvm和opencv,设置环境变量就能正常的用opencv-rust

下面是官网给的环境变量设置方式,照着做就行了
在这里插入图片描述上面这个图片来源于这个issue,如果遇到更多的问题可以参考下
https://github.com/twistedfall/opencv-rust/issues/118

下面是我安装的opencv和配置(与上面步骤一样),可以参考下

安装完opencv需要设置环境变量即可,本机用的vs2019,这个是vc14(设置错了编译提示出错,最后有编译命令,可以看到是vc14.xxx)
在这里插入图片描述

1.3 toml配置

opencv = {version = “0.46”, default-features = false, features = [“opencv-4”, “buildtime-bindgen”]}

前面安装llvm是为了动态生成opencv绑定用的,如果不用动态绑定编译可能会出错(本来不想装llvm,去掉了buildtime-bindgen提示编译出错)

cargo build即可使用opencv-rust了

2. opencv-rust接口使用

2.1 toml配置

需要安装llvm和opencv,这个按照前面步骤来即可

opencv = {version = “0.46”, default-features = false, features = [“opencv-4”, “buildtime-bindgen”]}

2.2 代码的位置

cargo下载的代码都在下面这个目录:

C:\Users\xxx\.cargo\registry\src\github.com-yyyy\ 

xxx是电脑的用户名,github.com-yyyy每个人可能不一样,也可能会有几个文件夹,找到最新的一个文件夹。
这个目录下面找到:opencv-0.46.0这个目录,opencv-rust的代码都在这儿
部分binding代码需要在用到opencv-rust的工程里cargo build才能生成

2.3 opencv的c接口

这部分代码主要在opencv-0.46.0\bindings\cpp\opencv_4目录里

这部分是c代码,是opencv-rust这个库用llvm生成的。由于rust只能调用c接口,这儿的c代码将rust无法直接调用的代码封装成c接口。比如:cpp成员函数调用\函数重载\namespace等c没有的东西

  • c接口的Result定义

    定义在opencv-0.46.0\src_cpp\ocvrs_common.hpp 这个文件里,这个文件主要是c部分的Result和OCVRS_CATCH的定义,这两个基本上所有c接口函数都用到。而c里的Result会通过Rust里对应的Result的into_result转换成Rust内部的std::result::Result,具体继续往下看。

2.4 rust绑定接口

这是rust代码使用的opencv的接口

opencv-0.46.0\src\opencv目录下默认是opencv4,内容与opencv-0.46.0\bindings\rust\opencv_4是一样的,库编译的时候用的是src目录的内容

sys.rs是 2.3里的c接口的extern声明,这个基本上不需要看,函数名/接口与opencv的c接口一样的

常用代码在:core.rs,imgproc.rs。imgcodecs.rs和highgui.rs也有一部分

2.5 调用接口对应方法

opencv的cpp接口在rust里对应的接口以及调用参数查找方法

首先在opencv-0.46.0\bindings\cpp\opencv_4目录找到core.cpp\imgproc.cpp,看下c++下对应的接口被封装在了哪个c接口里

比如:cv::cvtColor,这个在imgproc.cpp里

	Result_void cv_cvtColor_const__InputArrayR_const__OutputArrayR_int_int(const cv::_InputArray* src, const cv::_OutputArray* dst, int code, int dstCn) {
		try {
			cv::cvtColor(*src, *dst, code, dstCn);
			return Ok();
		} OCVRS_CATCH(OCVRS_TYPE(Result_void))
	}

其中:对应的c的函数封装后的名对应的是:

cv_cvtColor_const__InputArrayR_const__OutputArrayR_int_int

用这个c的函数名称去opencv-0.46.0\src\opencv\hub目录下同名的文件去找,这儿对应的是:imgproc.rs

搜索c的函数名可以看到如下的rust封装代码,rust对外提供的接口名是cvt_color这个名字。可以看到opencv在Rust里的函数名称与c/c++的有区别,这就是需要按上面方法找对应关系的原因。

pub fn cvt_color(src: &dyn core::ToInputArray, dst: &mut dyn core::ToOutputArray, code: i32, dst_cn: i32) -> Result<()> {
	input_array_arg!(src);
	output_array_arg!(dst);
	unsafe { sys::cv_cvtColor_const__InputArrayR_const__OutputArrayR_int_int(src.as_raw__InputArray(), dst.as_raw__OutputArray(), code, dst_cn) }.into_result()
}

可以看到这儿unsafe里调用的是sys::xxxx这种形式,前面提到过外部c接口

2.6 部分重要的代码结构与类型

  • 目录结构

    此crate的入口在src/lib.rs,所有的mod都在src目录下,这个注意下就行了,opencv-0.46.0\bindings\rust\opencv_4这个目录并不在这个crate里,这个只是生成的一个中间目录

  • Result

    c结构部分定义了Result模板(见前面c接口部分),注意这个是c里的Result结构体,与Rust里的std::result::Result不是一样的。从上面代码段的调用可以看到,c接口返回的Result通过into_result转换成了Rust的Result。opencv-0.46.0\src\manual\sys.rs有这个c接口里Result的定义,两种类型的Result转换在Result定义的下方,具体见下面代码:

    pub fn into_result(self) -> CrateResult<O> {
    	if self.error_msg.is_null() {
    		Ok(self.result.into())
    	} else {
    		Err(Error::new(self.error_code, unsafe { crate::templ::receive_string(self.error_msg as *mut String) }))
    	}
    }
    

    Rust的Result在crate::Result,从lib.rs里可以看出这个Result在 error::Result

    打开src\error.rs看到Result的定义

    #[derive(Debug)]
    pub struct Error {
    	pub code: i32,
    	pub message: String,
    }
    
    impl Error {
    	pub fn new(code: i32, message: String) -> Self {
    		Self { code, message }
    	}
    }
    
    impl fmt::Display for Error {
    	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    		write!(f, "{} (code: {})", self.message, self.code)
    	}
    }
    
    impl From<NulError> for Error {
    	fn from(_: NulError) -> Self {
    		Self::new(core::StsBadArg, "Passed Rust string contains nul byte".into())
    	}
    }
    
    impl std::error::Error for Error {}
    
    pub type Result<T, E = Error> = ::std::result::Result<T, E>;
    
  • crate::core

    在代码里经常看到crate::core这个模块,下面看下这个模块的位置

    在lib.rs的第五行可以看到如下代码引入了hub的所有模块

    pub use crate::opencv::hub::*;
    

    其中hub模块引入了core,imgcodecs等模块,后面代码里出现的crate::core等模块都是指hub里的这些模块

    pub mod calib3d;
    pub mod core;
    pub mod dnn;
    pub mod features2d;
    pub mod flann;
    pub mod highgui;
    pub mod imgcodecs;
    pub mod imgproc;
    pub mod ml;
    pub mod objdetect;
    pub mod photo;
    pub mod stitching;
    pub mod video;
    pub mod videoio;
    #[cfg(feature = "contrib")]
    pub mod world;
    pub mod types;
    

2.7 常用接口

opencv-0.46.0\examples\ 这个目录里有一些简单的例子,更多的例子可以参考 opencv-0.46.0\tests\这个目录,

2.7.1 Mat

Mat在下面这个文件里定义:
opencv-0.46.0\src\opencv\hub\core.rs
Mat的接口除了impl Mat还有MatTrait定义的方法,分别搜索impl Mat和pub trait MatTrait可以看下有没有要用的接口

  • 元素访问
    一维接口: at
    二维接口: at_2d

  • Mat内存释放
    Mat的内存管理与c++是否一致?
    比如ROI区域操作,opencv-rust里roi定义如下

    pub fn roi(m: &core::Mat, roi: core::Rect) -> Result<core::Mat> {
    	unsafe { sys::cv_Mat_Mat_const_MatR_const_RectR(m.as_raw_Mat(), &roi) }.into_result().map(|r| unsafe { core::Mat::opencv_from_extern(r) } )
    }
    

    这儿用的是:cv_Mat_Mat_const_MatR_const_RectR,这个在c++里定义如下,可以看到这儿用的是new cv::Mat,也就是roi函数new了一个Mat对象

    Result<cv::Mat*> cv_Mat_Mat_const_MatR_const_RectR(const cv::Mat* m, const cv::Rect* roi) {
    	try {
    		cv::Mat* ret = new cv::Mat(*m, *roi);
    		return Ok<cv::Mat*>(ret);
    	} OCVRS_CATCH(OCVRS_TYPE(Result<cv::Mat*>))
    }
    

    Mat生命周期结束后会自动调用drop,drop代码在 opencv-0.46.0\src\opencv\hub\core.rs 里
    可以看到drop里调用了 cv_Mat_delete函数

    impl Drop for Mat {
    	fn drop(&mut self) {
    		extern "C" { fn cv_Mat_delete(instance: *mut c_void); }
    		unsafe { cv_Mat_delete(self.as_raw_mut_Mat()) };
    	}
    }
    

    cv_Mat_delete函数在opencv-0.46.0\bindings\cpp\opencv_4\core.cpp里定义,这儿只是简单的调用了delete释放了Mat对象,delete 会引发自动执行Mat的析构函数

    void cv_Mat_delete(cv::Mat* instance) {
    	delete instance;
    }
    

    c++的Mat对象的析构函数可以看下官方文档:https://docs.opencv.org/4.4.0/d3/d63/classcv_1_1Mat.html

    这个网页里搜索:~Mat 可以看到文档里只有一句:calls release

    继续看下release函数,这个函数会减少引用计数,到0了就真正的释放内存

    opencv-rust实际上用的是opencv c++的内存管理方法,Rust只是多了一个Mat::drop触发析构函数的步骤而已,使用过程中按照c++的方式去操作即可,不用担心内存泄露

2.7.2 cv::resize

这个不要与Mat::resize弄混了
搜索的方法:在opencv-rust库里搜索所有文件:cv::resize
在imgproc.cpp里有调用

Result_void cv_resize_const__InputArrayR_const__OutputArrayR_Size_double_double_int(const cv::_InputArray* src, const cv::_OutputArray* dst, cv::Size* dsize, double fx, double fy, int interpolation) {
	try {
		cv::resize(*src, *dst, *dsize, fx, fy, interpolation);
		return Ok();
	} OCVRS_CATCH(OCVRS_TYPE(Result_void))
}

可以看到封装后的c接口为:

cv_resize_const__InputArrayR_const__OutputArrayR_Size_double_double_int

在opencv-rust库里搜索这个c接口名,可以在imgproc.rs里找到如下代码

pub fn resize(src: &dyn core::ToInputArray, dst: &mut dyn core::ToOutputArray, dsize: core::Size, fx: f64, fy: f64, interpolation: i32) -> Result<()> {
	input_array_arg!(src);
	output_array_arg!(dst);
	unsafe { sys::cv_resize_const__InputArrayR_const__OutputArrayR_Size_double_double_int(src.as_raw__InputArray(), dst.as_raw__OutputArray(), dsize.opencv_as_extern(), fx, fy, interpolation) }.into_result()
}

所以找到这个cv::resize在Rust里接口为:imgproc::resize(…)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要安装OpenCV库,可以使用以下命令: 1. 在Windows上,使用命令提示符或PowerShell,输入以下命令: ``` pip install opencv-python ``` 2. 在Linux或macOS上,打开终端,输入以下命令: ``` pip3 install opencv-python ``` 如果你需要安装OpenCV的contrib模块,可以使用以下命令: 1. 在Windows上,使用命令提示符或PowerShell,输入以下命令: ``` pip install opencv-contrib-python ``` 2. 在Linux或macOS上,打开终端,输入以下命令: ``` pip3 install opencv-contrib-python ``` 安装完成后,可以在Python代码中导入cv2模块,并使用其中的函数。例如,可以使用以下代码检查OpenCV是否已正确安装: ``` import cv2 print(cv2.__version__) ``` 如果输出了OpenCV的版本号,则说明OpenCV已成功安装。 ### 回答2: 安装OpenCV-Python可以按照以下步骤进行。 1. 首先,确保你已经安装了Python。你可以在Python的官方网站上下载并安装最新版本的Python。 2. 打开命令提示符或终端,并输入以下命令来安装OpenCV-Python: ``` pip install opencv-python ``` 3. 等待安装完成。这个过程可能需要一些时间,具体取决于你的网络连接速度和计算机性能。 4. 安装完成后,你可以验证OpenCV-Python是否成功安装。在命令提示符或终端中输入以下命令: ``` python >>> import cv2 >>> print(cv2.__version__) ``` 如果没有报错,并且输出了OpenCV-Python的版本号,那么说明OpenCV-Python已经成功安装了。 通过以上步骤,你可以很容易地安装OpenCV-Python并开始使用它进行图像处理和计算机视觉的开发。如果遇到任何安装问题,可以查阅更多的教程或在社区中寻求帮助。 ### 回答3: 要安装opencv-python,可以按照以下步骤进行操作: 1. 首先,确保你的计算机上已经安装了Python。如果没有,请先去Python官方网站下载并安装最新版本的Python。 2. 打开命令提示符或终端窗口,并使用以下命令安装opencv-python: ```shell pip install opencv-python ``` 这个命令将会自动从Python包索引中下载并安装最新版的opencv-python。 3. 等待安装完成。这可能需要一些时间,取决于你的互联网连接速度和计算机性能。 4. 安装完成后,你就可以在Python脚本中导入opencv了。使用以下代码: ```python import cv2 ``` 这将导入opencv库,你就可以使用opencv的各种功能了。 注意:如果你之前已经安装过其他版本的opencv,可能需要先卸载之前的版本,然后再安装最新的opencv-python。 另外,如果你的计算机上已经安装了其他科学计算相关的库(如numpy、matplotlib等),你也可以考虑安装opencv-python-headless。这是一个无界面版本的opencv-python,可以节省一些依赖库的安装时间。 ```shell pip install opencv-python-headless ``` 安装过程和使用方法与opencv-python相同。 总之,安装opencv-python只需要使用pip命令即可,然后就可以在Python脚本中导入opencv库并使用它的功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值