Skip to content
imaged

Image classification

Run an image model and read its highest-scoring classes.

Use your own .slab model and a runtime license. Model files carry their input sizes, preprocessing, labels, and backend preferences.

classify.c

C setup →
/* Classify an image and print the five most likely classes.
 *
 * usage: classify MODEL.slab IMAGE LICENSE_FILE
 * build: clang classify.c -I<release>/macos -L<release>/macos -lslab -Wl,-rpath,<release>/macos -o classify
 */

#include <stdio.h>
#include <string.h>

#include "slab.h"

#define S(str) (uint8_t *)(str), strlen(str)   /* Slab strings are (pointer, length) */

static int read_file(const char *path, char *buf, size_t cap, size_t *len) {
    FILE *f = fopen(path, "rb");
    if (!f) return 0;
    *len = fread(buf, 1, cap, f);
    fclose(f);
    while (*len && (buf[*len - 1] == '\n' || buf[*len - 1] == '\r')) (*len)--;
    return 1;
}

int main(int argc, char **argv) {
    if (argc < 4) { fprintf(stderr, "usage: %s MODEL.slab IMAGE LICENSE_FILE\n", argv[0]); return 2; }

    /* 1. Configure once and attach the runtime license. */
    uint8_t *cfg = slab_config_new();
    char token[4096]; size_t token_len;
    if (!read_file(argv[3], token, sizeof token, &token_len) ||
        !slab_config_set_runtime_license(cfg, (uint8_t *)token, token_len)) {
        fprintf(stderr, "License rejected: %.*s\n",
                (int)slab_config_runtime_license_error_message_len(cfg),
                (char *)slab_config_runtime_license_error_message_ptr(cfg));
        return 1;
    }

    /* 2. Open the model. The model file carries its preprocessing and labels. */
    uint8_t *session = slab_session_new(cfg);
    slab_session_set_warmup(session, 1);
    if (!slab_session_open(session, S(argv[1]))) {
        fprintf(stderr, "Cannot open the model: %.*s\n",
                (int)slab_session_error_message_len(session), (char *)slab_session_error_message_ptr(session));
        return 1;
    }

    /* 3. Decode the image and run. */
    uint8_t *frame = slab_frame_new();
    if (!slab_frame_load_file(frame, S(argv[2]))) {
        fprintf(stderr, "Cannot load the image: %.*s\n",
                (int)slab_frame_error_message_len(frame), (char *)slab_frame_error_message_ptr(frame));
        return 1;
    }
    uint8_t *in = slab_input_new();
    uint8_t *out = slab_output_new();
    slab_input_set_frame(in, frame);
    if (!slab_session_run(session, in, out)) {
        fprintf(stderr, "Run failed: %.*s\n",
                (int)slab_session_error_message_len(session), (char *)slab_session_error_message_ptr(session));
        return 1;
    }

    /* 4. Rank the classes. Labels are empty when the model has none. */
    int32_t k = slab_output_compute_top_k(out, 0, 5, 1);
    printf("backend %d, %.2f ms\n", slab_output_backend_used(out), slab_output_latency_ms(out));
    for (int32_t r = 0; r < k; r++) {
        size_t len = slab_output_top_label_len(out, r);
        if (len) printf("  %.*s: %.4f\n", (int)len, (char *)slab_output_top_label_ptr(out, r), slab_output_top_score(out, r));
        else printf("  class %d: %.4f\n", slab_output_top_class_id(out, r), slab_output_top_score(out, r));
    }

    /* 5. Free in any order; outputs stay valid even if the session goes first. */
    slab_output_free(out);
    slab_input_free(in);
    slab_frame_free(frame);
    slab_session_free(session);
    slab_config_free(cfg);
    return 0;
}