#ifndef ZCPPWIN_ZCV_H
#define ZCPPWIN_ZCV_H


/*
 * zcv.h
 * -----------------------------------------------------------------------------
 * 基于 OpenCV 4.x / opencv_contrib 4.x 的常用计算机视觉工具库声明文件。
 *
 * 设计目标：
 *   1. 将 OpenCV 中高频使用的图像、视频、特征、DNN、二维码/条码、ArUco、标定等
 *      操作整理成统一的 ZCV 命名空间，减少项目中的重复样板代码。
 *   2. 保持“薄封装”原则：函数内部仍然使用 OpenCV 原生数据结构，如 cv::Mat、cv::Rect、
 *      cv::Point2f、cv::dnn::Net，便于和既有 OpenCV 代码互操作。
 *   3. 尽量兼容 OpenCV 4.x 的不同小版本。对 contrib 中可能不存在或 API 变化较大的模块，
 *      使用 __has_include 与版本宏做条件编译。
 *
 * 使用方式：
 *   #include "zcv.h"
 *   cv::Mat img = ZCV::readImage("test.jpg");
 *   cv::Mat gray = ZCV::ensureGray(img);
 *   cv::Mat edges = ZCV::canny(gray, 80, 160);
 *
 * 编译提示：
 *   CMake 中通常写法：
 *     find_package(OpenCV 4 REQUIRED)
 *     add_library(zcv zcv.cpp)
 *     target_include_directories(zcv PUBLIC ${OpenCV_INCLUDE_DIRS})
 *     target_link_libraries(zcv PUBLIC ${OpenCV_LIBS})
 */

#include <opencv2/core.hpp>
#include <opencv2/core/version.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
// #include <opencv2/video.hpp>
#include <opencv2/calib3d.hpp>
// #include <opencv2/features2d.hpp>
// #include <opencv2/objdetect.hpp>
#include <opencv2/dnn.hpp>
// #include <opencv2/photo.hpp>

// #include <algorithm>
#include <cstdint>
// #include <limits>
// #include <map>
// #include <stdexcept>
#include <string>
// #include <utility>
#include <vector>

// ---------------------------- 可选 contrib 模块检测 ----------------------------
// ArUco 在 OpenCV 4.x 的不同小版本中经历过头文件与 API 调整；优先使用传统 aruco.hpp，
// 若新版本只提供 objdetect 下的头文件，也尝试包含。
#if __has_include(<opencv2/aruco.hpp>)
    #include <opencv2/aruco.hpp>
    #define ZCV_HAS_ARUCO 1
#elif __has_include(<opencv2/objdetect/aruco_detector.hpp>) && __has_include(<opencv2/objdetect/aruco_dictionary.hpp>)
    #include <opencv2/objdetect/aruco_detector.hpp>
    #include <opencv2/objdetect/aruco_dictionary.hpp>
    #define ZCV_HAS_ARUCO 1
#else
    #define ZCV_HAS_ARUCO 0
#endif

// barcode 模块属于 contrib/objdetect 体系，不同版本头文件位置可能不同。
#if __has_include(<opencv2/objdetect/barcode.hpp>)
    #include <opencv2/objdetect/barcode.hpp>
    #define ZCV_HAS_BARCODE 1
#elif __has_include(<opencv2/barcode.hpp>)
    #include <opencv2/barcode.hpp>
    #define ZCV_HAS_BARCODE 1
#else
    #define ZCV_HAS_BARCODE 0
#endif

// SIFT 在较新的 OpenCV 4.x 中位于 features2d；较旧版本可能在 xfeatures2d。
#if (CV_VERSION_MAJOR > 4) || (CV_VERSION_MAJOR == 4 && CV_VERSION_MINOR >= 4)
    #define ZCV_HAS_SIFT 1
#elif __has_include(<opencv2/xfeatures2d.hpp>)
    #include <opencv2/xfeatures2d.hpp>
    #define ZCV_HAS_SIFT 1
    #define ZCV_SIFT_IN_XFEATURES2D 1
#else
    #define ZCV_HAS_SIFT 0
#endif

