1

The objective is to remove uneven vertical and horizontal lines from an images using cv2 Python.

Currently, I am using these two code block to remove the horizontal and vertical lines.

Remove vertical and horizontal line

nimg_v=gray.copy()
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 40))
detLines = cv2.morphologyEx(nimg_v, cv2.MORPH_OPEN, kernel, iterations=2) #
nimg_v[(detLines !=0)]=0

# Remove horizontal lines
nimg_h=nimg_v.copy()
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,30))
detLines = cv2.morphologyEx(nimg_h, cv2.MORPH_OPEN, kernel, iterations=1)
nimg_h[(detLines !=0)]=0

Despite adjusting the Size of the structuring element, but I am still unable to remove most of the lines while maintaining the text.

The full code is

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

dpath='so_images/dummy_image.jpg'

im = cv2.imread(dpath)
# Rough estimation the starting point of text region
y,x=50,700

# Rough estimation where the end of text region
y_end, x_end=1500,1350
white_bg = 255*np.ones_like(im)
white_bg[y:y+(y_end-y), x:x+(x_end-x)] =im[y:y+(y_end-y), x:x+(x_end-x)]
gray=cv2.cvtColor(white_bg, cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
dilate = cv2.dilate(gray, kernel, iterations = 2)
idx = (dilate==255)
gray[idx]=0

## Remove vertical and horizontal line

nimg_v=gray.copy()
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 40))
detLines = cv2.morphologyEx(nimg_v, cv2.MORPH_OPEN, kernel, iterations=2) #
nimg_v[(detLines !=0)]=0

# Remove horizontal lines
nimg_h=nimg_v.copy()
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,30))
detLines = cv2.morphologyEx(nimg_h, cv2.MORPH_OPEN, kernel, iterations=1)
nimg_h[(detLines !=0)]=0



img_sm=nimg_h.copy()
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2,2))
dilate = cv2.dilate(img_sm, kernel, iterations = 4)

img_sm[(dilate !=0)]=255


img_cont=img_sm.copy()
schunk_small=800
schunk_big=50000
cnts = cv2.findContours(img_cont, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if (area < schunk_small) | (area>schunk_big):
        cv2.drawContours(img_cont, [c], -1, (0, 0, 0), -1)

plt.imshow(img_cont)
plt.show()

In addition, I also try using HoughLinesP and filter based on the slope <1 as below. However, I am still unable to remove the lines.

edges = cv2.Laplacian(img_cont,cv2.CV_8UC1) # Laplacian Edge Detection

lines = cv2.HoughLinesP(
    edges, # Input edge image
    1, # Distance resolution in pixels
    np.pi/180, # Angle resolution in radians
    threshold=100, # Min number of votes for valid line
    minLineLength=5, # Min allowed length of line
    maxLineGap=10 # Max allowed gap between line for joining them
)

lines_list = []

for points in lines:
    x1,y1,x2,y2=points[0]
    slope = ((y2-y1) / (x2-x1)) if (x2-x1) != 0 else np.inf
    if slope <= 1:
        cv2.line(img_cont,(x1,y1),(x2,y2),(255,255,255),1)
mpx
  • 3,081
  • 2
  • 26
  • 56
  • "uneven vertical and horizontal lines" please point those out in the picture, and explain why they are an issue. all I see is an overexposed picture of a bond wire on the pad of a chip, besieged by squirrels! -- "OCR is unable to..." please illustrate how OCR is distracted by other features in the picture that are reasonably far away from those letters – Christoph Rackwitz May 28 '22 at 10:09
  • 1
    I dont know whether it was you @ChristophRackwitz or this is rather coincident , but I dont understand why the need to vote for `close`. Something similar happen in my post here https://stackoverflow.com/q/72358173/6446053 – mpx May 28 '22 at 10:30
  • The bounty doesn’t allow me to vote as duplicate, but I think this other Q&A, though not identical, solves your problem. https://stackoverflow.com/a/54029190/7328782 – Cris Luengo Jun 05 '22 at 16:14

1 Answers1

0

By convolving the image with low pass filter with a custom kernel can remove thin vertical and horizontal lines in your image. Since the thickness of alphanumeric characters is much higher than those lines, it can filter those lines. By adding below code gave me these results -

kernel = np.full(fill_value=1/(18*18*250), shape=(18,18), dtype=float)
img_rst = cv2.filter2D(img_cont,-1,kernel)
plt.imshow(img_rst)
plt.show()

enter image description here

YadneshD
  • 396
  • 2
  • 12
  • For completeness, maybe you can try to clean to horizontal as well. But, I can see your solution is better than what I am having now, albeit take more time to complete – mpx Jun 01 '22 at 11:44
  • this code is equivalent to a lowpass. the choice to use a box blur rather than other shapes (gaussian) is arbitrary. OpenCV has `cv::boxFilter` https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html#gad533230ebf2d42509547d514f7d3fbc3 there's nothing custom about it except the choice of kernel size. – Christoph Rackwitz Jun 01 '22 at 14:54
  • If you haven't tested cv2.boxFliter. Then the answer is NO! The gaussian is right to do the job. – toyota Supra Jun 04 '22 at 02:05