wxPython:调用OCR模块实现图片识别

(读者电脑中应安装有Canopy)

先下载tesseract-ocr模块:OCR模块

将其安装在Canopy那个盘。

安装了之后,下载代码:代码

将代码解压至......\Canopy\User\Lib\site-packages

然后在Canopy内运行代码文件中的pytesser.py即可。

PS:

  1. 要将代码中11,237,301,311行的路径修改成读者本机路径。
  2. 代码中抓取的图片地址为华东师范大学公共数据库

# -*- coding: utf-8 -*-

import os
import wx
import util
import errors
import urllib2
import subprocess
from PIL import Image

os.chdir('D:\Canopy\User\Lib\site-packages\pytesser_v0.0.1')

tesseract_exe_name = 'tesseract'  # Name of executable to be called at command line
scratch_image_name = "temp.bmp"   # This file must be .bmp or other Tesseract-compatible format
scratch_text_name_root = "temp"   # Leave out the .txt extension
cleanup_scratch_flag = True       # Temporary files cleaned up after OCR operation

def call_tesseract(input_filename, output_filename):
	"""Calls external tesseract.exe on input file (restrictions on types),
	outputting output_filename+'txt'"""
	args = [tesseract_exe_name, input_filename, output_filename]
	proc = subprocess.Popen(args)
	retcode = proc.wait()
	if retcode!=0:
		errors.check_for_errors()

def image_to_string(im, cleanup = cleanup_scratch_flag):
	"""Converts im to file, applies tesseract, and fetches resulting text.
	If cleanup=True, delete scratch files after operation."""
	try:
		util.image_to_scratch(im, scratch_image_name)
		call_tesseract(scratch_image_name, scratch_text_name_root)
		text = util.retrieve_text(scratch_text_name_root)
	finally:
		if cleanup:
			util.perform_cleanup(scratch_image_name, scratch_text_name_root)
	return text

def image_file_to_string(filename, cleanup = cleanup_scratch_flag, graceful_errors=True):
	"""Applies tesseract to filename; or, if image is incompatible and graceful_errors=True,
	converts to compatible format and then applies tesseract.  Fetches resulting text.
	If cleanup=True, delete scratch files after operation."""
	try:
		try:
			call_tesseract(filename, scratch_text_name_root)
			text = util.retrieve_text(scratch_text_name_root)
		except errors.Tesser_General_Exception:
			if graceful_errors:
				im = Image.open(filename)
				text = image_to_string(im, cleanup)
			else:
				raise
	finally:
		if cleanup:
			util.perform_cleanup(scratch_image_name, scratch_text_name_root)
	return text

