华为健康APP全天24小时手环心率数据截图OCR转文字100%识别,python+cv2+pytesseract+Tesseract+jTessBoxEditor

华为手环会监测全天心率,大约一般是10分钟一个数据,最短是1分钟1个数据。如果屏幕亮着(最长可设成常亮20分钟),则会一直记录(1分钟1个数据)。

手环心率数据会自动同步到手机的华为健康APP,再自动同步到华为服务器。需要数据导出的话,需要华为网站申请,而且要1周后,非常麻烦,也无法及时得到数据。

华为健康APP,心率那边可以看每天的心率数据,想及时得到数据,最好的办法就是截图+OCR了。

比如截出的图片中的数据是:

图标  70 次/分钟   19:00 >

图标  101 次/分钟  20:00 >

看起来很简单,只需要把图片中的数字识别出来就行了。但千辛万苦,入了N多坑,才终于OCR成功,100%识别。

总结一下:

手机截出的长图,水平是540pix,最多截到2万多PIX垂直长度就不截了,需要分多个图来截。

手机截出的短图,可能水平PIX数会不一样,大于540,程序需要resize成一样的540。因为OCR训练字库是按540PIX的图来的,如果PIX不一样,OCR错误率就很高。

用百度云的“文字识别API”可以,必须采用“精确识别”,效果很好,错误率低,基本100%出来!  其它的如“数字识别”等不行,效果差!  但“精确识别”有长度限制,限制8192pix,长图需要分割,有点麻烦。 百度API有一些免费次数,基本够用。

其它的OCR软件就更不能看了,一是一般长度限制在1万pix,二是错误率高,三是漏内容,有很多内容被忽略了,或“未找到文字”,好悲伤。

因为有tesseract开源OCR软件和python支持,于是自己尝试进行OCR。

tesseract不同语言包,就是用各自的识别字库,比如默认就是英语,用英语的字库进行强行匹配出字符,指定中文就是用中文的字库进行强行匹配出字符。

psm=3,是全页进行分析切割,邻近的文字会当成一个分割大块,因为各个时间邻近,所以所有的时间就都在一起了,心率、时间就分开了,不在同一行,格式乱了。

psm=6,是类似按表格那样处理,心率、时间就能在同一行,需要用这种方式。

发现OCR真的太难了,图片分辨率不能太大也不能太小,不然都错误率高,只有适中的分辨率才能较好地识别,所以不能随便resize,但要找到合适的分辨率size太难了。如果采用训练字库,则训练的字符和待识别的字符要一样pix大,不然错误率高,所以也不能随便resize。

tesseract是先识别出图块,再把各个图块OCR出来一个字符。一个图块一定会OCR出一个字符来,无法忽略掉这个图块,即使图块和字符完全不符,它也会强行去匹配字符而不忽略,所以会OCR出来乱七八糟的字符!

识别过程有N种可能性,同一个图片中的一个汉字在可能会被识别成完整汉字、或者偏旁分开、或者和别的字符一起,所以有无数可能性组合,造成了OCR出来的字符乱七八糟。这也和你采用什么识别语言字库有关系。

试了N多方案,最后发现还是必须要把图片中所有的干扰字(中文、英文、符号等)全部去掉,只留下数字,并且采用训练字库,才可能100%识别,不然干扰实在太多了,一直有错误率。

即使图片中只有数字,采用tesseract自带的语言包字库,也有很多识别错的,所以必须要用jTessBoxEditor自己训练语言包字库,才能100%。 不难,就是把图片里的各个数字0~9截出来进行训练就好了。

所以OCR真的是一个高难度技术活!

然后,又碰到华为健康APP会更新,心率数据显示格式会变了!每行数据的高度没有变,数字的宽高没有变。但水平定位位置变了。程序得调整,还好训练的字库还能用。

当前PYTHON程序如下:

import cv2

import pytesseract

image = cv2.imread("1.jpg",cv2.IMREAD_GRAYSCALE)

if image is not None:                 #try捕捉不了cv2.imread错误,要用None来判断

    height, width = image.shape

   

    if width != 540 :

        image = cv2.resize(image, ( 540, int(height/width*540)  ) ,interpolation=cv2.INTER_LANCZOS4)  

        height, width = image.shape

   

    cv2.rectangle(image, (0, 0), (width-1, 155), (255, 255, 255), -1)      #清除上方

    cv2.rectangle(image, (0, 0), (79, height-1), (255, 255, 255), -1)      #清除左方

    cv2.rectangle(image, (445, 0), (450, height-1), (255, 255, 255), -1)     #清除冒号

    cv2.rectangle(image, (480, 0), (width-1, height-1), (255, 255, 255), -1)   #清除右方

   

   

    #查找心率超过100的突出来的“钟”  #消除这行中文文字

    for yy in range(12, height):

        tempsum=0

        for xx in range(216, 222):   #7个像素,平均小于80,就找到了

            tempsum=tempsum+image[ yy , xx ]

        if tempsum/7 < 80 :

            #print(xx,yy)

            cv2.rectangle(image, (144, yy-12), (400, yy+23), (255, 255, 255), -1)     #清除本行中文文字   yy+23会超过总高,没有关系不会出错,不然有的文字比较靠底部,会清不到

           

    #再查找小率小于100的“钟”    #消除这行中文文字

    for yy in range(12, height):

        tempsum=0

        for xx in range(202, 209):   #7个像素,平均小于80,就找到了

            tempsum=tempsum+image[ yy , xx ]

        if tempsum/7 < 80 :

            #print(xx,yy)

            cv2.rectangle(image, (130, yy-12), (400, yy+23), (255, 255, 255), -1)     #清除本行中文文字

   

   

    cv2.imwrite("output1.png",image)

   

    text = pytesseract.image_to_string(image, config='-l mynum --psm 6 --oem 3')

    #print(text)

   

    with open('output.txt', 'w') as file:

        file.write(text)

    print('1.jpg   output.txt ok\n')

   

