@ryoppippi

ZigのOpenCVライブラリ「zigcv」を作っている

27 Aug 2022 ・ 4 min read


zigcv

はじめに

以前、​Zig の​ Tensorflow Lite の​ライブラリを​使って​遊ぶ記事を​書いた。

/blog/2022-08-18-zenn-4f4716118cc06b-ja

この​記事内では、​静止画の​処理を​行う​ために、STB ライブラリを​用いた。

こうなると​次は​動画の​処理を​行いたくなる​ものだ。

…​ ならば OpenCV を​ Zig から​使えるようにしようではないか。

https://github.com/ryoppippi/zigcv

OpenCV の​ C バインディングを​作る

OpenCV は​ C++で​書かれているので、​Zig から​関数を​呼び出すには​ C バインディングを​作る​必要が​ある。 1から​ OpenCV の​ C バインディングを​作るのは​大変なので、 今回は​同じ​手法で​ C バインディングを​実装して​呼び出している​ gocv の​コードを​利用させていただく​ことにした。 これで、​工数の​半分以上が​省ける​ことになる。

https://github.com/hybridgroup/gocv

Zig バインディングを​作る

この​記事の​執筆中では​まだ​完成は​していない。 しかし、​Web カメラの​画像を​取得して​文字や図を​書き込んだり、​画像を​ファイルから​読み込んで​加工、​保存を​する​ことは​できる。 また、​DNN の​モデルを​呼び出し推論を​行うことも​できるようになった。

Web カメラから画像を取得し、顔が含まれているならば Blur 処理をするコード
const std = @import("std");
const cv = @import("zigcv");

pub fn main() anyerror!void {
    var allocator = std.heap.page_allocator;
    var args = try std.process.argsWithAllocator(allocator);
    defer args.deinit();
    const prog = args.next();
    const device_id_char = args.next() orelse {
        std.log.err("usage: {s} [cameraID]", .{prog.?});
        std.os.exit(1);
    };
    const device_id = try std.fmt.parseUnsigned(c_int, device_id_char, 10);

    // open webcam
    var webcam = try cv.VideoCapture.init();
    try webcam.openDevice(device_id);
    defer webcam.deinit();

    // open display window
    const window_name = "Face Detect";
    var window = try cv.Window.init(window_name);
    defer window.deinit();

    // prepare image matrix
    var img = try cv.Mat.init();
    defer img.deinit();

    // load classifier to recognize faces
    var classifier = try cv.CascadeClassifier.init();
    defer classifier.deinit();

    classifier.load("./libs/gocv/data/haarcascade_frontalface_default.xml") catch {
        std.debug.print("no xml", .{});
        std.os.exit(1);
    };

    const size = cv.Size{ .width = 75, .height = 75 };
    while (true) {
        webcam.read(&img) catch {
            std.debug.print("capture failed", .{});
            std.os.exit(1);
        };
        if (img.isEmpty()) {
            continue;
        }
        const rects = try classifier.detectMultiScale(img, allocator);
        defer rects.deinit();
        const found_num = rects.items.len;
        std.debug.print("found {d} faces\n", .{found_num});
        for (rects.items) |r| {
            std.debug.print("x:\t{}, y:\t{}, w:\t{}, h:\t{}\n", .{ r.x, r.y, r.width, r.height });
            cv.gaussianBlur(img, &img, size, 0, 0, .{});
        }

        window.imShow(img);
        if (window.waitKey(1) >= 0) {
            break;
        }
    }
}
blur

実用例?

いく​つかの​実装例は​以下に​おいてある。

https://github.com/ryoppippi/zigcv/tree/main/examples

また、​mattn 氏が​前述の​ tensorflow Lite ライブラリと​組み合わせた​例を​公開している。

https://github.com/mattn/zig-tflite-example

終わりに

まだまだ​開発途中です。 API も​まだ​不安定ですし、​テストも​足りていません。 しかし、​ある​程度は​実用できると​思います。

Contribution 大歓迎です。 ぜひお待ちしています。

追記 2022/10/06

先日、​Core 部分の​実装が​終わり、​0.1.1 を​リリースしました!

https://github.com/ryoppippi/zigcv/releases/tag/0.1.1

comment on bluesky / twitter
CC BY-NC-SA 4.0 2022-PRESENT © ryoppippi