📸

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

2022/08/27に公開約2,900字

zigcv

はじめに

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

https://zenn.dev/ryoppippi/articles/4f4716118cc06b

この記事内では、静止画の処理を行うために、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 = cv.VideoCapture.init();
    try webcam.openDevice(device_id);
    defer webcam.deinit();

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

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

    // load classifier to recognize faces
    var classifier = 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, cv.BorderType.default);
        }

        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大歓迎です。
ぜひお待ちしています。

Discussion

ログインするとコメントできます