sowilo

OpenCV's algorithms. torchvision's autodiff. OCaml's reliability.


why sowilo?

differentiable vision

Every operation supports automatic differentiation. Train neural networks with classical CV in the loop.

pure functional

No global state, no side effects. Image processing operations that compose like functions should.

type-safe images

Images are just tensors with known shapes. The compiler catches dimension mismatches.

jit ready

Built on Rune's tensor operations. When JIT lands, your filters compile to GPU kernels automatically.


show me the code

OpenCV

import cv2
import numpy as np

# Load and process
img = cv2.imread('photo.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 1.0)
edges = cv2.Canny(blurred, 100, 200)

# Not differentiable!

SOWILO

open Sowilo

(* Load and process *)
let img = Nx_io.load_image "photo.jpg" |> Rune.of_bigarray
let processed = 
  img
  |> to_grayscale
  |> gaussian_blur ~ksize:5 ~sigma:1.0
  |> canny ~low:100. ~high:200.

(* Fully differentiable! *)

image processing operations

(* Filters *)
gaussian_blur img ~ksize:5 ~sigma:1.0
median_blur img ~ksize:3
box_filter img ~ksize:3

(* Edge detection *)
let grad_x, grad_y = sobel img ~dx:1 ~dy:0 ~ksize:3
let edges = canny img ~low:50. ~high:150.

(* Morphology *)
let kernel = get_structuring_element Rect ~ksize:3
let eroded = erode img kernel
let dilated = dilate img kernel

(* Thresholding *)
threshold img ~thresh:128. ~maxval:255. ~typ:Binary

differentiable augmentations

Train neural networks with classical CV operations in the forward pass:

(* Augmentation pipeline *)
let augment img =
  img
  |> random_crop ~size:(224, 224)
  |> random_flip ~p:0.5
  |> adjust_brightness ~factor:(random 0.8 1.2)
  |> gaussian_blur ~ksize:3 ~sigma:(random 0. 1.)

(* Use in training - gradients flow through! *)
let loss model img label =
  let augmented = augment img in
  let features = extract_features augmented in
  let pred = Model.forward model features in
  cross_entropy pred label

what's implemented

core operations

  • ✓ Color space conversions
  • ✓ Gaussian, median, box filters
  • ✓ Sobel gradients, Canny edges
  • ✓ Morphological operations
  • ✓ Thresholding functions
  • ✓ Image resizing (nearest, bilinear)

coming soon

  • ⏳ Feature detection (SIFT, ORB)
  • ⏳ Optical flow
  • ⏳ Semantic segmentation ops
  • ⏳ Video processing
  • ⏳ 3D vision primitives

design philosophy

Images are tensors. No special image type - just 3D arrays with shape [H; W; C]. This means any tensor operation works on images.

Everything differentiates. Unlike traditional CV libraries, every operation in sowilo can be differentiated. This enables new techniques like learnable image processing.

Functional composition. Operations are pure functions that compose naturally. No global state, no side effects.


get started

Sowilo isn't released yet. For now, check out the documentation to learn more.

When it's ready:

# Install
opam install sowilo

# Try it
open Sowilo

(* Edge detection example *)
let () =
  let img = Nx_io.load_image "input.jpg" in
  let edges = 
    Rune.of_bigarray (Nx.to_bigarray img)
    |> to_grayscale
    |> canny ~low:50. ~high:150.
    |> Rune.to_bigarray
    |> Nx.of_bigarray
  in
  Nx_io.save_image edges "edges.png"