opencv实践项目-修改表格缺失轮廓

2023-11-09

1. 背景

如果大家在输入图像时,看到的第二行中的单元格线未完全链接,在表格识别种,由于单元格不是闭合的框,算法将无法识别和考虑第二行,本文提出的解决方案不仅适用于这种情况。它也适用于表格中的其他虚线和孔。
在这里插入图片描述

2. 修复步骤

2.1 图像灰度化,并进行高斯模糊

有助于识别线条

	cv::Mat img = cv::imread("/Users/xialz/Downloads/5.png");
    cv::Mat gray_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);

    cv::Mat gauss_img;
    cv::GaussianBlur(gray_img, gauss_img, Size(3,3), 1);

2.2 对图像进行阀值处理

	cv::Mat threshold_img;
    cv::threshold(gray_img, threshold_img, 0, 255, cv::THRESH_BINARY_INV|THRESH_OTSU);

2.3 查找轮廓

对于所有轮廓,将绘制一个边界矩形以创建表格的框/单元格,然后将这些框与四个值x,y,宽度,高度一起存储起来,并计算最小、最大高度、宽度以及x,y

	std::vector<std::vector<cv::Point>> contrours;

    cv::findContours(threshold_img, contrours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);

    std::vector<cv::Rect> box;

    std::vector<int> heights, widths, xs, ys;
    for (auto &c : contrours)
    {
        cv::Rect rect = cv::boundingRect(c);
        box.push_back(rect);
        heights.push_back(rect.height);
        widths.push_back(rect.width);
        xs.push_back(rect.x);
        ys.push_back(rect.y);
    }
    
    sort(heights.begin(), heights.end());
    int min_height = heights[0];
    int max_height = heights.at(heights.size()-1);

    sort(widths.begin(), widths.end());
    int min_weight = widths[0];
    int max_weight = widths.at(widths.size()-1);

    sort(xs.begin(), xs.end());
    int min_x = xs[0];
    int max_x = xs.at(xs.size()-1);

    sort(ys.begin(), ys.end());
    int min_y = ys[0];
    int max_y = ys.at(ys.size()-1);

2.4 利用存储的值了解表格的位置

最小的y用于获取表的最上一行,该行可以视为表的起点。
x的最小值是表格的左边缘,要获得近似大小,我们需要检索最大y值,该值是表底部的单元格或行。
最后一行的y值表示单元格的上边缘,而不是单元格的底部。要考虑单元格和表格的整体大小,必须将最后一行的高度加到最大y以检索表格的完整高度。
最大的x将是表格的最后一列,并且连续的是表格的最右边的单元格或者行。
x值是每个单元格的左边缘,并且连续

	int max_y_height = 0, max_x_width = 0;
    for (auto &b : box){
        if (b.y == max_y)
        {
            max_y_height = b.height;
        }

        if (b.x == max_x)
            max_x_width = b.width;
    }

2.5 提取所有的水平线和垂直线

由于反转,背景为黑色,前景为白色,这意味着表格是白色的,使用形态学的扩张可以是白色区域扩大,现在修复孔和虚线,为了进一步识别表,将考虑所有的单元格

	auto horizontal_kernal = cv::getStructuringElement(cv::MORPH_RECT, Size(50, 1));

    cv::Mat horizontal_mask;
    cv::morphologyEx(threshold_img, horizontal_mask, cv::MORPH_OPEN, horizontal_kernal);
    cv::dilate(horizontal_mask, horizontal_mask, horizontal_kernal, cv::Point(-1, -1), 9);

    auto vertcal_kernal = cv::getStructuringElement(cv::MORPH_RECT, Size(1, 50));
    cv::Mat vertical_mask;
    cv::morphologyEx(threshold_img, vertical_mask, cv::MORPH_OPEN, vertcal_kernal);
    cv::dilate(vertical_mask, vertical_mask, vertcal_kernal, cv::Point(-1, -1), 9);

2.6 合并垂直和水平的两个模版

使用bitwise_or合并表
使用255-bitwise_or的结果进行反色

    cv::Mat result;

    cv::bitwise_or(vertical_mask, horizontal_mask, result);
    result = 255 - result;

3. 完整代码

