Using dilation in only one direction?
Asked Answered
A

2

6

This is my first post on Stack Overflow, so I am sorry if the problem isn't defined enough.

I am currently working on extracting table data from images and I need a way to dilate the text only in a vertical direction so that I can get clear column representation that will be used for further segmentation.

After removing horizontal and vertical lines and transforming the image bitwise, I am at this stage:

Current state after dilation and line extraction

The ideal goal for this problem would be:

The goal

Is there a method or an algorithm that would be helpful in my case?

Alizaalizarin answered 26/11, 2019 at 11:36 Comment(4)
When using cv2.dilate, you can set up a custom kernel. Use a 3 x 1 (rows x columns) white rectangle here, and set iterations large enough.Chilson
Maybe you can dilate by a vertical kernel with width of 1. I don't know if it works, but I think that should dilate only on vertical direction.Lac
Thank You, I will try that.Emilyemina
You can also set a kernel with a reasonable height and perform only one iteration (see my answer below).Verger
V
6

You can just call cv2.dilate with the appropriate structuring element.

import cv2

pre_img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
h, w = pre_img.shape

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, ksize=(1, 2 * h))

dilated = cv2.dilate(pre_img, kernel)

cv2.imshow('input', pre_img)
cv2.imshow('output', dilated)
cv2.waitKey(0)

Input input image

Output output image

To visualize better what's happening:

blended = (pre_img.astype(float) + dilated.astype(float)) / 2
cv2.imshow('blended', blended.astype(np.uint8))
cv2.waitKey(0)

Blended image blend

Verger answered 26/11, 2019 at 11:58 Comment(0)
E
4

It looks like you don’t want a dilation, but a maximum projection. For each column, check to see if any pixel is set. Use numpy.any for that:

result = np.any(image, axis=0)
Epi answered 26/11, 2019 at 15:25 Comment(3)
This is much more efficient than using a convolution approach. Maybe add a .reshape(image.shape) at the end to get the 2D image, depending on the use case.Dispel
@Dispel np.tile would be more suited to convert the projection back into a 2D image. Might be necessary or not depending on subsequent operations. Implicit broadcasting might make it unnecessary.Epi
You are right, my mistake. It should be np.tile(np.any(image, axis=0), (image.shape[0], 1)). I agree that it is usually not needed.Dispel

© 2022 - 2024 — McMap. All rights reserved.