karolzak / boxdetect

BoxDetect is a Python package based on OpenCV which allows you to easily detect rectangular shapes like character or checkbox boxes on scanned forms.
MIT License
105 stars 20 forks source link

Removing noise while preserving the boundary of the checkbox #21

Closed waiyeung1 closed 2 years ago

waiyeung1 commented 2 years ago

This is not a bug but a request for help.

I am trying to identify the checkboxes in the attached image (clip2.png). The top 4 are identified but the bottom 2 are not. I've tried various dilation and kernel sizes but I haven't been able to successful get the box. At the same time I would like to be able to get rid of the peppering to avoid false positives as there are other docs that have checkmarks that are much smaller.

I've attached the configuration ([boxdetect_cfg.yaml.txt) being used as well.

Any suggestion will be appreciated.

boxdetect_cfg.yaml.txt

clip2 t

karolzak commented 2 years ago

Hi @waiyeung1 Just by knowing how the algorithm works and by looking at the example you shared I'd say it will be hard to capture these 2 checkboxes on the bottom because they are missing the whole top section so the pixels don't even make a full rectangle there. I will give it a try and let you know how it goes but overall I don't think it will work without some major changes in the algo.

image
waiyeung1 commented 2 years ago

Hi @karolzak , Thanks for your responding so quickly. I posted the question on StackOverflow as well. https://stackoverflow.com/questions/72147441/how-to-detect-checkboxes-by-removing-noise-using-python-opencv

The method proposed follows very closely to what's implemented in boxdetect. When I get more time, I'll see if I can make changes to boxdetect to get it working. Cheers, Wai

karolzak commented 2 years ago

So I finally had a chance to look into it and after running few iterations I was able to make BoxDetect work for the example you provided. It's not perfect but seems to work: image

Here's the code I used:

from boxdetect import config

cfg = config.PipelinesConfig()

# important to adjust these values to match the size of boxes on your image
cfg.width_range = (40, 50)
cfg.height_range = (35, 45)

# the more scaling factors the more accurate the results but also it takes more time to processing
# too small scaling factor may cause false positives
# too big scaling factor will take a lot of processing time
cfg.scaling_factors = [1.4]

# w/h ratio range for boxes/rectangles filtering
cfg.wh_ratio_range = (0.9, 1.1)

# for this image we will use rectangles as a kernel for morphological transformations
cfg.morph_kernels_type = ['rectangles']
cfg.morph_kernels_thickness = 2

# num of iterations when running dilation tranformation (to engance the image)
cfg.dilation_kernel = [(5,1), (1,5)]
cfg.dilation_iterations = 1

from boxdetect.pipelines import get_checkboxes

file_path = 'github1.png'

# had to modify px_threshold for tick detection because of the presence of noise pixels
checkboxes = get_checkboxes(
    file_path, cfg=cfg, px_threshold=0.4, plot=False, verbose=True)

from boxdetect.img_proc import draw_rects, get_image
import cv2
import matplotlib.pyplot as plt
%matplotlib inline

input_image = cv2.imread(file_path)
out_img = draw_rects(input_image, checkboxes[:,0], thickness=2)

plt.figure(figsize=(15,20))
plt.imshow(out_img)
plt.show()
waiyeung1 commented 2 years ago

Hi Karol, Thanks for your efforts. Unfortunately, I can't increase the px_threshold as there are some samples where the checkmarks in the checkboxes are actually quite small and don't have as much noise.

Cheers, Wai