# -*- coding:utf-8 -*- import sys, os, time reload(sys) sys.setdefaultencoding("utf-8") from TST.NetOCR import * from ssat_sdk.picture import image_util from ssat_sdk.utils import LoggingUtil from sat_environment import * from utils import string_util from picture.ocr_baidu import OCRBaidu from picture.ocr_tesseract import OCRTes from picture import ocr_tesseract import json import cv2 as cv import numpy as np EXP_Info = "ERR" #所有语言定义 OCR_LanDIC = ["chineseprc+english", "chinesetaiwan+english", "spanish", "chineseprc","chinesetaiwan","russian","french" ,"english","vietnamese","hebrew","thai","arabic","portuguese","german","italian","japanese","korean"] ''' OCR Type定义: abbyy:0~999 tesseract:1000~9999 baidu:10000~10100 ''' #泰彼OCR定义 Abbyy_LanDIC = {"chineseprc+english": "ChinesePRC+English", "chinesetaiwan+english": "ChineseTaiwan+English", "spanish": "Spanish", "chineseprc": "ChinesePRC", "chinesetaiwan": "ChineseTaiwan", "russian": "Russian", "french": "French", "english": "English", "vietnamese": "Vietnamese", "hebrew": "Hebrew", "thai": "Thai" } ABBYY_BASIC = 0 ABBYY_MAX = 999 ABBYY_CONTRAST_ENABLE = ABBYY_BASIC ABBYY_CONTRAST_DISABLE = ABBYY_BASIC+1 ABBYY_NORMAL = ABBYY_BASIC+2 ABBYY_CONVERSION_ENGINE_ENABLE = ABBYY_BASIC+3 ABBYY_INVERT_IMAGE_ENABLE = ABBYY_BASIC+4 ABBYY_CONVERSION_AND_CONTRAST_ENABLE = ABBYY_BASIC+5 ABBYY_ENGLISH_RECOMMENDATION_MODE = 253 Abbyy_TypeList = [ABBYY_CONTRAST_ENABLE,ABBYY_CONTRAST_DISABLE,ABBYY_NORMAL,ABBYY_CONVERSION_ENGINE_ENABLE ,ABBYY_INVERT_IMAGE_ENABLE,ABBYY_CONVERSION_AND_CONTRAST_ENABLE,ABBYY_ENGLISH_RECOMMENDATION_MODE] #Tesseract OCR定义。没有Type Tes_LanDIC = ocr_tesseract.Tes_LanDIC Tes_BASIC = 1000 Tes_MAX = 9999 Tes_TypeList = [Tes_BASIC] #百度 OCR定义。 Baidu_LanDIC = {"chineseprc+english": "CHN_ENG", "spanish": "SPA","russian": "RUS", "french": "FRE", "english": "ENG", "portuguese": "POR", "german": "GER", "italian": "ITA", "japanese": "JAP", "korean": "KOR"} Baidu_BASIC = 10000 Baidu_MAX = 10100 Baidu_General = Baidu_BASIC Baidu_Accurate = Baidu_BASIC + 1 Baidu_TypeList=[Baidu_General,Baidu_Accurate] OCR_TMP_DIR = getOCRTmpDir() OCR_ERR_DIR = getOCRErrDir() if not os.path.exists(OCR_TMP_DIR): os.mkdir(OCR_TMP_DIR) if not os.path.exists(OCR_ERR_DIR): os.mkdir(OCR_ERR_DIR) class OCRConvert(): OCR_PRODUCT_BAIDU = "baidu" OCR_PRODUCT_ABBYY = "abbyy" OCR_PRODUCT_TES = "tesseract" def __init__(self): self.timeout = 3 self.ocrBaidu = OCRBaidu() self.ocrTes = OCRTes() def setTimeOut(self, seconds): self.timeout = seconds ''' 根据自然语言描述,和OCR Type,返回OCR识别语言的字符串定义 :param language: chineseprc+english/chinesetaiwan+english/spanish/chineseprc/chinesetaiwan/russian/french/english/vietnamese/hebrew /portuguese/german/italian/japanese/korean :param type: OCR识别类型编号 :return OCR语言类别定义的字符串.如果在字典库找不到,直接返回传入的language。 ''' def getOCRLaParam(self, language, type): if type = ABBYY_BASIC: if Abbyy_LanDIC.has_key(language.lower()): return Abbyy_LanDIC[language.lower()] else: return language elif type = Tes_BASIC: if Tes_LanDIC.has_key(language.lower()): return Tes_LanDIC[language.lower()] else: return language elif type < Baidu_MAX and type>=Baidu_BASIC: if Baidu_LanDIC.has_key(language.lower()): return Baidu_LanDIC[language.lower()] else: return language else: return language """ 根据传入的语言类型(无论自然语言类型,或者ocr语言类型),转换成目标自然语言类型 """ def getHumanLan(self, language, type): if type < ABBYY_MAX and type >= ABBYY_BASIC: if Abbyy_LanDIC.has_key(language): return language for humanLan in Abbyy_LanDIC: # print "getHumanLan:", humanLan if string_util.strcmp(Abbyy_LanDIC[humanLan], language): return humanLan return "" elif type < Tes_MAX and type >= Tes_BASIC: if Tes_LanDIC.has_key(language): return language for humanLan in Tes_LanDIC: # print "getHumanLan:", humanLan if string_util.strcmp(Tes_LanDIC[humanLan], language): return humanLan return "" elif type < Baidu_MAX and type >= Baidu_BASIC: if Baidu_LanDIC.has_key(language): return language for humanLan in Baidu_LanDIC: # print "getHumanLan:", humanLan if string_util.strcmp(Baidu_LanDIC[humanLan], language): return humanLan return "" else: return "" ''' 根据传入的OCR 类型,返回厂家名字 :param type:OCR识别类型编号 :return OCR厂家名称 ''' def getOCRProductByType(self, type): if type < ABBYY_MAX and type >= ABBYY_BASIC: return self.OCR_PRODUCT_ABBYY elif type < Tes_MAX and type >= Tes_BASIC: return self.OCR_PRODUCT_TES elif type < Baidu_MAX and type >= Baidu_BASIC: return self.OCR_PRODUCT_BAIDU else: return "" def sendPicToServer(self, picPath, lan, type): try: ocr = NetOCR(getOCRIpAddr(), getOCRPort(), picPath, lan, type) # ocr.setTimeOut(self.timeout) return ocr except Exception, e: print "OCR", u"SCBC OCR连接失败,Err:" ,e return None ''' 在getStr函数基础上,添加了图片处理参数。处理图片后,再使用图片识别。 :param imgProcParams: 字典:{"Threshold":[127,250, 阈值类型], "contrast":[], "LaplaceSharp":[], "Noisy":[]} :param picPath: 图片路径 :param lan :OCR识别用的语言类别,不同OCR产品的定义不一样 :param type:OCR识别的类型编号 :return 识别后的字符串。同getStr函数 ''' def getStrWithImgProcess(self, picPath, imgProcParams, lan, type, reconTimes = 5): print "getStrWithImgProcess, param:", picPath, imgProcParams,lan,type,reconTimes destPicPath = os.path.join(OCR_TMP_DIR, "ocr_"+str(time.time())+".png") img = self.handleImage(picPath, imgProcParams) cv.imwrite(destPicPath, img) return self.getStr(destPicPath, lan, type) ''' 根据图片处理参数,处理图片,返回image对象 :param imgProcParams: 字典:{"Threshold":[127,250, 阈值类型], "contrast":[], "LaplaceSharp":[], "Noisy":[]} :param picPath: 图片路径 :return 返回图片image对象 ''' def handleImage(self, picPath, imgProcParams): print u"handleImage,imgProcParams:", imgProcParams srcImg = cv.imread(picPath) destPicPath = picPath img = srcImg if imgProcParams.has_key("Threshold"): img = image_util.saveThresholdPicImg(srcImg, \ imgProcParams["Threshold"][0], imgProcParams["Threshold"][1], imgProcParams["Threshold"][2]) return img ''' 根据传入的图片路径,获取图片的字符串。 :param picPath.图片的绝对路径 :param lan. OCR识别的文字语言类别。 type<10000: ChinesePRC+English ChineseTaiwan+English Spanish ChinesePRC ChineseTaiwan Russian French English Vietnamese Hebrew Thai :param type. OCR识别文字时的识别模型编号。 :param reconTimes. OCR识别文字异常时,重新尝试识别的次数,默认为5次,最高为10次。 :return str. 返回识别的字符串。未识别到,返回"",如果type未10000,10001表示采用百度OCR,返回字符串数组 如果属于字符识别异常:返回字符串"ERR" ''' def getStr(self, picPath, lan, type, reconTimes = 5): print "getStr, param:", picPath, lan, type, reconTimes lan = self.getOCRLaParam(lan, type) if type < ABBYY_MAX and type >= ABBYY_BASIC: ocr = self.sendPicToServer(picPath, lan, type) if (ocr == None): return "" try: LoggingUtil.printLog("OCR", u"泰彼 OCR") string = ocr.getStr() # print string return string_util.toUTF8Str(string) except Exception, e: print u"OCR", u"获取文字失败.error:" ,e return EXP_Info finally: ocr.close() elif type >=Tes_BASIC and type < Tes_MAX: return self.ocrTes.getStr(picPath, lan, type) else: # 超出范围的重连次数,都默认为10次; if reconTimes > 10 or reconTimes < 0: reconTimes = 10 # by zippo 把百度的返回数组转换成字符串,统一返回值 allStr = self.ocr_BaiduGS(picPath, type - 10000, lan) while allStr is None or allStr == EXP_Info and reconTimes > 0: LoggingUtil.printLog("OCR", u'百度OCR重连') time.sleep(1) reconTimes -= 1 allStr = self.ocr_BaiduGS(picPath, type - 10000, lan) return EXP_Info if allStr is None else allStr # return self.ocr_Baidu(picPath, type-10000, lan) # 字符串比对 def cmpOcrStr(self, ocrStr, stdStr, erase = [], picPath=None): # print u"OCR_Convert:cmpOcrStr start param:", ocrStr, stdStr, erase, picPath if type(picPath) == type('') else 'path is imgObj' if type(ocrStr) == type(u''): ocrStr = str(ocrStr).encode('utf-8') else: try: ocrStr = str(ocrStr).encode('utf-8') except Exception: pass if type(stdStr) == type(u''): stdStr = str(stdStr).encode('utf-8') else: try: stdStr = str(stdStr).encode('utf-8') except Exception: pass # 去除空格; ocrStr = ocrStr.replace(' ', '').lower() stdStr = stdStr.replace(' ', '').lower() # 移除指定字符; for char in erase: ocrStr = ocrStr.replace(char, '').lower() stdStr = stdStr.replace(char, '').lower() #长度判断 if len(ocrStr) != len(stdStr): self.saveOCRErr(ocrStr, stdStr, picPath) return False # 遍历字符串 result = True # 忽略的相似字符; ignore = [{'i','l','1','t','I','T'},{'o','0','O'}] cnt = len(stdStr) for i in range(0, cnt): if stdStr[i] == ocrStr[i]: continue elif stdStr[i] in ignore[0] and ocrStr[i] in ignore[0]: continue elif stdStr[i] in ignore[1] and ocrStr[i] in ignore[1]: continue else: result = False break #endfor if result is False: self.saveOCRErr(ocrStr,stdStr, picPath) return result #end def saveOCRErr(self, ocrStr, stdStr, pic): if pic is None or pic == '': print u"Warn:Save OCR Error picture fail. is None or Empty" return destPicName = unicode(ocrStr + "_" + stdStr + ".png") destPic = os.path.join(OCR_ERR_DIR, destPicName) try: if type(pic) == type(""):# 如果是路径; shutil.copyfile(pic, destPic) else:# 如果是图像数组;numpy.ndarray cv.imwrite(destPic,pic) except Exception,e: print u"Warn:Save OCR Error picture fail.",e.message ''' 根据传入的目标字符串stdStr,如果指定的OCR type可以识别到文字,则返回True和OCR字符串。 如果指定的OCR type识别不到文字,遍历所有OCR type方式识别文字,返回最终遍历结果。 :param stdStr : 目标字符串 :param picPath: 图片路径 :param lan :OCR识别用的语言类别,不同OCR产品的定义不一样 :param type:OCR识别的类型编号 :param imgProcParams: 字典:{"Threshold":[127,250, 阈值类型], "contrast":[], "LaplaceSharp":[], "Noisy":[]} :param erase:erase 字符数组,文字比对时,需过滤掉的字符。 :return boolean,string: boolean标识是否成功(ture/false),string 是指定的OCR type识别到的文字。 ''' def findPicStr(self, stdStr, picPath, lan, type, imgProcParams={}, erase = []): #匹配自然语言类型 humanLan = self.getHumanLan(lan, type) ocrStr = self.getStrWithImgProcess(picPath, imgProcParams, lan, type, reconTimes = 1) ret = self.cmpOcrStr(ocrStr, stdStr,erase, picPath) return ret,ocrStr if ret is True: return True,ocrStr for typeA in Abbyy_TypeList: if type <> typeA: ocrLan = self.getOCRLaParam(humanLan, typeA) ocrStr = self.getStrWithImgProcess(picPath, imgProcParams, ocrLan, typeA, reconTimes=1) ret = self.cmpOcrStr(ocrStr, stdStr, erase, "") if ret is True: return True, ocrStr for typeB in Baidu_TypeList: if type <> typeB: ocrLan = self.getOCRLaParam(humanLan, typeB) ocrStr = self.getStrWithImgProcess(picPath, imgProcParams, ocrLan, typeB, reconTimes=1) ret = self.cmpOcrStr(ocrStr, stdStr, erase, "") if ret is True: return True, ocrStr return False, ocrStr # 指定ocr列表,遍历查找; def findPicStrEx(self, stdStr, picPath, list_ocr, imgProcParams={}, erase = []): result,ocrStr = False,'' for item in list_ocr: ocrStr = self.getStrWithImgProcess(picPath, imgProcParams, item["lan"], item["type"], reconTimes = 1) if stdStr.lower() in ocrStr.lower(): result = True break return result, ocrStr ''' 根据传入的图片路径,获取图片的字符串。 :param picPath.图片的绝对路径 :param lan. OCR识别的文字语言类别。 :param type. OCR识别文字时的识别模型编号。 :param area. OCR识别的图片区域。要求是图片刚好适配的矩形框区域。 :return str. 返回识别的字符串。未识别到,返回"". ''' def getPositionStr(self, picPath, lan, type, area): ocr = self.sendPicToServer(picPath, lan, type) if (ocr == None): return "" try: startX, startY, endX, endY = area string = ocr.getPositionStr(startX, startY, endX, endY) return string_util.toUTF8Str(string) except Exception, e: print "OCR", u"获取文字失败.error:",e return EXP_Info finally: ocr.close() ''' 根据传入的图片路径,获取图片的字符串。 :param picPath.图片的绝对路径 :param lan. OCR识别的文字语言类别。 :param type. OCR识别文字时的识别模型编号。 :param keyword. OCR需要寻找的文字。 :return str. 返回识别的字符串。未识别到,返回[-1,-1,-1,-1], ''' def getStrPosition(self, picPath, lan, type, keyword): ocr = self.sendPicToServer(picPath, lan, type) if (ocr == None): return [-1, -1, -1, -1] try: area = ocr.getStrPosition(keyword) return area except Exception, e: print "OCR", u"获取文字位置失败.error:",e return [-1, -1, -1, -1] finally: ocr.close() ''' 根据传入的图片路径,获取图片的字符串。 :param picPath.图片的绝对路径 :param lan. OCR识别的文字语言类别。 :param type. OCR识别文字时的识别模型编号。 :param area. OCR识别的图片区域。 :return str. 返回识别的字符串。未识别到,返回"", ''' def getAreaStr(self, picPath, lan, type, area): ocr = self.sendPicToServer(picPath, lan, type) if (ocr == None): return "" try: startX, startY, endX, endY = area string = ocr.getAreaStr(startX, startY, endX, endY) return string_util.toUTF8Str(string) except Exception, e: print "OCR", u'获取文字失败.error:',e return EXP_Info finally: ocr.close() def close(self): pass ''' :param language: 识别语言类型,默认为CHN_ENG。可选值包括: - CHN_ENG#中英文混合; - ENG#英文; - POR#葡萄牙语; - FRE#法语; - GER#德语; - ITA#意大利语; - SPA#西班牙语; - RUS#俄语; - JAP#日语; - KOR#韩语 :param type: 0 basicGeneral;1 basicAccurate 高精度通用文字; 选择高精度时,language参数失效。 :return : 正常返回字符串数组,如果异常,返回['ERR'] ''' def ocr_Baidu(self, pic_path, type, language="CHN_ENG"): if type == 0: ret = self.ocrBaidu.basicGeneral(pic_path, language) if ret is None: return [EXP_Info] return ret elif type == 1: ret = self.ocrBaidu.basicAccurate(pic_path, language) if ret is None: return [EXP_Info] return ret ''' :param language: 识别语言类型,默认为CHN_ENG。可选值包括: - CHN_ENG#中英文混合; - ENG#英文; - POR#葡萄牙语; - FRE#法语; - GER#德语; - ITA#意大利语; - SPA#西班牙语; - RUS#俄语; - JAP#日语; - KOR#韩语 :param type: 0 basicGeneral;1 basicAccurate 高精度通用文字; 选择高精度时,language参数失效。 ''' def ocr_BaiduGS(self, pic_path, type, language="CHN_ENG"): str1 = "" strList = self.ocr_Baidu(pic_path, type, language="CHN_ENG") for index in range(strList.__len__()): strT = strList[index] if index == 0: str1 = strT continue str1 += " "+strT return str1 if __name__ == "__main__": if 0: # DIR = r"D:\ocr_err\\" DIR = r"D:\temp-pic\gbk\\" # picPath = DIR + "mi_4.png" # picPath = DIR + "ocr_2.png" picPath = DIR + "546473243246047508.png" # DIR = u"D:/temp-pic/" # picPath = DIR + "20180604113525.png" # pic_path = r"D:\ocr_err\checkChannelList_crop.jpg" pic_path = r"D:\ocr_err\11.png" pic_path = r"D:\ocr_err\mi_1.png" pic_path = r"D:\ocr_err\mi\5.png" ocrCon = OCRConvert() # allStr = ocrCon.getStr(pic_path,"english", 1000, -1) allStr = ocrCon.getStr(pic_path,"chineseprc", 1000, -1) print "ocr:",allStr sys.exit(0) if 0: # s = u'林' # print s.encode('utf-8') # print s.encode('gbk') ocrCon = OCRConvert() ocrStr = u"1你好T0i" stdStr = u"i你好io1" result = ocrCon.cmpOcrStr(ocrStr, stdStr) print u'结果',result ocrStr = "1你好T0i" stdStr = "i你好io1" result = ocrCon.cmpOcrStr(ocrStr, stdStr) print u'结果',result ocrStr = "1你好T0i" stdStr = u"i你好io1" result = ocrCon.cmpOcrStr(ocrStr, stdStr) print u'结果',result # ocrStr = unicode("1你好T0i",'gbk') # stdStr = u"i你好io1" # print ocrStr,stdStr,type(ocrStr),type(stdStr) # result = ocrCon.cmpOcrStr(ocrStr, stdStr) # print u'结果',result if 1: ocr = OCRConvert() pic = r'D:\temp-pic\UI\NT72-1\home.png' # strAll = ocr.getStr(pic, "english", 253) # print "strall:",strAll position = ocr.getStrPosition(pic, "english", 253, "hdmi") print "position:",position