class MyModalDialog(wx.Dialog):
    
    def __init__(self, parent, title):
        
        super(MyModalDialog, self).__init__(parent, title = title, pos = (500, 300), size = (950, 580))  # 调用父类构造器(必须)
        
        panel = wx.Panel(self)
        
        wx.StaticText(panel, -1, u"Folder: ", pos=(5, 5), size=(60, 30)) 
        self.imagePath = wx.TextCtrl(panel, pos=(65, 5), size=(400, 30)) 
        self.imagePath.SetLabel(os.getcwd())    
        
        wx.StaticText(panel, -1, u"Files of type: ", pos=(5, 40), size=(100, 30))     
        sampleList = ['tif files(*.tif)|*.tif', 'png files(*.png)|*.png', 'jpg files(*.jpg)|*.jpg']
        self.combobox = wx.ComboBox(panel, -1, "tif files(*.tif)|*.tif", (105, 40), wx.DefaultSize, sampleList, wx.CB_DROPDOWN)
        self.Bind(wx.EVT_TEXT, self.comboboxChange, self.combobox)
        
        wx.Button(panel, 300, label = u"up one level", pos = (500, 5), size = (100, 30))
        wx.Button(panel, 301, label = u"Browse for a folder", pos=(650, 5), size=(150, 30))
        wx.Button(panel, 302, label = u"Open", pos = (30, 500), size = (100, 30))
        wx.Button(panel, 303, label = u"Cancel", pos = (170, 500), size = (100, 30))
        self.Bind(wx.EVT_BUTTON, self.Back, id = 300)
        self.Bind(wx.EVT_BUTTON, self.FileDialog, id = 301)
        self.Bind(wx.EVT_BUTTON, self.Ok, id = 302)
        self.Bind(wx.EVT_BUTTON, self.Cancel, id = 303)
        
        self.bitmap = wx.StaticBitmap(panel, -1, pos = (350, 45)) 
        
        self.list = wx.ListBox(panel, -1, (5, 100), (300, 300), '', wx.LB_SINGLE)  # 文件夹listbox
        self.list.Bind(wx.EVT_LISTBOX_DCLICK, self.OnDClick)
        
        curdir = os.getcwd()  # 设置初始路径
        self.LoadDir(curdir)  # 加载初始文件夹
        
        self.Bind(wx.EVT_CLOSE, self.OnClose)  # 绑定事件
    
    def OnClose(self, event):
        
        self.Destroy()
        
    def comboboxChange(self, event):
        
        self.LoadDir(os.getcwd())
        
    def OnDClick(self, event):  # listbox双击事件
        
        if self.list.GetSelection() == 0:  # 判断是否选择了返回上一层文件夹
            path = os.getcwd()
            pathinfo = os.path.split(path)
            dir = pathinfo[0]
        else:  # 获得需要进入的下一层文件夹
            dir = self.list.GetStringSelection()
        
        if os.path.isdir(dir):  # 进入文件夹
            self.LoadDir(dir)
        else:  
            path = os.getcwd()
            self.imagePath.SetLabel(path + os.path.sep + dir)
            
            # 这里之所以把SetSize放在SetBitmap的后面,是因为这样可以让图片显示在中心
            tempBitmap = wx.Image(dir, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
            self.bitmap.SetBitmap(tempBitmap) 
            self.bitmap.SetSize((580, 450))
            
    
    def LoadDir(self, dir):  # 加载文件夹
        
        self.list.Clear()  # 清空
        self.list.Append('...')  # 添加返回上一层文件夹标志
        
        # 从combobox中获取选中的后缀,保存在suffix中
        value = self.combobox.GetValue()
        length = len(value)
        temp = []
        temp.append(value[length - 4])
        temp.append(value[length - 3])
        temp.append(value[length - 2])
        temp.append(value[length - 1])
        suffix = ''.join(temp)  # 将list类型转化成字符串类型
        
        for _dir in os.listdir(dir):
            if os.path.splitext(_dir)[-1] == suffix or os.path.isdir(dir + os.path.sep + _dir):
                self.list.Append(_dir)
               
        os.chdir(dir)  # 设置工作路径
        self.imagePath.SetLabel(os.getcwd())
        
    def FileDialog(self, evt):  # 打开文件对话框
        
        wildcard = self.combobox.GetValue()
        dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", wildcard, wx.OPEN)
        if dialog.ShowModal() == wx.ID_OK:
            self.path = dialog.GetPath()
        dialog.Destroy()
        
        self.imagePath.SetLabel(self.path)
        
        tempBitmap = wx.Image(self.path, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        self.bitmap.SetBitmap(tempBitmap) 
        self.bitmap.SetSize((580, 450))
        
    def Back(self, evt):
        
        pathInformation = os.path.split(self.imagePath.GetLabel())
        self.imagePath.SetLabel(pathInformation[0])
        os.chdir(pathInformation[0])
        self.LoadDir(pathInformation[0])
         
    def Ok(self, event):
        
        path = self.imagePath.GetLabel()
            
        self.GetParent().imagePath.SetLabel(path) 
        
        tempBitmap = wx.Image(path, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        self.GetParent().bitmap.SetSize((tempBitmap.GetWidth(), tempBitmap.GetHeight()))
        self.GetParent().bitmap.SetBitmap(tempBitmap) 
    
        self.Destroy()
        
    def Cancel(self, event):
        
        self.Destroy()
        
class MyFrame(wx.Frame):
    
    def __init__(self):
        
        wx.Frame.__init__(self, None, -1, u"第八次上机练习(WX)", size=(700, 700))
        
        self.menuBar = wx.MenuBar()
        
        self.file = wx.Menu()
        self.file.Append(201, u"打开")
        self.file.Append(202, u"下载验证码")
        self.file.Append(203, u"保存")
        self.file.Enable(203, False)
        self.file.Append(204, u"退出")
        self.Bind(wx.EVT_MENU_RANGE, self.FILE, id = 201, id2 = 204)
        self.menuBar.Append(self.file, u"&文件")
        
        self.ocr = wx.Menu()
        self.ocr.Append(205, u"识别英文")
        self.ocr.Append(206, u"识别中文")
        self.Bind(wx.EVT_MENU_RANGE, self.OCR, id = 205, id2 = 206)
        self.menuBar.Append(self.ocr, u"&OCR")	
        
        self.image = wx.Menu()
        self.image.Append(207, u"图像增强")
        self.Bind(wx.EVT_MENU, self.IMAGE, id = 207)
        self.menuBar.Append(self.image, u"&图像")
        
        self.about = wx.Menu()
        self.about.Append(208, u"程序信息")
        self.Bind(wx.EVT_MENU, self.ABOUT, id = 208)
        self.menuBar.Append(self.about, u"&关于")	
        		
        self.SetMenuBar(self.menuBar)
        
        #self.panel = wx.Panel(self, -1)
        self.text = wx.StaticText(self, -1, u" 图像文件:", pos=(0, 0), size=(70, 20)) 
        self.imagePath = wx.StaticText(self, -1, u"None", pos=(70, 0), size=(100, 20)) 
        self.identifyText = ""  # 保存图像识别的结果
        self.bitmap = wx.StaticBitmap(self, -1, pos = (5, 30))   
        
    def FILE(self, evt):
            
        Id = evt.GetId()
        
        if Id == 201:  # 通过模式对话框选择图片                  
            MyModalDialog(self, u"Image Browser").ShowModal() 
                 
        elif Id == 202:  # 下载验证码
            url = 'https://portal1.ecnu.edu.cn/cas/Captcha.jpg'  # 验证码生成页面的地址
            imageData = urllib2.urlopen(url).read()              # 读取验证码图片
            f = open('identifyingCode.png','wb')                 # 打开一个identifyingCode.png文件,没有的话自动生成
            f.write(imageData)                                   # 写入图片内容
            f.close()                                            # 关闭文件
            
            self.imagePath.SetLabel('D:\Canopy\User\Lib\site-packages\pytesser_v0.0.1\identifyingCode.png')
            
            # 这里之所以把SetSize放在SetBitmap的前面,是因为这样可以让图片显示在左上角
            tempBitmap = wx.Image('identifyingCode.png', wx.BITMAP_TYPE_ANY).ConvertToBitmap()
            self.bitmap.SetSize((tempBitmap.GetWidth(), tempBitmap.GetHeight()))
            self.bitmap.SetBitmap(tempBitmap)
                
        elif Id == 203:  # 将识别结果保存成txt文件
            wildcard = "Txt files (*.txt)|*.txt"
            dialog = wx.FileDialog(None, "Save the file", "", "", wildcard, wx.SAVE)
            if dialog.ShowModal() == wx.ID_OK:
                self.path = dialog.GetPath()
                file = open(self.path, 'wb')
                file.write(self.identifyText)
                file.close()  
            dialog.Destroy()
        
        else:  # 关闭窗口
            self.Close()  
         
    def OCR(self, evt):  # 图像识别
        
        Id = evt.GetId()  
        
        if Id == 205:
            path = self.imagePath.GetLabel()
            image = Image.open(path)
	    self.identifyText = image_to_string(image)
	    wx.MessageBox(self.identifyText, u"TEXT")
	    self.file.Enable(203, True)
            
    def IMAGE(self, evt):  # 图像增强,将图片变为黑白
        
        path = self.imagePath.GetLabel()
        im = Image.open(path) 
        (w, h) = im.size  
        R = 0  
        G = 0  
        B = 0  
  
        for x in xrange(w):  
            for y in xrange(h):  
                pos = (x, y)  
                rgb = im.getpixel(pos)  
                (r, g, b) = rgb  
                R = R + r  
                G = G + g  
                B = B + b  
  
        rate1 = R * 1000 / (R + G + B)  
        rate2 = G * 1000 / (R + G + B)  
        rate3 = B * 1000 / (R + G + B)   
      
        for x in xrange(w):  
            for y in xrange(h):  
                pos = (x, y)  
                rgb = im.getpixel(pos)  
                (r, g, b) = rgb  
                n = r * rate1 / 1000 + g * rate2 / 1000 + b * rate3 / 1000  
                if n >= 60:  
                    im.putpixel(pos, (255, 255, 255))  
                else:  
                    im.putpixel( pos, (0, 0, 0))  
        
        im.save('D:\Canopy\User\Lib\site-packages\pytesser_v0.0.1\_temp\enhance.bmp')  # 将增强后的图片副本保存在固定位置
        
        wildcard = "bmp files (*.bmp)|*.bmp"
        dialog = wx.FileDialog(None, "Save the file", "", "", wildcard, wx.SAVE)
        if dialog.ShowModal() == wx.ID_OK:
            self.path = dialog.GetPath()  
        dialog.Destroy()
        
        im.save(self.path)
        
        tempBitmap = wx.Image('D:\Canopy\User\Lib\site-packages\pytesser_v0.0.1\_temp\enhance.bmp', wx.BITMAP_TYPE_ANY).ConvertToBitmap()  # 读取增强图片副本
        self.bitmap.SetSize((tempBitmap.GetWidth(), tempBitmap.GetHeight()))
        self.bitmap.SetBitmap(tempBitmap)
    
    def ABOUT(self, evt):  # 程序信息
        
        wx.MessageBox(u"第八次上机练习(WX)\n图片转换成文本\n\n学号: 10152130110\n姓名: 李正甲",
           u"Lab8", wx.OK | wx.ICON_INFORMATION, self)
           

if __name__=='__main__':
	app = wx.PySimpleApp()
        frame = MyFrame()
        frame.Show(True)
        app.MainLoop()
        
        



	





你可能感兴趣的:(多平台应用开发)