namespace ZCV {

// =============================================================================
// 1. 基础枚举与数据结构
// =============================================================================

/** 图像缩放模式。 */
enum class ResizeMode {
    Stretch,        ///< 直接拉伸到目标尺寸，可能改变宽高比。
    KeepAspectFit,  ///< 保持宽高比完整放入目标画布，不足区域填充颜色，类似 letterbox。
    KeepAspectFill  ///< 保持宽高比并填满目标尺寸，多余区域居中裁剪。
};

/** 常用形态学操作类型。 */
enum class MorphType {
    Erode,      ///< 腐蚀：缩小白色前景区域。
    Dilate,     ///< 膨胀：扩大白色前景区域。
    Open,       ///< 开运算：先腐蚀后膨胀，常用于去除小噪声。
    Close,      ///< 闭运算：先膨胀后腐蚀，常用于填补小孔洞。
    Gradient,   ///< 形态学梯度：突出目标边界。
    TopHat,     ///< 顶帽：原图 - 开运算结果，突出小亮区域。
    BlackHat,   ///< 黑帽：闭运算结果 - 原图，突出小暗区域。
    HitMiss     ///< 击中击不中，仅适用于二值单通道图像。
};

/** 90 度倍数旋转模式。 */
enum class RotateMode {
    Clockwise90,         ///< 顺时针旋转 90 度。
    CounterClockwise90,  ///< 逆时针旋转 90 度。
    Rotate180            ///< 旋转 180 度。
};

/** 图像基本信息，便于调试日志输出。 */
struct ImageInfo {
    bool empty = true;          ///< cv::Mat 是否为空。
    int width = 0;              ///< 图像宽度，单位：像素。
    int height = 0;             ///< 图像高度，单位：像素。
    int channels = 0;           ///< 通道数。
    int depth = -1;             ///< OpenCV 深度，例如 CV_8U、CV_32F。
    int type = -1;              ///< OpenCV 完整类型，例如 CV_8UC3。
    std::string typeString;     ///< 便于阅读的类型字符串，例如 "CV_8UC3"。
};

/** letterbox 缩放的返回结果。 */
struct LetterboxResult {
    cv::Mat image;              ///< 输出图像，尺寸等于 targetSize。
    double scale = 1.0;         ///< 原图到缩放图的比例。
    int padLeft = 0;            ///< 左侧填充像素数。
    int padTop = 0;             ///< 顶部填充像素数。
    cv::Rect contentRect;       ///< 原图缩放后在目标画布中的区域。
};

/** 轮廓摘要信息。 */
struct ContourInfo {
    std::vector<cv::Point> contour; ///< 原始轮廓点。
    double area = 0.0;              ///< 轮廓面积，来自 cv::contourArea。
    double perimeter = 0.0;         ///< 轮廓周长，来自 cv::arcLength。
    cv::Rect boundingBox;           ///< 水平外接矩形。
    cv::RotatedRect rotatedBox;     ///< 最小面积旋转外接矩形。
    cv::Point2f center;             ///< 根据矩计算出的质心；矩退化时取外接框中心。
    float enclosingRadius = 0.0f;   ///< 最小外接圆半径。
    double circularity = 0.0;       ///< 圆形度，4*pi*area/perimeter^2，越接近 1 越圆。
};

/** 连通域摘要信息。 */
struct ComponentInfo {
    int label = -1;                 ///< 连通域标签，0 通常是背景。
    int area = 0;                   ///< 像素面积。
    cv::Rect boundingBox;           ///< 外接矩形。
    cv::Point2d centroid;           ///< 质心。
};

/** 特征检测结果。 */
struct FeatureResult {
    std::vector<cv::KeyPoint> keypoints; ///< 关键点列表。
    cv::Mat descriptors;                 ///< 描述子矩阵。
};

/** 两幅图像特征匹配结果。 */
struct MatchResult {
    FeatureResult first;                  ///< 第一幅图像特征。
    FeatureResult second;                 ///< 第二幅图像特征。
    std::vector<cv::DMatch> matches;       ///< 通过筛选的匹配。
    cv::Mat homography;                   ///< 若启用单应性估计，则保存 3x3 H 矩阵。
    std::vector<char> inlierMask;          ///< RANSAC 内点掩码，与 matches 一一对应。
    int inlierCount = 0;                  ///< 内点数量。
};

/** 棋盘格角点检测结果。 */
struct ChessboardResult {
    bool found = false;                   ///< 是否成功找到所有内角点。
    cv::Size boardSize;                   ///< 棋盘格内角点数量，width x height。
    std::vector<cv::Point2f> corners;      ///< 角点坐标。
    cv::Mat debugImage;                   ///< 绘制角点后的调试图。
};

/** 相机标定结果。 */
struct CalibrationResult {
    bool ok = false;                      ///< 标定是否执行成功。
    double reprojectionError = 0.0;        ///< cv::calibrateCamera 返回的重投影误差。
    cv::Mat cameraMatrix;                 ///< 3x3 内参矩阵。
    cv::Mat distCoeffs;                   ///< 畸变系数。
    std::vector<cv::Mat> rvecs;            ///< 每张标定图的旋转向量。
    std::vector<cv::Mat> tvecs;            ///< 每张标定图的平移向量。
    std::size_t usedImageCount = 0;        ///< 实际参与标定的图片数量。
};

/** 视频文件或摄像头的摘要信息。 */
struct VideoInfo {
    bool opened = false;                  ///< 是否成功打开。
    int width = 0;                        ///< 帧宽。
    int height = 0;                       ///< 帧高。
    double fps = 0.0;                     ///< 帧率；摄像头或部分文件可能返回 0。
    int frameCount = 0;                   ///< 总帧数；实时流可能返回 0 或不可靠值。
    double durationSec = 0.0;             ///< 估算时长，frameCount / fps。
    std::string backendName;              ///< OpenCV 使用的视频后端名称。
};

/** QRCodeDetector 单个二维码识别结果。 */
struct QRCodeResult {
    bool success = false;                 ///< 是否检测并解码出非空字符串。
    std::string text;                     ///< 解码文本，OpenCV 通常返回 UTF-8 字符串。
    std::vector<cv::Point2f> points;       ///< 二维码四个角点。
    cv::Mat straight;                     ///< 透视校正后的二维码图像，可为空。
};

#if ZCV_HAS_ARUCO
/** ArUco marker 检测结果。 */
struct ArucoResult {
    std::vector<int> ids;                              ///< marker ID 列表。
    std::vector<std::vector<cv::Point2f>> corners;      ///< 每个 marker 的四个角点。
    std::vector<std::vector<cv::Point2f>> rejected;     ///< 被拒绝的候选区域，便于调参。
};
#endif

#if ZCV_HAS_BARCODE
/** 条形码检测与解码结果。 */
struct BarcodeResult {
    bool success = false;                 ///< 是否成功解码。
    std::string text;                     ///< 解码文本。
    std::string type;                     ///< 条码类型，如 EAN_13、CODE_128 等，具体取决于 OpenCV。
    std::vector<cv::Point2f> points;       ///< 条码旋转矩形四个点；可能因版本差异为空。
};
#endif

/** DNN 前处理参数。 */
struct DnnOptions {
    cv::Size inputSize;                   ///< 网络输入尺寸；空尺寸表示不强制 resize。
    double scale = 1.0;                   ///< 像素缩放因子，例如 1/255.0。
    cv::Scalar mean = cv::Scalar();        ///< 均值，按 BGR 或 RGB 顺序取决于 swapRB。
    bool swapRB = false;                  ///< 是否交换 R/B 通道，常用于 BGR -> RGB。
    bool crop = false;                    ///< blobFromImage 是否中心裁剪。
    int ddepth = CV_32F;                  ///< blob 数据深度，一般为 CV_32F。
    int backend = cv::dnn::DNN_BACKEND_OPENCV; ///< 推理后端。
    int target = cv::dnn::DNN_TARGET_CPU;      ///< 推理目标设备。
    std::string inputName;                ///< setInput 的输入层名称，通常留空。
};

/** DNN 推理结果。 */
struct DnnForwardResult {
    std::vector<cv::Mat> outputs;         ///< 网络输出 blob 列表。
    double inferenceMs = 0.0;             ///< 单次 forward 耗时，单位毫秒。
};

/** 分类分数。 */
struct ClassScore {
    int classId = -1;                     ///< 类别索引。
    float score = 0.0f;                   ///< 置信度或概率。
};

/** 简单计时器，基于 cv::TickMeter。 */
class TickTimer {
public:
    void start();                         ///< 清零并开始计时。
    double stopMs();                      ///< 停止计时并返回毫秒数。
    double elapsedMs() const;             ///< 返回当前累计毫秒数。
private:
    cv::TickMeter meter_;
};

// =============================================================================
// 2. 基础信息、类型转换与安全检查
// =============================================================================

std::string opencvVersionString();
std::string matTypeToString(int type);
ImageInfo getImageInfo(const cv::Mat& image);
bool isGray(const cv::Mat& image);
bool isBgrLike(const cv::Mat& image);
bool hasAlpha(const cv::Mat& image);
void assertNotEmpty(const cv::Mat& image, const std::string& name = "image");
cv::Mat ensureGray(const cv::Mat& image);
cv::Mat ensureBgr(const cv::Mat& image);
cv::Mat ensureBgra(const cv::Mat& image);
cv::Mat to8U(const cv::Mat& image, bool normalize = true, double alpha = 1.0, double beta = 0.0);
cv::Mat toFloat32(const cv::Mat& image, double scale = 1.0 / 255.0);

// =============================================================================
// 3. 图像读写、显示与基础矩阵操作
// =============================================================================

cv::Mat readImage(const std::string& path, int flags = cv::IMREAD_COLOR, bool throwIfEmpty = true);
bool saveImage(const std::string& path, const cv::Mat& image,
               const std::vector<int>& params = std::vector<int>());
std::vector<cv::Mat> readImages(const std::vector<std::string>& paths,
                                int flags = cv::IMREAD_COLOR,
                                bool skipFailed = true);
void showImage(const std::string& windowName, const cv::Mat& image,
               int delayMs = 0, int windowFlags = cv::WINDOW_AUTOSIZE,
               bool destroyAfter = false);
cv::Rect clampRect(const cv::Rect& roi, const cv::Size& imageSize);
cv::Mat crop(const cv::Mat& image, const cv::Rect& roi, bool safe = true, bool clone = true);
cv::Mat centerCrop(const cv::Mat& image, const cv::Size& size, bool clone = true);
std::vector<cv::Mat> splitChannels(const cv::Mat& image);
cv::Mat mergeChannels(const std::vector<cv::Mat>& channels);
cv::Mat stackHorizontal(const std::vector<cv::Mat>& images, int gap = 0,
                        const cv::Scalar& background = cv::Scalar(0, 0, 0));
cv::Mat stackVertical(const std::vector<cv::Mat>& images, int gap = 0,
                      const cv::Scalar& background = cv::Scalar(0, 0, 0));
cv::Mat makeGrid(const std::vector<cv::Mat>& images, int columns,
                 cv::Size cellSize = cv::Size(), int gap = 0,
                 const cv::Scalar& background = cv::Scalar(0, 0, 0));

// =============================================================================
// 4. 几何变换
// =============================================================================

cv::Mat resizeTo(const cv::Mat& image, const cv::Size& targetSize,
                 ResizeMode mode = ResizeMode::Stretch,
                 int interpolation = cv::INTER_LINEAR,
                 const cv::Scalar& borderColor = cv::Scalar(114, 114, 114));
cv::Mat resizeScale(const cv::Mat& image, double fx, double fy = 0.0,
                    int interpolation = cv::INTER_LINEAR);
LetterboxResult letterbox(const cv::Mat& image, const cv::Size& targetSize,
                          const cv::Scalar& color = cv::Scalar(114, 114, 114),
                          bool allowScaleUp = true,
                          int interpolation = cv::INTER_LINEAR);
cv::Mat rotate90(const cv::Mat& image, RotateMode mode);
cv::Mat rotateAngle(const cv::Mat& image, double angleDeg, double scale = 1.0,
                    bool expand = true,
                    const cv::Scalar& borderValue = cv::Scalar(0, 0, 0));
cv::Mat translate(const cv::Mat& image, double dx, double dy,
                  const cv::Scalar& borderValue = cv::Scalar(0, 0, 0));
std::vector<cv::Point2f> orderQuadPoints(const std::vector<cv::Point2f>& points);
cv::Mat fourPointTransform(const cv::Mat& image, const std::vector<cv::Point2f>& points,
                           int interpolation = cv::INTER_LINEAR);
cv::Mat warpPerspectiveFromPoints(const cv::Mat& image,
                                  const std::vector<cv::Point2f>& srcPoints,
                                  const std::vector<cv::Point2f>& dstPoints,
                                  const cv::Size& dstSize,
                                  int interpolation = cv::INTER_LINEAR);

// =============================================================================
// 5. 图像增强与滤波
// =============================================================================

cv::Mat adjustBrightnessContrast(const cv::Mat& image, double alpha = 1.0, double beta = 0.0);
cv::Mat gammaCorrect(const cv::Mat& image, double gamma);
cv::Mat equalizeGray(const cv::Mat& image);
cv::Mat clahe(const cv::Mat& image, double clipLimit = 2.0,
              cv::Size tileGridSize = cv::Size(8, 8));
cv::Mat normalizeMinMax(const cv::Mat& image, double alpha = 0.0, double beta = 255.0,
                        int dtype = -1);
cv::Mat grayWorldWhiteBalance(const cv::Mat& image);
cv::Mat sharpen(const cv::Mat& image);
cv::Mat unsharpMask(const cv::Mat& image, double amount = 1.0, double sigma = 1.0);
cv::Mat denoise(const cv::Mat& image, float h = 10.0f, float hColor = 10.0f,
                int templateWindowSize = 7, int searchWindowSize = 21);
cv::Mat applyColorMapToGray(const cv::Mat& image, int colorMap = cv::COLORMAP_JET);
cv::Mat meanBlur(const cv::Mat& image, int ksize = 3);
cv::Mat gaussianBlur(const cv::Mat& image, int ksize = 5, double sigmaX = 0.0);
cv::Mat medianBlur(const cv::Mat& image, int ksize = 5);
cv::Mat bilateral(const cv::Mat& image, int d = 9, double sigmaColor = 75.0, double sigmaSpace = 75.0);
cv::Mat sobelEdges(const cv::Mat& image, int dx = 1, int dy = 0, int ksize = 3);
cv::Mat laplacianEdges(const cv::Mat& image, int ksize = 3);
cv::Mat calcGrayHist(const cv::Mat& image, int histSize = 256, float rangeMin = 0.0f, float rangeMax = 256.0f);
cv::Mat drawGrayHist(const cv::Mat& hist, cv::Size canvasSize = cv::Size(512, 300),
                     const cv::Scalar& color = cv::Scalar(255, 255, 255));

// =============================================================================
// 6. 二值化、边缘、形态学与距离变换
// =============================================================================

cv::Mat thresholdBinary(const cv::Mat& image, double thresh, double maxVal = 255.0,
                        bool inverse = false);
cv::Mat thresholdOtsu(const cv::Mat& image, double maxVal = 255.0, bool inverse = false);
cv::Mat adaptiveThresholdBinary(const cv::Mat& image, int blockSize = 31, double C = 5.0,
                                bool inverse = false,
                                int method = cv::ADAPTIVE_THRESH_GAUSSIAN_C);
cv::Mat canny(const cv::Mat& image, double threshold1, double threshold2,
              int apertureSize = 3, bool L2gradient = false);
cv::Mat morph(const cv::Mat& image, MorphType type, int kernelSize = 3, int iterations = 1,
              int shape = cv::MORPH_RECT);
cv::Mat erodeImage(const cv::Mat& image, int kernelSize = 3, int iterations = 1,
                   int shape = cv::MORPH_RECT);
cv::Mat dilateImage(const cv::Mat& image, int kernelSize = 3, int iterations = 1,
                    int shape = cv::MORPH_RECT);
cv::Mat fillHoles(const cv::Mat& binaryImage);
cv::Mat distanceTransformBinary(const cv::Mat& binaryImage, int distanceType = cv::DIST_L2,
                                int maskSize = 3);

// =============================================================================
// 7. 轮廓、连通域与几何度量
// =============================================================================

std::vector<ContourInfo> findContoursInfo(const cv::Mat& binaryImage,
                                          int retrievalMode = cv::RETR_EXTERNAL,
                                          int approximation = cv::CHAIN_APPROX_SIMPLE,
                                          double minArea = 0.0,
                                          bool sortByAreaDesc = true);
bool largestContour(const cv::Mat& binaryImage, ContourInfo& outInfo, double minArea = 0.0);
cv::Mat drawContourInfos(const cv::Mat& image, const std::vector<ContourInfo>& contours,
                         const cv::Scalar& color = cv::Scalar(0, 255, 0),
                         int thickness = 2, bool drawBoundingBox = true,
                         bool drawIndex = false);
cv::Mat contourMask(const cv::Size& size, const std::vector<cv::Point>& contour,
                    uchar fillValue = 255);
std::vector<ComponentInfo> connectedComponentsInfo(const cv::Mat& binaryImage,
                                                   int connectivity = 8,
                                                   int minArea = 1);
cv::Mat drawComponents(const cv::Mat& labels, int labelCount);
double intersectionOverUnion(const cv::Rect2f& a, const cv::Rect2f& b);
cv::Scalar randomColor(int seed, int minValue = 40, int maxValue = 255);

// =============================================================================
// 8. 特征点、描述子与匹配
// =============================================================================

FeatureResult detectORB(const cv::Mat& image, int nfeatures = 1000);
FeatureResult detectAKAZE(const cv::Mat& image);
#if ZCV_HAS_SIFT
FeatureResult detectSIFT(const cv::Mat& image, int nfeatures = 0);
#endif
std::vector<cv::DMatch> matchDescriptors(const cv::Mat& desc1, const cv::Mat& desc2,
                                         int normType = -1,
                                         bool crossCheck = false,
                                         double ratio = 0.75,
                                         int maxMatches = 0);
MatchResult matchORB(const cv::Mat& image1, const cv::Mat& image2,
                     int nfeatures = 1500, double ratio = 0.75,
                     bool estimateHomography = true,
                     double ransacReprojThreshold = 3.0);
cv::Mat drawMatchResult(const cv::Mat& image1, const cv::Mat& image2,
                        const MatchResult& result,
                        bool onlyInliers = true);

// =============================================================================
// 9. 相机标定、畸变校正与传统目标检测
// =============================================================================

ChessboardResult findChessboard(const cv::Mat& image, cv::Size boardSize,
                                bool refineSubPix = true,
                                int flags = cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE);
CalibrationResult calibrateCameraFromChessboards(const std::vector<cv::Mat>& images,
                                                 cv::Size boardSize,
                                                 float squareSize,
                                                 int flags = 0);
CalibrationResult calibrateCameraFromChessboardFiles(const std::vector<std::string>& imagePaths,
                                                     cv::Size boardSize,
                                                     float squareSize,
                                                     int flags = 0);
cv::Mat undistortImage(const cv::Mat& image, const cv::Mat& cameraMatrix,
                       const cv::Mat& distCoeffs, double alpha = 0.0);
std::vector<cv::Rect> detectHaar(const cv::Mat& image, const std::string& cascadePath,
                                 double scaleFactor = 1.1, int minNeighbors = 3,
                                 cv::Size minSize = cv::Size(), cv::Size maxSize = cv::Size());
cv::Mat drawRects(const cv::Mat& image, const std::vector<cv::Rect>& rects,
                  const cv::Scalar& color = cv::Scalar(0, 255, 0), int thickness = 2);

// =============================================================================
// 10. DNN：模型加载、blob 前处理、推理与后处理辅助
// =============================================================================

cv::dnn::Net loadDnnNet(const std::string& modelPath,
                        const std::string& configPath = std::string(),
                        const std::string& framework = std::string(),
                        int backend = cv::dnn::DNN_BACKEND_OPENCV,
                        int target = cv::dnn::DNN_TARGET_CPU);
cv::Mat makeBlob(const cv::Mat& image, const DnnOptions& options);
DnnForwardResult forwardDnn(cv::dnn::Net& net, const cv::Mat& image,
                            const DnnOptions& options,
                            const std::vector<std::string>& outputNames = std::vector<std::string>());
std::vector<ClassScore> topK(const cv::Mat& scores, int k = 5);
std::vector<int> nmsBoxes(const std::vector<cv::Rect>& boxes,
                          const std::vector<float>& confidences,
                          float scoreThreshold = 0.25f,
                          float nmsThreshold = 0.45f,
                          float eta = 1.0f,
                          int topK = 0);

// =============================================================================
// 11. 视频读取、写入与帧抽取
// =============================================================================

VideoInfo getCaptureInfo(cv::VideoCapture& cap);
cv::VideoCapture openVideo(const std::string& path, int apiPreference = cv::CAP_ANY,
                           bool throwIfFailed = true);
cv::VideoCapture openCamera(int index = 0, int width = 0, int height = 0,
                            double fps = 0.0, int apiPreference = cv::CAP_ANY,
                            bool throwIfFailed = true);
bool readFrameAt(const std::string& videoPath, int frameIndex, cv::Mat& frame,
                 int apiPreference = cv::CAP_ANY);
cv::VideoWriter createVideoWriter(const std::string& path, cv::Size frameSize, double fps,
                                  const std::string& fourcc = "MJPG", bool isColor = true,
                                  int apiPreference = cv::CAP_ANY);
bool writeVideoFromFrames(const std::string& path, const std::vector<cv::Mat>& frames,
                          double fps, const std::string& fourcc = "MJPG",
                          bool isColor = true);
std::vector<cv::Mat> readAllFrames(const std::string& videoPath, int maxFrames = -1,
                                   int step = 1, int apiPreference = cv::CAP_ANY);
int extractFrames(const std::string& videoPath, const std::string& outputPattern,
                  int step = 1, int maxFrames = -1, int startFrame = 0,
                  int apiPreference = cv::CAP_ANY);

// =============================================================================
// 12. 二维码、条码、ArUco 与绘制辅助
// =============================================================================

QRCodeResult detectAndDecodeQRCode(const cv::Mat& image);
cv::Mat drawQRCodeResult(const cv::Mat& image, const QRCodeResult& result,
                         const cv::Scalar& color = cv::Scalar(0, 255, 0));

#if ZCV_HAS_BARCODE
std::vector<BarcodeResult> detectAndDecodeBarcodes(const cv::Mat& image,
                                                   const std::string& srPrototxt = std::string(),
                                                   const std::string& srModel = std::string());
cv::Mat drawBarcodeResults(const cv::Mat& image, const std::vector<BarcodeResult>& results,
                           const cv::Scalar& color = cv::Scalar(255, 0, 0));
#endif

#if ZCV_HAS_ARUCO
ArucoResult detectArucoMarkers(const cv::Mat& image,
                               int dictionaryId = cv::aruco::DICT_4X4_50,
                               bool refineCorners = true);
cv::Mat drawArucoResult(const cv::Mat& image, const ArucoResult& result,
                        const cv::Scalar& color = cv::Scalar(0, 255, 0));
cv::Mat generateArucoMarker(int markerId, int sidePixels = 300,
                            int dictionaryId = cv::aruco::DICT_4X4_50,
                            int borderBits = 1);
#endif

void drawLabel(cv::Mat& image, const std::string& text, cv::Point origin,
               double fontScale = 0.6,
               const cv::Scalar& textColor = cv::Scalar(255, 255, 255),
               const cv::Scalar& bgColor = cv::Scalar(0, 0, 0),
               int thickness = 1);
void drawRotatedRect(cv::Mat& image, const cv::RotatedRect& rect,
                     const cv::Scalar& color = cv::Scalar(0, 255, 0), int thickness = 2);
void drawCrosshair(cv::Mat& image, cv::Point center, int radius = 10,
                   const cv::Scalar& color = cv::Scalar(0, 0, 255), int thickness = 1);
cv::Mat drawGridOverlay(const cv::Mat& image, int gridSize = 50,
                        const cv::Scalar& color = cv::Scalar(80, 80, 80),
                        int thickness = 1);

} // namespace ZCV


#endif //ZCPPWIN_ZCV_H