Skip to content

Latest commit

 

History

History
81 lines (63 loc) · 3.44 KB

README.md

File metadata and controls

81 lines (63 loc) · 3.44 KB

TrustMark C++

This C++17 runner uses OpenCV for image loading, crop/resize, and writing, and ONNX Runtime for the TrustMark B, C, P, and Q encoder and decoder models. Like the Rust and Python interfaces, it supports binary payload encoding and decoding with BCH error correction. Text encoding and watermark removal are not implemented.

Build

Install an ONNX Runtime C/C++ distribution with headers and a shared library, and OpenCV with CMake packages. From the repository root:

cmake -S cpp -B cpp/build -DONNXRUNTIME_ROOT=/path/to/onnxruntime
cmake --build cpp/build

If CMake cannot find OpenCV, also pass -DOpenCV_DIR=/path/to/opencv/lib/cmake/opencv4. Fetch ONNX models from the rust/ directory with cargo xtask fetch-models (instructions).

Encode and decode images

cpp/build/trustmark-runner encode-image rust/models Q images/ghost.png encoded.png \
  1011011110011000111111000000011111011111011100000110110110111 BCH_5
cpp/build/trustmark-runner decode-image rust/models Q encoded.png

The payload is a binary string of at most 40 (BCH_SUPER), 61 (BCH_5, the default), 68 (BCH_4), or 75 (BCH_3) bits. Short payloads are padded with zeros. The variant can be B, C, P, or Q. Optionally supply a strength in [0,1] after the BCH version; the default is 0.95. The output is an image file; use PNG for lossless roundtrips. The original alpha channel is preserved for RGBA inputs. Decode prints Found watermark (BCH_5): <payload bits> when BCH validation succeeds, or Corrupt or missing watermark otherwise.

OpenCV accepts 8-bit RGB/RGBA images here. The runner center-crops P images and images with an aspect ratio above 2:1, resizes to the ONNX model's input size (224 for P decoding, 256 otherwise), and normalizes RGB channels to [-1,1]. For encoding, it scales and clamps the model residual before compositing it onto the original image. OpenCV and the Rust/Python image resize routines can produce slightly different pixel values. The Python PyTorch decoder currently uses 245 for B/C/Q; the ONNX models used here and by Rust require 256.

Raw model inference

The tensor interface remains available for callers with their own image pipeline:

cpp/build/trustmark-runner inspect rust/models/decoder_Q.onnx
cpp/build/trustmark-runner decode rust/models/decoder_Q.onnx input.f32
cpp/build/trustmark-runner encode rust/models/encoder_Q.onnx input.f32 "$BITS100" output.f32

input.f32 is a native-endian float32 RGB tensor in NCHW order, normalized to [-1,1]. Raw decode prints 100 unvalidated bits. Raw encode takes a full 100-bit packet including BCH parity and schema bits, and writes the model's float32 output tensor. Use encode-image/decode-image for BCH and image I/O.

To run the BCH checks and image inference smoke test:

ctest --test-dir cpp/build --output-on-failure
python3 cpp/tests/smoke.py cpp/build/trustmark-runner rust/models

To verify interoperability in both directions with the Rust CLI for B, C, P, and Q on square PNG and JPEG inputs, plus P and Q on an image wider than 2:1 (writing lossless PNG outputs):

cargo build --manifest-path rust/Cargo.toml -p trustmark-cli
python3 cpp/tests/interoperability.py cpp/build/trustmark-runner \
  rust/target/debug/trustmark rust/models

The Rust implementation does not reliably decode its own B/C watermarks on very wide images, so those cases are not used as cross-implementation fixtures.