int main()
{
    cv::Mat img = cv::imread("/Users/xialz/Downloads/5.png");
    cv::Mat gray_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);

    cv::Mat gauss_img;
    cv::GaussianBlur(gray_img, gauss_img, Size(3,3), 1);

    cv::Mat threshold_img;
    cv::threshold(gray_img, threshold_img, 0, 255, cv::THRESH_BINARY_INV|THRESH_OTSU);

    std::vector<std::vector<cv::Point>> contrours;

    cv::findContours(threshold_img, contrours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);

    std::vector<cv::Rect> box;

    std::vector<int> heights, widths, xs, ys;
    for (auto &c : contrours)
    {
        cv::Rect rect = cv::boundingRect(c);
        box.push_back(rect);
        heights.push_back(rect.height);
        widths.push_back(rect.width);
        xs.push_back(rect.x);
        ys.push_back(rect.y);
    }

    sort(heights.begin(), heights.end());
    int min_height = heights[0];
    int max_height = heights.at(heights.size()-1);

    sort(widths.begin(), widths.end());
    int min_weight = widths[0];
    int max_weight = widths.at(widths.size()-1);

    sort(xs.begin(), xs.end());
    int min_x = xs[0];
    int max_x = xs.at(xs.size()-1);

    sort(ys.begin(), ys.end());
    int min_y = ys[0];
    int max_y = ys.at(ys.size()-1);

    int max_y_height = 0, max_x_width = 0;
    for (auto &b : box){
        if (b.y == max_y)
        {
            max_y_height = b.height;
        }

        if (b.x == max_x)
            max_x_width = b.width;
    }

    auto horizontal_kernal = cv::getStructuringElement(cv::MORPH_RECT, Size(50, 1));

    cv::Mat horizontal_mask;
    cv::morphologyEx(threshold_img, horizontal_mask, cv::MORPH_OPEN, horizontal_kernal);
    cv::dilate(horizontal_mask, horizontal_mask, horizontal_kernal, cv::Point(-1, -1), 9);

    auto vertcal_kernal = cv::getStructuringElement(cv::MORPH_RECT, Size(1, 50));
    cv::Mat vertical_mask;
    cv::morphologyEx(threshold_img, vertical_mask, cv::MORPH_OPEN, vertcal_kernal);
    cv::dilate(vertical_mask, vertical_mask, vertcal_kernal, cv::Point(-1, -1), 9);

    cv::Mat result;

    cv::bitwise_or(vertical_mask, horizontal_mask, result);
    result = 255 - result;

    cv::imshow("result", result);
    cv::waitKey(0);

    return 0;
}

结果图:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

