You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV技术实现:如何从掩码中提取数字到std::vector<int>数组

从掩码中提取数字并转为std::vector

基于你已有的掩码处理代码,接下来可以通过轮廓检测、轮廓筛选排序、数字识别这几个步骤,把图像中的数字提取为std::vector<int>,具体实现如下:

步骤1:提取并筛选数字轮廓

在现有掩码处理代码之后,添加轮廓检测逻辑,过滤掉噪声小轮廓,只保留符合数字形状特征的轮廓:

void find_numbers(const cv::Mat& image, std::vector<int>& out_numbers){
    // 你的原有代码...
    cv::bitwise_and(dlt,dlt, dst, msk);   

    // 1. 提取最外层轮廓(忽略数字内部孔洞,比如0、8的空白区域)
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(dst, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    // 2. 筛选有效轮廓:根据面积、宽高比过滤噪声
    std::vector<std::vector<cv::Point>> valid_contours;
    for (auto& cnt : contours) {
        double area = cv::contourArea(cnt);
        cv::Rect rect = cv::boundingRect(cnt);
        // 阈值根据你的数字实际尺寸调整,示例值适配常规数字
        if (area > 100 && (double)rect.width/rect.height > 0.3 && (double)rect.width/rect.height < 1.2) {
            valid_contours.push_back(cnt);
        }
    }

步骤2:按从左到右顺序排序轮廓

数字是横向排列的,需按轮廓的x坐标排序,保证识别顺序与视觉一致:

// 按轮廓左上角x坐标从小到大排序
    std::sort(valid_contours.begin(), valid_contours.end(), [](const std::vector<cv::Point>& a, const std::vector<cv::Point>& b) {
        return cv::boundingRect(a).x < cv::boundingRect(b).x;
    });

步骤3:数字识别并填充vector

针对固定字体的数字,模板匹配是最简便的方案。先准备0-9的数字模板(与目标数字尺寸、风格一致的单数字灰度图),再对每个数字区域做匹配:

模板加载逻辑(可提前初始化)

// 存储0-9的数字模板
std::vector<cv::Mat> num_templates;
void load_num_templates() {
    for (int i = 0; i < 10; ++i) {
        std::string path = "templates/" + std::to_string(i) + ".png";
        cv::Mat temp = cv::imread(path, cv::IMREAD_GRAYSCALE);
        if (!temp.empty()) {
            num_templates.push_back(temp);
        }
    }
}

在find_numbers中完成匹配

// 3. 对每个有效轮廓做模板匹配,识别数字
    for (auto& cnt : valid_contours) {
        cv::Rect rect = cv::boundingRect(cnt);
        cv::Mat num_roi = dst(rect);
        // 将ROI调整为与模板一致的尺寸(示例为20x30,根据你的模板修改)
        cv::resize(num_roi, num_roi, cv::Size(20, 30));

        double max_match_val = 0;
        int matched_num = -1;
        for (int i = 0; i < num_templates.size(); ++i) {
            cv::Mat result;
            cv::matchTemplate(num_roi, num_templates[i], result, cv::TM_CCOEFF_NORMED);
            double val;
            cv::minMaxLoc(result, nullptr, &val);
            // 匹配阈值,大于0.8认为匹配成功
            if (val > max_match_val && val > 0.8) {
                max_match_val = val;
                matched_num = i;
            }
        }
        if (matched_num != -1) {
            out_numbers.push_back(matched_num);
        }
    }
}

替代方案:无模板形状识别

如果数字风格极度规整,也可以通过轮廓特征识别:

  • 统计孔洞数量:0、8有2个孔洞,6、9有1个,其余数字无孔洞
  • 轮廓近似顶点数:1的顶点数最少,7有独特折线特征
    这种方法无需模板,但仅适配固定的简单字体。

内容的提问来源于stack exchange,提问作者Aleksandr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 17:32:41