non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

RustでFaceTime HDカメラやWebカメラを使う

おはようございます。最近、長男が食べ物を次男に分けてあげることをよく見かけます。奥さんの話だと、長男があまり好きではない者を弟にあげているとの話しでした。kjunichiです。
 

はじめに

node-webkitや、Atom ShellでWebRTCを使えば、Facetime HDカメラを簡単に使えるが、Rustだとどういうやり方があるのかと調べて、試してみた。

OpenCV使うと簡単に出来た。

Rustは言語レベルでFFIがサポートされているので、これを使ってOpenCVを叩ける。

#[allow(dead_code)]
pub mod cv {
    extern crate libc;
    use self::libc::{ c_char, c_double, c_int, c_schar, c_void }
    ;

    pub struct Capture;
    pub struct IplImage;

    #[link(name = "opencv_highgui")]
    extern"C" {
        fn cvDestroyAllWindows() -> c_void;
        fn cvNamedWindow(title: * const c_char) -> c_int;
        fn cvShowImage(name: * const c_char, image: * const IplImage) -> c_void;
        fn cvWaitKey(delay: c_int) -> c_int;
        fn cvCreateCameraCapture(index: c_int) -> * mut Capture;
        fn cvQueryFrame(capture: * mut Capture) -> * mut IplImage;
        fn cvSaveImage(filename: * const c_char, image: * const IplImage, params: *const c_int) -> c_int;
    }

    pub fn destroy_all_windows() -> () {
        unsafe {
            cvDestroyAllWindows();
        }
    }

    pub fn named_window(title: &str) -> () {
        title.with_c_str(| title | unsafe {
            cvNamedWindow(title);
        }
        );
    }

    pub fn create_camera_capture(index: int) -> * mut Capture {
        unsafe {
            cvCreateCameraCapture(index.to_i32().unwrap())
        }
    }

    pub fn query_frame(capture: * mut Capture) -> * mut IplImage {
        unsafe {
            cvQueryFrame(capture)
        }
    }

    pub fn show_image(name: &str, image: * const IplImage) -> () {
        name.with_c_str(| name | unsafe {
            cvShowImage(name, image);
        }
        )
    }

    pub fn wait_key(delay: int) -> int {
        unsafe {
            cvWaitKey(delay.to_i32().unwrap()).to_int().unwrap()
        }
    }

    pub fn save_image(name: &str, image: * const IplImage) -> int {
      name.with_c_str(| name | unsafe {
          cvSaveImage(name, image,0 as * const i32).to_int().unwrap()
      }
      )

    }

}

fn main() {
    let name = "WebCam test";
    let capture = cv::create_camera_capture(0);
    cv::named_window(name);
    while true {
        let frame = cv::query_frame(capture);
        cv::show_image(name, frame as * const cv::IplImage);
        let c = cv::wait_key(2);
        if c == 0x1b {
            break;
        }
        if c == 0x20 {
          cv::save_image("snap.jpg",frame as * const cv::IplImage);
          break;
        }
    }
    cv::destroy_all_windows();
}

まとめ

OpenCVは自分が学生やってたころに、インテルから作るよというアナウンスがあったくらいから知っているが、JavaScriptで顔検出するまで、使ったことがなかった。

今どきはC++APIは今回のRustで使っているCのAPIよりずっと洗練されたAPIを持っているようで、どうりで、皆C++で書いているのだと分かった。

Link

関連記事