# rust-opencv-bind-demo **Repository Path**: qwsaeda/rust-opencv-lib ## Basic Information - **Project Name**: rust-opencv-bind-demo - **Description**: rust通过FFI机制可以绑定C库进行调用,但大多数都是基于C源码的方式进行演示,本例是基于opencv2 windows版本的dll文件和相关.h头文件方式演示了,如何绑定一个用于生产开发使用的C库的demo - **Primary Language**: Rust - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2020-06-15 - **Last Updated**: 2022-04-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # rust-opencv-bind-demo #### 介绍 rust通过FFI机制可以绑定C库进行调用,但大多数都是基于C源码的方式进行演示,本例是基于opencv2 windows版本的dll文件和相关.h头文件方式演示了,如何绑定一个用于生产开发使用的C库的demo #### 软件架构 使用Idea社区版+rust插件做为rust开发IDE #### 原由 虽然知道rust的FFI机制,对C语言只有初步的了解,在进行一个C库进行Rust绑定时,发现大部分教程都是和官方例子一样,或者是按snappy例子。但真实在工作中与C库打交道都是使用动态库或静态库结合.h头文件的方式。对于一般小的C库,主要是指.h头文件少的(一两个),按官方教程去翻译成rust代码也没有问题![输入图片说明](https://images.gitee.com/uploads/images/2020/0615/143130_36dccc1b_64294.png "微信截图_20200615143056.png") 对C了解不多,所以我使用rust的第三方库bindgen来翻译C头文件生成rust代码。 首先这个第三方库,可以用以下命令安装,也可以用依赖库的方案,官方文档[https://rust-lang.github.io/rust-bindgen/command-line-usage.html](https://rust-lang.github.io/rust-bindgen/command-line-usage.html),在翻简单C库,只有两个.h头文件时,一下子就OK了,但是翻译opencv的头文件时翻车了,因为opencv的好多头文件都是一个依赖另一个,然后bindgen就报include的路径找不到了,这个参数这篇文章。 cargo install bindgen #### 安装教程 1. 创建一个cargo lib项目 2. 在上面安装好bindgen后,就在include文件中打开windows命令行执行 **bindgen highgui.h -o highgui.rs** 把highgui.h头文件翻译成highgui.rs,然后highgui.rs放到src下面,然后在lib.rs中声明这个模块。 3. 把lib文件夹copy到项目根目录下 4. 创建一个build.rs文件,看一些老教程说要在cargo.toml的[package]下声明build = "build.rs",但我没声明可以编译执行。 5. build.rs内的内容就是 > println!("cargo:rustc-link-search=all={}", "D:/rust/opencv/lib64/opencv/lib"); > println!("cargo:rustc-link-lib=static=opencv_core249"); > println!("cargo:rustc-link-lib=static=opencv_highgui249"); > println!("cargo:rustc-link-lib=static=opencv_imgproc249"); rustc-link-search=all路径我写了绝对路径,真实开发中肯定不要这样写,去参考cargo手册里有项目相关的变量 rustc-link-lib=static静态库编译找这几个相关的.lib文件,查询相关的资料说windows编译调用动态库dll时,需要在编译时查询同名相关的.lib,经验证发现,编译时有.lib文件即可,这个演示项目只依赖上面三个.lib文件。 6. 这时的项目结构 ![项目结构](https://images.gitee.com/uploads/images/2020/0615/145505_b1dd069f_64294.png "微信截图_20200615145431.png") 7. 编译这个lib项目 在Idea IDE中可以直接编译,可以在项目根据目录执行cargo build进行编译。然后这个项目就可以让本地项目依赖使用了。可以上传发布crates.io中。 贴张本地其它项目如何使用 在本地其它项目的cargo.toml文件中增加依赖 ``` [dependencies] opencv={path="../opencv",version="0.1.0"} ``` 测试代码: ``` use std::ffi::CString; use std::os::raw::c_void; use opencv::highgui::{CV_LOAD_IMAGE_COLOR, CV_WINDOW_AUTOSIZE, CvArr, cvCopy, cvCreateImage, cvDestroyWindow, cvLoadImage, cvNamedWindow, CvRect, cvReleaseImage, cvResetImageROI, cvSetImageROI, cvShowImage, CvSize, cvWaitKey, IplImage}; fn main() { cv_demo(); } fn cv_demo() { unsafe { let mut filename = CString::new("d:/u=3710180744,1467376657&fm=26&gp=0.jpg").expect("CString::new failed"); let filename = filename.as_c_str().as_ptr(); let img = cvLoadImage(filename, CV_LOAD_IMAGE_COLOR); let mut name = CString::new("Image_show").expect("CString::new failed"); let name = name.as_c_str().as_ptr(); cvNamedWindow(name, CV_WINDOW_AUTOSIZE); cvShowImage(name, img as *const CvArr); cvWaitKey(0); let p = Box::into_raw(Box::new(img)) as *mut *mut IplImage; cvReleaseImage(p); cvDestroyWindow(name); } } ``` FFI中与C语言对应的翻译还是要了解的。 #### 使用说明 1. 不应该直接暴露unsafe方法,应该再写一个wrap.rs的文件进行safe的方法的包装 2. 本项目只是windows下对opencv的绑定,故linux下不使用 3. 本rust库底层还是依赖于opencv相关的dll文件,以上/lib64/opencv/lib目录下只是*.lib文件 4. 其它依赖此库的项目需要把相关的dll文件放到与执行文件同目录下,否则为报经典的windows缺失dll错误 5. dll目录下存在opencv相关模块的Dll文件,需要copy到使用此库生成的执行文件同目录