#################################################################################################################

image = cv2.imread("2.jpg",cv2.IMREAD_GRAYSCALE)

if image is not None:                 #try捕捉不了cv2.imread错误,要用None来判断

    height, width = image.shape

   

    if width != 540 :

        image = cv2.resize(image, ( 540, int(height/width*540)  ) ,interpolation=cv2.INTER_LANCZOS4)  

        height, width = image.shape

   

    cv2.rectangle(image, (0, 0), (width-1, 155), (255, 255, 255), -1)      #清除上方

    cv2.rectangle(image, (0, 0), (79, height-1), (255, 255, 255), -1)      #清除左方

    cv2.rectangle(image, (445, 0), (450, height-1), (255, 255, 255), -1)     #清除冒号

    cv2.rectangle(image, (480, 0), (width-1, height-1), (255, 255, 255), -1)   #清除右方

   

   

    #查找心率超过100的突出来的“钟”  #消除这行中文文字

    for yy in range(12, height):

        tempsum=0

        for xx in range(216, 222):   #7个像素,平均小于80,就找到了

            tempsum=tempsum+image[ yy , xx ]

        if tempsum/7 < 80 :

            #print(xx,yy)

            cv2.rectangle(image, (144, yy-12), (400, yy+23), (255, 255, 255), -1)     #清除本行中文文字   yy+23会超过总高,没有关系不会出错,不然有的文字比较靠底部,会清不到

           

    #再查找小率小于100的“钟”    #消除这行中文文字

    for yy in range(12, height):

        tempsum=0

        for xx in range(202, 209):   #7个像素,平均小于80,就找到了

            tempsum=tempsum+image[ yy , xx ]

        if tempsum/7 < 80 :

            #print(xx,yy)

            cv2.rectangle(image, (130, yy-12), (400, yy+23), (255, 255, 255), -1)     #清除本行中文文字

   

   

    cv2.imwrite("output2.png",image)

   

    text = pytesseract.image_to_string(image, config='-l mynum --psm 6 --oem 3')

    #print(text)

   

    with open('output.txt', 'a') as file:

        file.write(text)

    print('2.jpg   output.txt ok\n')

#################################################################################################################

image = cv2.imread("3.jpg",cv2.IMREAD_GRAYSCALE)

if image is not None:                 #try捕捉不了cv2.imread错误,要用None来判断

    height, width = image.shape

   

    if width != 540 :

        image = cv2.resize(image, ( 540, int(height/width*540)  ) ,interpolation=cv2.INTER_LANCZOS4)  

        height, width = image.shape

   

    cv2.rectangle(image, (0, 0), (width-1, 155), (255, 255, 255), -1)      #清除上方

    cv2.rectangle(image, (0, 0), (79, height-1), (255, 255, 255), -1)      #清除左方

    cv2.rectangle(image, (445, 0), (450, height-1), (255, 255, 255), -1)     #清除冒号

    cv2.rectangle(image, (480, 0), (width-1, height-1), (255, 255, 255), -1)   #清除右方

   

   

    #查找心率超过100的突出来的“钟”  #消除这行中文文字

    for yy in range(12, height):

        tempsum=0

        for xx in range(216, 222):   #7个像素,平均小于80,就找到了

            tempsum=tempsum+image[ yy , xx ]

        if tempsum/7 < 80 :

            #print(xx,yy)

            cv2.rectangle(image, (144, yy-12), (400, yy+23), (255, 255, 255), -1)     #清除本行中文文字   yy+23会超过总高,没有关系不会出错,不然有的文字比较靠底部,会清不到

           

    #再查找小率小于100的“钟”    #消除这行中文文字

    for yy in range(12, height):

        tempsum=0

        for xx in range(202, 209):   #7个像素,平均小于80,就找到了

            tempsum=tempsum+image[ yy , xx ]

        if tempsum/7 < 80 :

            #print(xx,yy)

            cv2.rectangle(image, (130, yy-12), (400, yy+23), (255, 255, 255), -1)     #清除本行中文文字

   

   

    cv2.imwrite("output3.png",image)

   

    text = pytesseract.image_to_string(image, config='-l mynum --psm 6 --oem 3')

    #print(text)

   

    with open('output.txt', 'a') as file:

        file.write(text)

    print('3.jpg   output.txt ok\n')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值