2

I used Hough lines to get intersection of horizontal and vertical lines in this image:

enter image description here

but the complexity grows with the grid cells count significantly.

Is there any simple way to complete the grid without using line detection ?

Thank you.

nathancy
  • 42,661
  • 14
  • 115
  • 137
Ziri
  • 718
  • 7
  • 16

2 Answers2

6

Here's a potential solution using morphological operations with OpenCV

  1. Obtain binary image. Load image, grayscale, Gaussian blur, Otsu's threshold

  2. Obtain horizontal/vertical lines masks. Create horizontal/vertical kernel and isolate horizontal/vertical grid lines with cv2.getStructuringElement() and cv2.morphologyEx()

  3. Combine masks. Bitwise-and masks together to complete grid

  4. Fill individual grid holes. Find contours and fix holes by filling in each grid cell


Binary image

Horizontal mask (left) and vertical mask (right)

Combine masks

Repair individual grid holes

Invert for result

import cv2

# Load image, grayscale, blur, Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Obtain horizontal lines mask
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
horizontal_mask = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=1)
horizontal_mask = cv2.dilate(horizontal_mask, horizontal_kernel, iterations=9)

# Obtain vertical lines mask
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
vertical_mask = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=1)
vertical_mask= cv2.dilate(vertical_mask, vertical_kernel, iterations=9)

# Bitwise-and masks together
result = 255 - cv2.bitwise_or(vertical_mask, horizontal_mask)

# Fill individual grid holes
cnts = cv2.findContours(result, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(result, (x, y), (x + w, y + h), 255, -1)

cv2.imshow('thresh', thresh)
cv2.imshow('vertical_mask', vertical_mask)
cv2.imshow('horizontal_mask', horizontal_mask)
cv2.imshow('result', result)
cv2.waitKey()
nathancy
  • 42,661
  • 14
  • 115
  • 137
  • What should I do if some of the grid lines are 100% gone, for example I have a table with only vertical lines and Iw ant to draw the horizontal ones? – Dolev Mitz Feb 14 '23 at 05:40
  • I created a question about it @nathancy https://stackoverflow.com/questions/75444109/draw-grid-on-a-gridless-fully-or-partially-table-image – Dolev Mitz Feb 14 '23 at 09:21
2

I thought of a creative solution that based on morphological operations.

The final result is not so impressive, and I don't know if it fulfills your goals.

I implemented the code in MATLAB (you didn't add a language tag).

Here is the code (details are in the comments):

I = imread('RedGrid.jpg'); %Read grid image
BW = imbinarize(rgb2gray(I)); %Convert to from RGB to Grayscale, and to binary image.
BW = ~BW; %Inverse polarity

BW = padarray(BW, [1, 1], 1); %Insert frame of white pixels around the image

BW1 = imerode(BW, ones(1, 20)); % Remove vertical lines by erode with short horizontal kernel
BW1 = imdilate(BW1, ones(1, 600)); %Complete horizontal line by dilate with long horizontal kernel
BW1 = imerode(BW1, ones(1, 800)); %Remove some of the horizontal duplications using erode with long horizontal kernel

imwrite(BW1, 'BW1.jpg')

%Repeat the above 3 stages with horizontal lines:
BW2 = imerode(BW, ones(20, 1)); % Remove vertical lines by erode with short horizontal kernel
BW2 = imdilate(BW2, ones(600, 1)); %Complete horizontal line by dilate with long horizontal kernel
BW2 = imerode(BW2, ones(800, 1)); %Remove some of the horizontal duplication using erode with long horizontal kernel

BW = BW1 | BW2; % Merge horizontal and vertical lines.

BW = BW(2:end-1, 2:end-1); %Remove the white frame added at the beginning.

%Paint lines with red color (assume the desired red is RGB = [220, 20, 20])
R = im2uint8(~BW); %Red color channel
G = im2uint8(~BW); %Green color channel
B = im2uint8(~BW); %Blue color channel
R(BW) = 220; %Red color
G(BW) = 20;
B(BW) = 20;

J = cat(3, R, G, B); % Create RGB image from R, G and B.

Results:

BW1:
enter image description here

BW2:
enter image description here

J:
enter image description here

Rotem
  • 30,366
  • 4
  • 32
  • 65
  • Thank you . Your approach needs morphological filter parameters tuning for other cases but it works for this one. – Ziri Feb 25 '20 at 13:40