如何在计算机上辅助计算公式?目前的方案主要包括mathOCR、爱做业、做业帮等表明,以下:
node
它们的缺点主要包括:算法
不支持手写字符输入、
不支持复杂题型、
不支持题库外的式子等等,
对于复杂的公式难以识别,对于简单的公式则应用场景很少。express所以咱们但愿解决上述痛点,加强产品功能。
此类产品主要针对有辅助计算需求的学者和论文写做者,但还有一个基本的要求是近年来不断升级的验证码识别,以算术形式出现的验证码每每由被修改过的字符以异常的形式排列,所以不要求识别工具对于复杂式子的识别,但有对识别准确率的要求。算式识别工具能够做为API接口提供服务,便于爬虫等须要自动访问网页的工具调用,提升对算术验证码的识别、经过能力。编程
**识别目标:对于四则运算+-*/ 和分式具备识别和计算能力**canvas
- 架构设计:
- pipeline处理,流程以下
- gui读取用户输入图片
- 作图像预处理,包括二值处理、滤波、切割
- 送进CNN识别
- 结合每一个字符的识别结果和位置关系捆绑空间上不连续的字符造成符号(切割时按边界切割)
- 按定义好的支持文法实现递归降低语法制导翻译,对输入记号流递归获得求解结果
- 展现在gui上
- 图片预处理
- 图片预处理以OpenCV做为主要工具。预处理的主要目的是把图片中的字符切割出来,同时避免无关变量对字符识别的影响。
- 主要步骤包括:灰度化、二值化、高斯滤波、字符切割
工具介绍:微信
- 卷积神经网络模型(CNN)
- 国际数学公式识别比赛数据集(CROHME)
海量字符集图片
与实际输入类似
原图
网络
binary image
架构
extracted components
app
项目重要文件介绍:框架
操做说明:
测试样例:
优势
缺点
是否有充足的时间来作计划?
团队在计划阶段是如何解决同事们对于计划的不一样意见的?
你原计划的工做是否最后都作完了? 若是有没作完的,为何?
是否项目的整个过程都按照计划进行,项目出了什么意外?有什么风险是当时没有估计到的,为何没有估计到?
咱们学到了什么? 若是历史重来一遍, 咱们会作什么改进?
咱们有足够的资源来完成各项任务么?
测试的时间,人力和软件/硬件资源是否足够? 对于那些不须要编程的资源 (美工设计/文案)是否低估难度?
每一个相关的成员都及时知道了变动的消息?
咱们采用了什么办法决定“推迟”和“必须实现”的功能?
成员是否可以有效地处理意料以外的工做请求?
设计工做在何时,由谁来完成的?是合适的时间,合适的人么?
设计工做有没有碰到模棱两可的状况,团队是如何解决的?
什么功能产生的Bug最多,为何?在发布以后发现了什么重要的bug? 为何咱们在设计/开发的时候没有想到这些状况?
import solver from PIL import Image from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.uix.label import Label from kivy.uix.widget import Widget from kivy.graphics import Color, Line class PaintWidget(Widget): color = (254, 0, 0, 1) # Pen color 画笔颜色 thick = 8 # Pen thickness 画笔粗度 def __init__(self, root, **kwargs): super().__init__(**kwargs) self.parent_widget = root # Touch down motion: # If the touch position is located in the painting board, draw lines. # 按下动做: # 若是触摸位置在画板内,则在画板上划线 def on_touch_down(self, touch): with self.canvas: Color(*self.color, mode='rgba') if touch.x > self.width or touch.y < self.parent_widget.height - self.height: return touch.ud['line'] = Line(points=(touch.x, touch.y), width=self.thick) # Touch move motion: # Draw line with mouse/hand moving # 移动动做: # 随着鼠标/手指的移动画线 def on_touch_move(self, touch): with self.canvas: if touch.x > self.width or touch.y < self.parent_widget.height - self.height: return touch.ud['line'].points += [touch.x, touch.y] # Touch up motion: # When ending drawing line, save the picture, and call the prediction component to do prediction # 抬起动做: # 结束画线,保存图片成文件,并调用预测相关的组件作预测 def on_touch_up(self, touch): if touch.x > self.width or touch.y < self.parent_widget.height - self.height: return #self.parent.parent.do_predictions() def export_image(self): input_img_name = './input_expression.png' self.export_to_png(input_img_name) im = Image.open(input_img_name) x, y = im.size p = Image.new('RGBA', im.size, (255, 255, 255)) p.paste(im, (0, 0, x, y), im) p.save('white_bg.png') return 'white_bg.png' class Recognizer(BoxLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.number = -1 # Variable to store the predicted number 保存识别的数字的变量 self.orientation = 'horizontal' # UI related UI相关 self.draw_window() # function to declare the components of the application, and add them to the window # 声明程序UI组件的函数,而且将它们添加到窗口上 def draw_window(self): # Clear button 清除按钮 self.clear_button = Button(text='CLEAR', font_name=HandwrittenMathCalculator.font_name, size_hint=(1, 4 / 45), background_color=(255, 165 / 255, 0, 1)) self.solve_button = Button(text='SOLVE', font_name=HandwrittenMathCalculator.font_name, size_hint=(1, 4 / 45), background_color=(255, 165 / 255, 0, 1)) # Painting board 画板 self.painter = PaintWidget(self, size_hint=(1, 8 / 9)) # Label for hint text 提示文字标签 self.hint_label = Label(font_name=HandwrittenMathCalculator.font_name, size_hint=(1, 1 / 45)) # Label for predicted number 识别数字展现标签 self.result_label = Label(font_size=120, size_hint=(1, 1 / 3)) # Label for some info 展现一些信息的标签 self.info_board = Label(font_size=24, size_hint=(1, 22 / 45)) # BoxLayout 盒子布局 first_column = BoxLayout(orientation='vertical', size_hint=(2 / 3, 1)) second_column = BoxLayout(orientation='vertical', size_hint=(1 / 3, 1)) # Add widgets to the window 将各个组件加到应用窗口上 first_column.add_widget(self.painter) first_column.add_widget(self.hint_label) second_column.add_widget(self.result_label) second_column.add_widget(self.info_board) second_column.add_widget(self.solve_button) second_column.add_widget(self.clear_button) self.add_widget(first_column) self.add_widget(second_column) # motion binding 动做绑定 # Bind the click of the clear button to the clear_paint function # 将清除按钮的点击事件绑定到clear_paint函数上 self.clear_button.bind(on_release=self.clear_paint) self.solve_button.bind(on_release=self.solve_expression) self.clear_paint() # Initialize the state of the app 初始化应用状态 # Clear the painting board and initialize the state of the app. def clear_paint(self): self.painter.export_image() #call solver to solve # Clear the painting board and initialize the state of the app. def clear_paint(self, obj=None): self.painter.canvas.clear() self.number = -1 self.result_label.text = '?' self.hint_label.text = 'Write math expression above' self.info_board.text = 'Detected expression:\n' # Extract info from the predictions, and display them on the window # 从预测结果中提取信息,并展现在窗口上 def show_info(self, result, detected_expression='8+7'): if result == None: self.number = 'Error' else: self.number = result self.result_label.text = str(self.number) self.hint_label.text = 'Detected expression and result is shown.Press clear to Retry!' self.info_board.text += detected_expression def solve_expression(self, obj=None): img = self.painter.export_image() self.info_board.text = 'Detected expression:\n' (result,detected_expression) = solver.solve(img) self.show_info(result,detected_expression) # Main app class # 主程序类 class HandwrittenMathCalculator(App): font_name = r'Arial.ttf' def build(self): return Recognizer()
def solve(filename,mode = 'product'): original_img, binary_img = read_img_and_convert_to_binary(filename) symbols = binary_img_segment(binary_img, original_img) sort_symbols = sort_characters(symbols) process.detect_uncontinous_symbols(sort_symbols, binary_img) length = len(symbols) symbols_to_be_predicted = normalize_matrix_value([x['src_img'] for x in symbols]) predict_input_fn = tf.estimator.inputs.numpy_input_fn( x={"x": np.array(symbols_to_be_predicted)}, shuffle=False) predictions = cnn_symbol_classifier.predict(input_fn=predict_input_fn) characters = [] for i,p in enumerate(predictions): # print(p['classes'],FILELIST[p['classes']]) candidates = get_candidates(p['probabilities']) characters.append({'location':symbols[i]['location'],'candidates':candidates}) #print([x['location'] for x in characters]) modify_characters(characters) # print('排序后的字符序列') # print([[x['location'], x['candidates']] for x in characters]) tokens = process.group_into_tokens(characters) # print('识别出的token') print(tokens) node_list = characters_to_nodes(characters) print(node_list) exp_parser = Exp_parser() result=exp_parser.expression(node_list) str = '' for token in tokens: str += token['token_string'] print(result) if result is None: return None, str else: return (round(result,2),str)