Skip to content

include/cvw/pipeline.hpp

Pipeline composition via step factories and operator| chaining. More...

Namespaces

Name
cvw
cvw::steps
Namespace containing step factory functions for pipeline composition.
cvw::pipe_ops
Namespace containing operator
cvw::detail
Internal validation helpers used by algorithm implementations.

Detailed Description

Pipeline composition via step factories and operator| chaining.

Author: Charliechen114514

Version: 1.0.0

Since: 1.0.0

Date: 2026-05-15

Provides three layers of pipeline support:

  • steps:😗 — factory functions returning callable step objects.
  • pipe_ops — operator| overloads for chaining steps with short-circuit.
  • make_pipeline — composes multiple steps into a reusable callable.

Source code

cpp

#pragma once

#include "algorithms.hpp"

namespace cvw {

// ═══════════════════════════════════════════════════════════════
// steps — Factory functions returning callable step objects
// ═══════════════════════════════════════════════════════════════

namespace steps {

// ── Geometric steps ──────────────────────────────────────────

[[nodiscard]] inline auto resize(int width, int height,
                                 int interpolation = cv::INTER_LINEAR) {
    return [=](auto img) -> expected<decltype(img), AlgorithmError> {
        return cvw::resize(std::move(img), width, height, interpolation);
    };
}

[[nodiscard]] inline auto flip(int axis) {
    return [=](auto img) -> expected<decltype(img), AlgorithmError> {
        return cvw::flip(std::move(img), axis);
    };
}

[[nodiscard]] inline auto rotate(double angle, bool expand = false) {
    return [=](auto img) -> expected<decltype(img), AlgorithmError> {
        return cvw::rotate(std::move(img), angle, expand);
    };
}

// ── Color conversion steps ───────────────────────────────────

[[nodiscard]] inline auto to_gray() {
    return [](Image<BGR> img) -> expected<Image<Gray>, AlgorithmError> {
        return cvw::to_gray(std::move(img));
    };
}

[[nodiscard]] inline auto to_gray_rgb() {
    return [](Image<RGB> img) -> expected<Image<Gray>, AlgorithmError> {
        return cvw::to_gray(std::move(img));
    };
}

[[nodiscard]] inline auto to_bgr() {
    return [](Image<Gray> img) -> expected<Image<BGR>, AlgorithmError> {
        return cvw::to_bgr(std::move(img));
    };
}

[[nodiscard]] inline auto yuyv_to_gray() {
    return [](ImageView<YUYV> view) -> expected<Image<Gray>, AlgorithmError> {
        return cvw::yuyv_to_gray(view);
    };
}

// ── Filter steps ─────────────────────────────────────────────

[[nodiscard]] inline auto gaussian_blur(int kernel_size, double sigma = 0.0) {
    return [=](auto img) -> expected<decltype(img), AlgorithmError> {
        return cvw::gaussian_blur(std::move(img), kernel_size, sigma);
    };
}

template <is_pixel_format F>
    requires(F::channels == 1)
[[nodiscard]] inline auto median_blur(int kernel_size) {
    return [=](Image<F> img) -> expected<Image<F>, AlgorithmError> {
        return cvw::median_blur(std::move(img), kernel_size);
    };
}

// ── Edge & threshold steps ───────────────────────────────────

[[nodiscard]] inline auto canny(double lo, double hi, int aperture = 3) {
    return [=](Image<Gray> img) -> expected<Image<Gray>, AlgorithmError> {
        return cvw::canny(std::move(img), lo, hi, aperture);
    };
}

[[nodiscard]] inline auto sobel(int dx, int dy, int kernel_size = 3) {
    return [=](Image<Gray> img) -> expected<Image<Float1>, AlgorithmError> {
        return cvw::sobel(std::move(img), dx, dy, kernel_size);
    };
}

[[nodiscard]] inline auto threshold(double thresh, double max_val,
                                    int type = cv::THRESH_BINARY) {
    return [=](Image<Gray> img) -> expected<Image<Gray>, AlgorithmError> {
        return cvw::threshold(std::move(img), thresh, max_val, type);
    };
}

[[nodiscard]] inline auto
adaptive_threshold(int block_size, double C,
                   int method = cv::ADAPTIVE_THRESH_GAUSSIAN_C) {
    return [=](Image<Gray> img) -> expected<Image<Gray>, AlgorithmError> {
        return cvw::adaptive_threshold(std::move(img), block_size, C, method);
    };
}

// ── Normalization step ───────────────────────────────────────

[[nodiscard]] inline auto normalize(float min_val = 0.0f,
                                    float max_val = 1.0f) {
    return [=](Image<Gray> img) -> expected<Image<Float1>, AlgorithmError> {
        return cvw::normalize(std::move(img), min_val, max_val);
    };
}

// ── Sink step ────────────────────────────────────────────────

[[nodiscard]] inline auto save(std::string path) {
    return [=](const auto& img) -> expected<void, AlgorithmError> {
        return cvw::save(img, path);
    };
}

} // namespace steps

// ═══════════════════════════════════════════════════════════════
// pipe_ops — operator| overloads for step chaining (opt-in)
// ═══════════════════════════════════════════════════════════════

namespace pipe_ops {

template <is_pixel_format F, typename Step>
auto operator|(Image<F> img, Step&& step) -> decltype(step(std::move(img))) {
    return std::forward<Step>(step)(std::move(img));
}

template <is_pixel_format F, typename Step>
auto operator|(expected<Image<F>, AlgorithmError> input, Step&& step)
    -> decltype(step(std::move(*input))) {
    if (!input) {
        return decltype(step(std::move(*input)))(unexpected(input.error()));
    }
    return std::forward<Step>(step)(std::move(*input));
}

template <typename Step>
auto operator|(expected<void, AlgorithmError> input, Step&& step)
    -> decltype(std::forward<Step>(step)()) {
    if (!input) {
        return decltype(std::forward<Step>(step)())(unexpected(input.error()));
    }
    return std::forward<Step>(step)();
}

} // namespace pipe_ops

// ═══════════════════════════════════════════════════════════════
// make_pipeline — Composes multiple steps into a reusable callable
// ═══════════════════════════════════════════════════════════════

namespace detail {

inline auto make_pipeline_impl() {
    return [](auto input) {
        return expected<decltype(input), AlgorithmError>(std::move(input));
    };
}

template <typename First, typename... Rest>
auto make_pipeline_impl(First&& first, Rest&&... rest) {
    auto tail = make_pipeline_impl(std::forward<Rest>(rest)...);
    return [first = std::forward<First>(first),
            tail = std::move(tail)](auto input) mutable {
        return first(std::move(input)).and_then([&tail](auto next) {
            return tail(std::move(next));
        });
    };
}

} // namespace detail

template <typename... Steps>
[[nodiscard]] auto make_pipeline(Steps&&... steps) {
    return detail::make_pipeline_impl(std::forward<Steps>(steps)...);
}

} // namespace cvw

Updated on 2026-05-17 at 13:22:38 +0000

Built with VitePress