整体思路:利用边缘检测+轮廓检测+透射变换+百度文字识别API实现。
总体分为3步:
1.运用边缘检测与轮廓检测检测到文本最外侧的边缘。
2.根据边缘的四点确定文档的区域,再利用透射变换等操作将文档视角转换。
3.调用百度文字识别API进行文本识别。
原始图像:
透射变换等操作之后的图像:
文本识别的结果(部分):
具体步骤:
Step1:运用边缘检测与轮廓检测检测到文本最外侧的边缘
通过Canny边缘检测将测出轮廓,然后再进行轮廓检测。轮廓检测时会出现多个闭合图形,可以通过比较闭合图形的面积的大小确定,拥有面积最大值的闭合图形即为文档边缘。
#读取图像
img=cv.imread('receipt.jpg',cv.IMREAD_COLOR)
org=img.copy()
ratio=0.4 #由于原图过大,所以采用缩放一定比例,方便观察结果
img=cv.resize(img, dsize=None,fx=ratio,fy=ratio)
#边缘检测+轮廓检测检测到最外围的矩形
gray=cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edged=cv.Canny(gray,75, 200)
cnts,hierarchy=cv.findContours(edged.copy(), cv.RETR_LIST,
cv.CHAIN_APPROX_SIMPLE)
cnt = sorted(cnts, key = cv.contourArea, reverse = True)[0]
peri = cv.arcLength(cnt, True) #计算图形的周长
approx=cv.approxPolyDP(cnt, 0.1*peri, True) #轮廓检测中的近似操作
if(len(list(approx))==4): #判断是否为4点(确定一个矩形)
screenCnt=approx
else:
print("未找到轮廓")
exit()
效果:
Step2:根据边缘的四点确定文档的区域,再利用透射变换等操作将文档视角转换。
1.确定文档边缘四点。
作者采用如下方法确定:
当x+y为最小/大值时,分别对应A/C点。(sum求和函数)
当y-x为最小/大值时,分别对应B/D点。(diff做差函数)
def order_points(pts):
# 一共4个坐标点
rect = np.zeros((4, 2), dtype = "float32")
# 按顺序找到对应坐标0123分别是 左上,右上,右下,左下
# 计算左上,右下
s = pts.sum(axis = 1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# 计算右上和左下
diff = np.diff(pts, n=1,axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
2.透射变换
以四个边长的长/宽的最大值分别作为透射变换后长/宽,然后做透射变换。
def four_point_transform(image, pts): #image为原始图像,pts为4*2的坐标矩阵
rect=order_points(pts)
len=np.zeros((4,1))
for (i,p) in enumerate(pts) :
if i!=3:
x=pts[i:(i+2),0]
y=pts[i:(i+2),1]
elif i==3:
x=[pts[3,0],pts[0,0]]
y=[pts[3,0],pts[0,1]]
len[i]=np.sqrt(((x[0]-x[1])**2+(y[0]-y[1])**2))
maxWidth=int(max(len[0],len[2]))
maxHight=int(max(len[1],len[3]))
dst=np.array([
[0,0],
[maxWidth-1,0],
[maxWidth-1,maxHight-1],
[0,maxHight-1]
],dtype = "float32")
M=cv.getPerspectiveTransform(rect, dst)
warped=cv.warpPerspective(image, M, (maxWidth,maxHight))
return warped
实际调用:
warped=four_point_transform(org, screenCnt.reshape(4,2)/ratio)
再进行旋转变换与阈值处理即可获得纠正后的图像:
#旋转90°(针对特定需要旋转的对象)
rows,cols = dst.shape[:2]
M = cv.getRotationMatrix2D((cols/2,rows/2),90,1)
dst = cv.warpAffine(dst,M,(cols,rows))
#阈值处理
gray=cv.cvtColor(warped, cv.COLOR_BGR2GRAY)
ret,dst=cv.threshold(gray, 127, 255, cv.THRESH_BINARY)
Step3:调用百度文字识别API进行文本识别。
如何获取OCR模块参考:https://blog.youkuaiyun.com/jyd0124/article/details/105868562
然后调用API即可,详细深入的OCR处理不在这里展开。
#调用百度API实现OCR功能
AppID = '*******'
API_Key = '********'
Secret_Key = '**************'
client = AipOcr(AppID, API_Key, Secret_Key)
image = get_file_content('图片的地址')
options = {}
options["language_type"] = "ENG"
options["detect_direction"] = "true"
options["detect_language"] = "true"
options["probability"] = "true"
res=client.basicGeneral(image,options)
print(res['words_result'])
for item in res['words_result']:
print(item['words'])
OCR结果: