【问题标题】:Detecting and Removing Vertical and Horizontal Lines in OpenCV在 OpenCV 中检测和删除垂直和水平线
【发布时间】:2019-06-12 08:53:09
【问题描述】:

我正在尝试使用 opencv (Python) 从填写好的表格中删除方框(垂直和水平线)。我试图通过OpenCV的形态学操作来检测垂直和水平线。

检测垂直线和水平线后。

垂直线

检测到水平线和垂直线后,我只是将它们相加并从处理后的图像中减去。 res = verticle_lines_img + horizontal_lines_img exp = img_bin - res

最终结果并没有预期的那么平滑。

完整的代码是

# Read the image
img_for_box_extraction_path='aligned_filled.jpg'
img = cv2.imread(img_for_box_extraction_path, 0)
# Thresholding the image
(thresh, img_bin) = cv2.threshold(img, 128, 255,cv2.THRESH_BINARY|     
cv2.THRESH_OTSU)
# Invert the image
img_bin = ~img_bin
cv2.imwrite("Image_bin.jpg",img_bin)
bw = cv2.adaptiveThreshold(img_bin, 255, cv2.ADAPTIVE_THRESH_MEAN_C, \
                            cv2.THRESH_BINARY, 15, -2)
horizontal = np.copy(bw)
vertical = np.copy(bw)
# Defining a kernel length for horizontal and vertical 
cols = horizontal.shape[1]


horizontal_size = int(cols)
horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, 
(horizontal_size, 1))
# Apply morphology operations
horizontal = cv2.erode(horizontal, horizontalStructure)
horizontal = cv2.dilate(horizontal, horizontalStructure)
rows = vertical.shape[0]

verticalsize = int(rows)
# Create structure element for extracting vertical lines through morphology 
operations
verticalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 
verticalsize))
# Apply morphology operations
vertical = cv2.erode(vertical, verticalStructure)
vertical = cv2.dilate(vertical, verticalStructure)
#kernel_length = np.array(img).shape[1]//80
#kernel_length = 7
# A verticle kernel of (1 X kernel_length =6), which will detect all the 
verticle lines from the image.
verticle_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 6))
# A horizontal kernel of (kernel_length=7 X 1), which will help to detect 
all the horizontal line from the image.
hori_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 1))
# A kernel of (3 X 3) ones.
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))


# Morphological operation to detect vertical lines from an image
img_temp1 = cv2.erode(img_bin, verticle_kernel, iterations=3)
verticle_lines_img = cv2.dilate(img_temp1, verticle_kernel, iterations=2)
cv2.imwrite("verticle_lines.jpg",verticle_lines_img)
# Morphological operation to detect horizontal lines from an image


img_temp2 = cv2.erode(img_bin, hori_kernel, iterations=3)
horizontal_lines_img = cv2.dilate(img_temp2, hori_kernel, iterations=2)
cv2.imwrite("horizontal_lines.jpg",verticle_lines_img)


res = verticle_lines_img + horizontal_lines_img
#fin = cv2.bitwise_and(img_bin, img_bin, mask = cv2.bitwise_not(res))
exp = img_bin - res
exp = ~exp
cv2.imwrite("final.jpg",exp)

有什么新方法可以检测和移除方框?

【问题讨论】:

  • 检测到线条后,扩大检测到的线条使其变粗,然后使用此图像作为蒙版,将原始图像中的那部分像素变为白色。
  • @zindarod 在代码 cv2.dilate() 中我在检测到它并将其用作掩码时将其用于水平和垂直。你能举个例子吗?
  • 只考虑一点需要考虑:像'L','I'和类似的字母可以被你的方法检测和删除,可能你需要一些东西来验证你的内核找到的行跨度>
  • 我设法做到了这一点,唯一的问题是它删除了盒子里的一堆东西imgur.com/a/IVKOiRc
  • @chris,你用什么方法来达到这个目的。

标签: python opencv opencv3.0


【解决方案1】:

网格线比文字细,所以我建议如下:

阈值->侵蚀->去除小斑点->扩张

这是上述方法的结果:

我一直以错误的语言提供示例代码,这让我感觉很糟糕,但这是生成 C++ 的结果。我认为函数调用在 python 中应该非常相似。特别是关于 blob 删除的注释 (How to remove small connected objects using OpenCV) 这个人在 python 中执行它,它比我的更干净,所以我建议你参考它来删除你的小 blob。我删除了小于 15 px 的任何东西,这是我尝试的第一件事。我可能已经杀死了一些具有如此高限制的角色(没有检查),所以你会想要为你的目的找到正确的值。

int main(int argc, char** argv)
{
    Mat image = imread("../../resources/images/fullForm.jpg", CV_LOAD_IMAGE_GRAYSCALE);

    Mat thresholded, errodedImage, openedImage;
    threshold(image, thresholded, 200, 255, THRESH_BINARY_INV);

    //errode first
    erode(thresholded, errodedImage, getStructuringElement(MORPH_CROSS, Size(3, 3)), cv::Point(-1, -1), 1);

    //delete any blobs with less than 15 px
    Mat labels, stats, centroids;
    Mat deblobbedImage = errodedImage.clone();
    int nccomps = connectedComponentsWithStats(errodedImage, labels, stats, centroids);
    std::vector<int> smallBlobs = std::vector<int>();
    for (int i = 0; i < nccomps; i++)
    {
        if (stats.at<int>(i, CC_STAT_AREA) < 15)
        {
            smallBlobs.push_back(0);
        }
        else
        {
            smallBlobs.push_back(1);
        }
    }

    for (int y = 0; y < errodedImage.rows; y++)
    {
        for (int x = 0; x < errodedImage.cols; x++)
        {
            int label = labels.at<int>(y, x);
            CV_Assert(0 <= label && label <= nccomps);
            if (smallBlobs[label] == 0)
            {
                deblobbedImage.at<uchar>(y, x) = 0;
            }
        }
    }

    //dilate to restore text
    dilate(deblobbedImage, openedImage, getStructuringElement(MORPH_CROSS, Size(3, 3)), cv::Point(-1, -1), 1);

    imshow("source", image);
    imshow("Thresholded", thresholded);
    imshow("erroded", errodedImage);
    imshow("deblobbed", deblobbedImage);
    imshow("finished", openedImage);
    waitKey(0);
    return 0;
}

【讨论】: