如何删除构成框/表的所有垂直和水平线
我已经搜索并尝试过。但是无法使其工作
最近几天尝试搜索它。.找到了一些不起作用的示例。.试图将各个部分放在一起。
cv:Mat img = cv::imread(input, CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat grad;
cv::Mat morphKernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
cv::morphologyEx(img, grad, cv::MORPH_GRADIENT, morphKernel);
cv::Mat res;
cv::threshold(grad, res, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// find contours
cv::Mat mask = cv::Mat::zeros(res.size(), CV_8UC1);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(res, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
for(int i = 0; i < contours.size(); i++){
cv::Mat approx;
double peri = cv::arcLength(contours[i], true);
cv::approxPolyDP(contours[i], approx, 0.04 * peri, true);
int num_vertices = approx.rows;
if(num_vertices == 4){
cv::Rect rect = cv::boundingRect(contours[i]);
// this is a rectangle
}
}
答案 0 :(得分:1)
您可以尝试类似的方法:
以下是相关的源代码:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <limits>
using namespace cv;
struct BBox {
BBox() :
_xMin(std::numeric_limits<int>::max()),
_xMax(std::numeric_limits<int>::min()),
_yMin(std::numeric_limits<int>::max()),
_yMax(std::numeric_limits<int>::min())
{}
int _xMin;
int _xMax;
int _yMin;
int _yMax;
};
int main()
{
// read input image
Mat inputImg = imread("test3_1.tif", IMREAD_GRAYSCALE);
// create binary image
Mat binImg;
threshold(inputImg, binImg, 254, 1, THRESH_BINARY_INV);
// compute connected components
Mat labelImg;
const int nbComponents = connectedComponents(binImg, labelImg, 8, CV_32S);
// compute associated bboxes
std::vector<BBox> bboxColl(nbComponents);
for (int y = 0; y < labelImg.rows; ++y) {
for (int x = 0; x < labelImg.cols; ++x) {
const int curLabel = labelImg.at<int>(y, x);
BBox& curBBox = bboxColl[curLabel];
if (curBBox._xMin > x)
curBBox._xMin = x;
if (curBBox._xMax < x)
curBBox._xMax = x;
if (curBBox._yMin > y)
curBBox._yMin = y;
if (curBBox._yMax < y)
curBBox._yMax = y;
}
}
// parse all labels
std::vector<bool> lutTable(nbComponents);
for (int i=0; i<nbComponents; ++i) {
// check current label width
const BBox& curBBox = bboxColl[i];
if (curBBox._xMax - curBBox._xMin > labelImg.cols * 0.3)
lutTable[i] = false;
else
lutTable[i] = true;
}
// create output image
Mat resImg(binImg);
MatConstIterator_<int> iterLab = labelImg.begin<int>();
MatIterator_<unsigned char> iterRes = resImg.begin<unsigned char>();
while (iterLab != labelImg.end<int>()) {
if (lutTable[*iterLab] == true)
*iterRes = 1;
else
*iterRes = 0;
++iterLab;
++iterRes;
}
// write result
imwrite("resImg3_1.tif", resImg);
}
我只需删除所有大于图像总宽度30%的标签。您的图片很吵,所以我不能像以前说的那样使用边框顶部的修饰,对不起...
不知道这是否与您所有的图片都匹配,但是您可以添加一些几何滤镜来改进第一个版本。
此致
答案 1 :(得分:1)
您可以为此目的使用LineSegmentDetector:
import numpy as np
import cv2
image = cv2.imread("image.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# This is the detector, you might have to play with the parameters
lsd = cv2.createLineSegmentDetector(0, _scale=0.6)
lines, widths, _, _ = lsd.detect(gray)
if lines is not None:
for i in range(0, len(lines)):
l = lines[i][0]
# Much slower version of Euclidean distance
if np.sqrt((l[0]-l[2])**2 + (l[1]-l[3])**2) > 50:
# You might have to tweak the threshold as well for other images
cv2.line(image, (l[0], l[1]), (l[2], l[3]), (255, 255, 255), 3,
cv2.LINE_AA)
cv2.imwrite("result.png", image)
输出:
如您所见,顶部图像中的行并未完全删除,因此我将 tweatking 部分留给您。希望对您有帮助!
答案 2 :(得分:0)
我想使用此答案框发表一些评论。
首先,如果您可以轻松地直观地看到输出效果,则它更容易查看进度。考虑到这一点,这里是代码的更新,重点是查看临时结果。我在Win10中使用VS Studio Community 2017和OpenCV version 4.0.1(64位)供任何想重复此练习的人使用。有一些例程需要OpenCV 4的更新...
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
int main()
{
cv::Mat img = cv::imread("0zx9Q.png", cv::IMREAD_GRAYSCALE ); // --> Contour size = 0x000000e7 hex (231 each)
// cv::Mat img = cv::imread("0zx9Q.png", cv::IMREAD_REDUCED_GRAYSCALE_2); // --> Contour size = 0x00000068 hex (104 each)
// cv::Mat img = cv::imread("0zx9Q.png", cv::IMREAD_REDUCED_GRAYSCALE_4); // --> Contour size = 0x0000001f hex (31 each)
// cv::Mat img = cv::imread("0zx9Q.png", cv::IMREAD_REDUCED_GRAYSCALE_8); // --> Contour size = 0x00000034 hex (52 each)
if (!img.data) // Check for invalid input
{
std::cout << "Could not open or find the image" << std::endl;
return -1;
}
// cv::namedWindow("Display Window - GrayScale Image", cv::WINDOW_NORMAL); // Create a window for display.
// cv::imshow("Display Window - GrayScale Image", img); // Show our image inside it.
// cv::waitKey(0); // Wait for a keystroke in the window
cv::Mat imgOriginal = cv::imread("0zx9Q.png", cv::IMREAD_UNCHANGED);
cv::namedWindow("Display Window of Original Document", cv::WINDOW_NORMAL); // Create a window for display.
cv::Mat grad;
cv::Mat morphKernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(25, 25));
// MORPH_ELLIPSE, contourSize: 0x00000005 when 60,60... but way slow...
// MORPH_ELLIPSE, contourSize: 0x00000007 when 30,30...
// MORPH_ELLIPSE, contourSize: 0x00000007 when 20,20...
// MORPH_ELLIPSE, contourSize: 0x0000000a when 15,15...
// MORPH_ELLIPSE, contourSize: 0x0000007a when 5,5...
// MORPH_ELLIPSE, contourSize: 0x000000e7 when 3,3 and IMREAD_GRAYSCALE
// MORPH_CROSS, contourSize: 0x0000008e when 5,5
// MORPH_CROSS, contourSize: 0x00000008 when 25,25
// MORPH_RECT, contourSize: 0x00000007 when 25,25
cv::morphologyEx(img, grad, cv::MORPH_GRADIENT, morphKernel);
cv::Mat res;
cv::threshold(grad, res, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// find contours
cv::Mat mask = cv::Mat::zeros(res.size(), CV_8UC1);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(res, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
int contourSize = contours.size();
std::cout << " There are a total of " << contourSize << " contours. \n";
for (int i = 0; i < contourSize; i++) {
cv::Mat approx;
double peri = cv::arcLength(contours[i], true);
cv::approxPolyDP(contours[i], approx, 0.04 * peri, true);
int num_vertices = approx.rows;
std::cout << " Contour # " << i << " has " << num_vertices << " vertices.\n";
if (num_vertices == 4) {
cv::Rect rect = cv::boundingRect(contours[i]);
cv::rectangle(imgOriginal, rect, cv::Scalar(255, 0, 0), 4);
}
}
cv::imshow("Display Window of Original Document", imgOriginal); // Show our image inside it.
cv::waitKey(0); // Wait for a keystroke in the window
}
话虽如此,getStructuringElement()
的参数非常重要。我花了很多时间尝试不同的选择,但结果却参差不齐。事实证明,有很多findContours()
响应没有四个顶点。我怀疑整个findContours()
方法可能有缺陷。我经常会在单词和短语的文本字符周围发现错误的矩形。此外,围绕某些框状区域的较浅线条将被忽略。
相反,如果C ++而非python存在这样的响应,我想我会努力研究直线检测via techniques discussed here。也许是here还是here?我希望线路检测技术最终能获得更好的结果。嘿,如果所选的文档/图像始终包含白色背景,则可以很容易地通过LineTypes: cv::FILLED
此处提供的信息,不是作为已发布问题的答案,而是作为直观地确定未来成功的方法。