代码已开源
github 地址:
https://github.com/KaiJin1995/tesseract_cardRecognition
本实验是识别放在桌子上的卡片上的英文人名、日期和编号。不要中文字符和其他英文字符。而限制条件在于没有大规模数据集,因此无法使用学习的方法完成这个任务。由于编号人名等信息在卡片上的位置相对固定,因此,采用了规则操作加图像形态学操作。分成了三个步骤:
1. 预处理(卡片区域获取)
2. 检测部分(定位卡片中的英文人名、编号和日期)
3. 识别部分(识别卡片中的人名编号和日期,这里采用tesseract)
关键点在于:灰度化、二值化、自适应、膨胀腐蚀、颜色变换。
解决的难点在于:有光照等亮度变化,对于灰度化和二值化等操作有影响。
预处理
首先检测图像中的card位置,在这里采用了膨胀腐蚀以及颜色变换的思想。由于数据集保密的原因,暂时不方便公开。
数据集特点:卡片是蓝色的、背景是桌面
颜色变换是图片中的使将蓝色部分保留。即灰度图只有蓝色部分是白色,其他均为黑色。
def img_change(img_a): # 保留蓝色部分
img_shape = img_a.shape
img = img_a.copy()
h = img_shape[0]
w = img_shape[1]
for i in range(h):
for j in range(w):
if (img[i, j, 0] > img[i, j, 1] and img[i, j, 0] > img[i, j, 2] and img[i, j, 0] > 100):
img[i, j, 1] = 0
img[i, j, 2] = 0
img[i, j, 0] = 255
else:
img[i, j, 1] = 0
img[i, j, 2] = 0
img[i, j, 0] = 0
return img
这样卡片区域变得更加明显,然后使用腐蚀膨胀,去噪并且得到卡片区域,使用卡片面积筛选其他小区域,便可以得到准确的卡片区域。
对应的代码如下
def img_preprocess(img):
img_rgb = cv2.resize(img, (1000, 1600))
img_save = img_change(img_rgb)
gray_b = cv2.split(img_save)[0]
ret, binary = cv2.threshold(gray_b, 180, 255, cv2.THRESH_BINARY)
ele = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10))
eroded = cv2.erode(binary, ele)
ele = cv2.getStructuringElement(cv2.MORPH_RECT, (60, 60))
diated = cv2.dilate(eroded, ele)
image, contours, hierarchy = cv2.findContours(diated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
cnt = contours[i]
area = cv2.contourArea(cnt)
# areas.append(area)
if area < 400000:
continue
rect = cv2.minAreaRect(cnt)
img_crop = crop_minAreaRect(img_rgb, rect)
img_crop = cv2.resize(img_crop, (1600, 1000))
return img_crop
这样可以得到crop的卡片。
检测
根据检测出卡片的彩图,对其灰度化->二值化->分区域腐蚀->分区域膨胀->获得最小矩形->规则排除其他区域->得到所选区域。代码如下所示:
def detect(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2. 形态学变换的预处理,得到可以查找矩形的图片
dilation = morph_process(gray)
# 3. 查找和筛选文字区域
region = findTextRegion(dilation)
# 4. 用绿线画出这些找到的轮廓
ii = 0
idImgs = []
for box in region:
h = abs(box[0][1] - box[2][1])
w = abs(box[0][0] - box[2][0])
Xs = [i[0] for i in box]
Ys = [i[1] for i in box]
x1 = min(Xs)
y1 = min(Ys)
img2 = img.copy()
if w > 0 and h > 0:
idImg = grayImg(img2[y1:y1 + h, x1:x1 + w])
ii += 1
idImgs.append(idImg)
return idImgs
识别
使用tesseract识别,tesseract识别需要很好的预处理才能识别正确,因此前面的预处理很重要。
由检测得到的bounding box,我们可以获得所选区域的RGB图,然后对RGB图灰度化和二值化,由于使用固定阈值效果不良好,因此这里采用了动态阈值,即
gray = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 47,20)
避免了光照、阴影等因素造成的灰度图颜色不均匀的问题,识别效果良好。识别代码如下:
tessdata_dir_config = '--psm 7 --oem 1'
result = pytesseract.image_to_string(image, lang='eng', config=tessdata_dir_config)