opencv实践项目-修改表格缺失轮廓 的相关文章

  • 使用高斯混合模型进行皮肤检测

    我正在根据以下进行皮肤检测算法本文 http www cc gatech edu rehg Papers SkinDetect IJCV lowres pdf 第 21 页有两个模型 高斯皮肤混合模型和非皮肤颜色模型 第一个皮肤检测模型效果
  • 霍夫变换的累加器填充

    我写了一段需要优化的代码 只是想与社区核实一下该代码是否确实是最佳的 它填充霍夫变换的累加器 实际上 我只是复制粘贴了 OpenCV 库中的大部分代码 谢谢 int i j n index for i 0 i
  • Android Camera2 API - 实时显示处理后的帧

    我正在尝试创建一个实时处理相机图像并将其显示在屏幕上的应用程序 我正在使用camera2 API 我创建了一个本机库来使用 OpenCV 处理图像 到目前为止 我已经成功设置了一个 ImageReader 来接收 YUV 420 888 格
  • 在进行字符识别之前使用 OpenCV 进行图像预处理(超正方体)

    我正在尝试开发简单的 PC 应用程序用于车牌识别 Java OpenCV Tess4j 图像不是很好 进一步它们会很好 我想对超立方体图像进行预处理 但我被困在车牌检测 矩形检测 上 我的步骤 1 源图像 Mat img new Mat i
  • OpenCV 的 findHomography 产生无意义的结果

    我正在制作一个程序 使用 OpenCV 2 43 中的 ORB 跟踪功能 我遵循并使用了建议从这里 https stackoverflow com questions 9919505 how can i extract fast featu
  • Python opencv排序轮廓[重复]

    这个问题在这里已经有答案了 我正在关注这个问题 如何从左到右 从上到下对轮廓进行排序 https stackoverflow com questions 38654302 how can i sort contours from left
  • 将 Magick::Image 转换为 cv::Mat

    我正在尝试将通过 Magick 从 GIF 加载的图像转换为cv Mat 我已经从cv Mat to Magick Image但似乎无法找到如何从 Magick 中的图像中提取数据以便将其加载到 Mat 中 最好的方法是什么 供参考 反过来
  • 增加图像亮度而不溢出

    我在尝试增加图像亮度时遇到问题 这是原始图像 我想要得到的图像是这样的 现在使用以下代码增加亮度 image cv2 imread home wni vbshare tmp a4 index2 png 0 if sum image 0 le
  • 如何在win32上安装OpenCV 2.0

    我需要在 Win32 上安装 OpenCV 我目前没有安装它 我下载了 OpenCV 2 0 0a win32 exe 并运行它 我现在到底该怎么办 没有 lib之类的东西 我找到了一些使用 cmake 构建版本的说明 http openc
  • 使用 OpenCV 查找重叠/复杂的圆

    我想计算红圈半径 图2 我在使用 OpenCV 的 HoughCircles 找到这些圆圈时遇到了麻烦 如图所示 2 我只能使用 HoughCircles 找到中心以黑色显示的小圆圈 original fig 2 由于我知道红色圆圈的中心
  • 使用 OpenCV 裁剪黑色边缘

    我认为这应该是一个很简单的问题 但我找不到解决方案或有效的关键字进行搜索 我只有这个图像 黑边没有用 所以我想把它们剪掉 只留下 Windows 图标 和蓝色背景 我不想计算Windows图标的坐标和大小 GIMP 和 Photoshop
  • 收据褪色部分可以恢复吗?

    我有一些包含一些扫描收据的文件 我需要使用 OCR 从中提取文本 由于收据上打印的文字在一段时间后会褪色 导致收据上的某些文字不清晰 影响OCR结果 褪色单词的一些示例 有什么方法可以恢复褪色的部分 以便提高 OCR 结果吗 我在OpenC
  • OpenCV findContours 破坏源图像

    我编写了一个在单通道空白图像中绘制圆形 直线和矩形的代码 之后 我只需找出图像中的轮廓 就可以正确获取所有轮廓 但找到轮廓后 我的源图像变得扭曲 为什么会出现这种情况 任何人都可以帮我解决这个问题 我的代码如下所示 using namesp
  • 在 Python 3.5 64 位上通过 pip 安装 OpenCV

    我尝试安装 OpenCV 但找不到任何合适的 pip 软件包 我决定上网查找有关如何安装它的官方文档 并发现this https opencv python tutroals readthedocs io en latest py tuto
  • brew 链接 jpeg 问题

    我正在尝试安装opencv在 Mac OSX Lion 上 brew install opencv 我收到以下错误 以及其他一些类似的错误 Error The linking step did not complete successful
  • 相机标定(OpenCV 2.3)-如何使用畸变参数?

    我有一组带有一些附加标记的刚体图像 我在这些标记之一中定义了一个原点坐标系 我想获得该坐标系与在相机原点定义的坐标系之间的旋转和平移 我尝试了一段时间 POSIT 以下this http goo gl cUYYt 但从未获得可接受的结果 直
  • Opencv matchTemplate 和 np.where():仅保留唯一值

    继带有马里奥硬币的 opencv 教程 https opencv python tutroals readthedocs io en latest py tutorials py imgproc py template matching p
  • 提高 pytesseract 从图像中正确识别文本的能力

    我正在尝试使用读取验证码pytesseract模块 大多数时候它都能提供准确的文本 但并非总是如此 这是读取图像 操作图像以及从图像中提取文本的代码 import cv2 import numpy as np import pytesser
  • Python:opencv warpPerspective 既不接受 2 个也不接受 3 个参数

    我发现单应矩阵如下特征匹配 单应性教程 https docs opencv org 3 4 1 d1 de0 tutorial py feature homography html using M mask cv2 findHomograp
  • OpenCV 仅围绕大轮廓绘制矩形?

    第一次发帖 希望我以正确的方式放置代码 我正在尝试检测和计算视频中的车辆 因此 如果您查看下面的代码 我会在阈值处理和膨胀后找到图像的轮廓 然后我使用 drawContours 和矩形在检测到的轮廓周围绘制一个框 我试图在 drawCont

随机推荐