-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathWordSegmentation.py
113 lines (88 loc) · 3.82 KB
/
WordSegmentation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import math
import cv2
import numpy as np
def wordSegmentation(img, kernelSize=23, sigma=11, theta=7, minArea=0):
"""Scale space technique for word segmentation proposed by R. Manmatha: http://ciir.cs.umass.edu/pubfiles/mm-27.pdf
Args:
img: grayscale uint8 image of the text-line to be segmented.
kernelSize: size of filter kernel, must be an odd integer.
sigma: standard deviation of Gaussian function used for filter kernel.
theta: approximated width/height ratio of words, filter function is distorted by this factor.
minArea: ignore word candidates smaller than specified area.
Returns:
List of tuples. Each tuple contains the bounding box and the image of the segmented word.
"""
# apply filter kernel
kernel = createKernel(kernelSize, sigma, theta)
imgFiltered = cv2.filter2D(img, -1, kernel, borderType=cv2.BORDER_REPLICATE).astype(np.uint8)
(_, imgThres) = cv2.threshold(imgFiltered, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
imgThres = 255 - imgThres
# find connected components. OpenCV: return type differs between OpenCV2 and 3
if cv2.__version__.startswith('3.'):
(_, components, _) = cv2.findContours(imgThres, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
else:
(components, _) = cv2.findContours(imgThres, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# append components to result
res = []
for c in components:
# skip small word candidates
if cv2.contourArea(c) < minArea:
continue
# append bounding box and image of word to result list
currBox = cv2.boundingRect(c) # returns (x, y, w, h)
(x, y, w, h) = currBox
currImg = img[y:y+h, x:x+w]
res.append((currBox, currImg))
# return list of words, sorted by x-coordinate
return sorted(res, key=lambda entry:entry[0][0])
def prepareImg(img, height):
"""convert given image to grayscale image (if needed) and resize to desired height"""
assert img.ndim in (2, 3)
if img.ndim == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h = img.shape[0]
factor = height / h
return cv2.resize(img, dsize=None, fx=factor, fy=factor)
def createKernel(kernelSize, sigma, theta):
"""create anisotropic filter kernel according to given parameters"""
assert kernelSize % 2 # must be odd size
halfSize = kernelSize // 2
kernel = np.zeros([kernelSize, kernelSize])
sigmaX = sigma
sigmaY = sigma * theta
for i in range(kernelSize):
for j in range(kernelSize):
x = i - halfSize
y = j - halfSize
expTerm = np.exp(-x**2 / (2 * sigmaX) - y**2 / (2 * sigmaY))
xTerm = (x**2 - sigmaX**2) / (2 * math.pi * sigmaX**5 * sigmaY)
yTerm = (y**2 - sigmaY**2) / (2 * math.pi * sigmaY**5 * sigmaX)
kernel[i, j] = (xTerm + yTerm) * expTerm
kernel = kernel / np.sum(kernel)
return kernel
def seg(image):
"""reads images from data/ and outputs the word-segmentation to out/"""
# read input images from 'in' directory
l=[]
# read image, prepare it by resizing it to fixed height and converting it to grayscal
## print(image)
img = prepareImg(image, 50)
#print(img.shape)
## img= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY);
# execute segmentation with given parameters
# -kernelSize: size of filter kernel (odd integer)
# -sigma: standard deviation of Gaussian function used for filter kernel
# -theta: approximated width/height ratio of words, filter function is distorted by this factor
# - minArea: ignore word candidates smaller than specified area
res = wordSegmentation(img, kernelSize=3, sigma=5, theta=2, minArea=100)
for (j, w) in enumerate(res):
(wordBox, wordImg) = w
(x, y, w, h) = wordBox
## cv2.imwrite('../out/%s/%d.png'%(f, j), wordImg) # save word
cv2.rectangle(img,(x,y),(x+w,y+h),0,1) # draw bounding box in summary image
# output summary image with bounding boxes around words
## print(wordImg)
wordImg=np.pad(wordImg, ((4,4),(4,4)),"constant",constant_values=(255))
l.append(wordImg)
#cv2.imshow("segmen",img)
return l