absolutely_dumb
absolutely_dumb

Reputation: 21

OpenCV polygon detection methods

So I have a digital form with fields like this:

The problem is that people fill these fields in many different ways: different colors

gradients and so on. So the only thing that remains consistent is the shape of the field.

How do I detect all such shapes and make sure that they are filled. Tried template matching but it doesn't work consistently on images with gradients or with images of low contrast where thresholding doesn't help much, and now I'm stuck.

I use OpenCV 3.1 along with Python 2.7.

EDIT: Tried to do it this way. It seems to provide results that are much more convenient for further processing but I'm still confused about next step.

import cv2

base_img = cv2.imread("form_base.png", 0)
form_img = cv2.imread("test2.png", 0)
ret,thresh1 = cv2.threshold(base_img,244,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(form_img,244,255,cv2.THRESH_BINARY)

res = thresh1 - thresh2

cv2.imwrite("test_output.png", res)

That's what I got

Upvotes: 0

Views: 1668

Answers (1)

dungeoneering
dungeoneering

Reputation: 81

The task is pretty easy if you do image segmentation with connectedComponents and then characterize the blobs found. This is one possible approach:

    import cv2
    import numpy as np
    import matplotlib.pyplot as plt 

    img = cv2.imread('test2.png')
    # Convert image to grayscale and get threshold image or mask:
    g = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    th, im_th = cv2.threshold(g, 220, 250, cv2.THRESH_BINARY_INV)
    # Opening, just to have delimited edges and make sure to separate each component:
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(2,2))
    im_th2 = cv2.morphologyEx(im_th, cv2.MORPH_OPEN, kernel)
    # Connected Components segmentation:
    maxLabels, labels = cv2.connectedComponents(im_th2)
    plt.imshow(labels)

image segmented

As you can see, those components filled will be bigger in size (number of pixels) than the ones not filled, so you can get the size of each component and see if is filled or not. For example: You can get the maximum value of blob sizes, and make a threshold, since, as observed, those not filled will have less than half the size of those filled:

   # Get size of blobs: First value is always "empty" space, 0 on the mask, so discard it 
   sizes = np.array([len(labels[labels==i]) for i in range(1,maxLabels)])
   # Threshold with minimum value:
   thSizes = np.max(sizes)/2

You can count the number of filled components or do other desired operations from here:

   n_blobs = len(sizes[sizes>thSizes])
   print('There are ' + str(n_blobs) + ' fields filled.')
   >>>There are 6 fields filled.

Upvotes: 1

Related Questions