Skip to content

include/cvw/qt/bridging.hpp

Conversion utilities between cv::Mat/QImage and Image<QImage>. More...

Namespaces

Name
cvw

Detailed Description

Conversion utilities between cv::Mat/QImage and Image<QImage>.

Author: Charliechen114514

Version: 1.0.0

Since: 1.0.0

Date: 2026-05-15

Provides bidirectional conversion between OpenCV and Qt image types, supporting both shared-memory and deep-copy modes. Also includes convenience wrappers for converting Image<F> directly to QImage.

Source code

cpp

#pragma once

#include <QImage>
#include <cstdint>
#include <cvw/base/expected.hpp>
#include <cvw/image.hpp>
#include <opencv2/core/mat.hpp>

namespace cvw {

enum class ConvertionalError : uint8_t {
    InternalError,      
    UnsupportedFormat,  
};

enum class ConvertionalMethod : uint8_t {
    Copy,    
    Shared,  
};

template <ConvertionalMethod Method> [[nodiscard("Dont throw away QImage")]]
inline cvw::expected<QImage, ConvertionalError> from_cv(const cv::Mat& mat) {
    if (mat.empty()) {
        return cvw::unexpected(ConvertionalError::InternalError);
    }

    QImage::Format fmt;
    switch (mat.type()) {
        case CV_8UC1:
            fmt = QImage::Format_Grayscale8;
            break;
        case CV_8UC3:
            fmt = QImage::Format_RGB888;
            break;
        case CV_8UC4:
            fmt = QImage::Format_RGBA8888;
            break;
        default:
            return cvw::unexpected(ConvertionalError::UnsupportedFormat);
    }

    QImage img(mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), fmt);
    if constexpr (Method == ConvertionalMethod::Copy) {
        return img.copy();
    } else {
        return img;
    }
}

template <ConvertionalMethod Method> [[nodiscard("Dont throw away cv Mat")]]
inline cvw::expected<cv::Mat, ConvertionalError> to_cv(const QImage& image) {
    if (image.isNull()) {
        return cvw::unexpected(ConvertionalError::InternalError);
    }

    int type;
    switch (image.format()) {
        case QImage::Format_Grayscale8:
            type = CV_8UC1;
            break;
        case QImage::Format_RGB888:
            type = CV_8UC3;
            break;
        case QImage::Format_RGBA8888:
        case QImage::Format_ARGB32:
            type = CV_8UC4;
            break;
        default:
            return cvw::unexpected(ConvertionalError::UnsupportedFormat);
    }

    cv::Mat mat(image.height(), image.width(), type,
                const_cast<uchar*>(image.constBits()),
                static_cast<size_t>(image.bytesPerLine()));
    if constexpr (Method == ConvertionalMethod::Copy) {
        return mat.clone();
    } else {
        return mat;
    }
}

} // namespace cvw

// ═══════════════════════════════════════════════════════════════
// Image<F> convenience wrappers
// ═══════════════════════════════════════════════════════════════

namespace cvw {

template <is_pixel_format F>
[[nodiscard]] inline cvw::expected<QImage, ConvertionalError>
to_qimage_view(const Image<F>& img) {
    return from_cv<ConvertionalMethod::Shared>(img.mat());
}

template <is_pixel_format F>
[[nodiscard]] inline cvw::expected<QImage, ConvertionalError>
to_qimage_copy(const Image<F>& img) {
    return from_cv<ConvertionalMethod::Copy>(img.mat());
}

} // namespace cvw

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

Built with VitePress