日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

人工智能团队博客

發(fā)布時間:2025/4/5 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 人工智能团队博客 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

憤怒的豬蹄小組 Beta展示——算式識別與計算

1.背景介紹

如何在計算機上輔助計算公式?目前的方案主要包括mathOCR、愛作業(yè)、作業(yè)幫等代表,如下:


它們的缺點主要包括:

不支持手寫字符輸入、
不支持復(fù)雜題型、
不支持題庫外的式子等等,
對于復(fù)雜的公式難以識別,對于簡單的公式則應(yīng)用場景不多。

因此我們希望解決上述痛點,增強產(chǎn)品功能。
此類產(chǎn)品主要針對有輔助計算需求的學者和論文寫作者,但還有一個基本的要求是近年來不斷升級的驗證碼識別,以算術(shù)形式出現(xiàn)的驗證碼往往由被修改過的字符以異常的形式排列,因此不要求識別工具對于復(fù)雜式子的識別,但有對識別準確率的要求。算式識別工具可以作為API接口提供服務(wù),便于爬蟲等需要自動訪問網(wǎng)頁的工具調(diào)用,提高對算術(shù)驗證碼的識別、通過能力。

2. 架構(gòu)設(shè)計

**識別目標:對于四則運算+-*/ 和分式具有識別和計算能力**

  • 架構(gòu)設(shè)計:
    • pipeline處理,流程如下
    • gui讀取用戶輸入圖片
    • 做圖像預(yù)處理,包括二值處理、濾波、切割
    • 送進CNN識別
    • 結(jié)合每個字符的識別結(jié)果和位置關(guān)系捆綁空間上不連續(xù)的字符形成符號(切割時按邊界切割)
    • 按定義好的支持文法實現(xiàn)遞歸下降語法制導(dǎo)翻譯,對輸入記號流遞歸得到求解結(jié)果
    • 展示在gui上

3. 系統(tǒng)實現(xiàn)

  • 圖片預(yù)處理
    • 圖片預(yù)處理以O(shè)penCV作為主要工具。預(yù)處理的主要目的是把圖片中的字符切割出來,同時避免無關(guān)變量對字符識別的影響。
    • 主要步驟包括:灰度化、二值化、高斯濾波、字符切割

工具介紹:

  • 卷積神經(jīng)網(wǎng)絡(luò)模型(CNN)
  • 國際數(shù)學公式識別比賽數(shù)據(jù)集(CROHME)
    海量字符集圖片
    與實際輸入相似
    • 原圖

    • binary image

    • extracted components

    項目重要文件介紹:

  • 項目配置文件:
    • 圖像處理:opencv
    • 分類器:tensorflow
    • gui: kivy
  • 操作說明:

  • 運行程序:
    • test.py提供無gui調(diào)用方式展示
    • gui直接運行可帶著gui運行
  • gui
  • 在界面左邊輸入手寫字符
  • 右側(cè)顯示識別結(jié)果,界面上端顯示計算結(jié)果
  • 點擊Solve按鈕:展示結(jié)果
  • 點擊Clear按鈕:清楚輸入狀態(tài)
  • 在右側(cè)欄中間顯示識別出的表達式,方便差錯
  • 4. 實驗結(jié)果

    測試樣例:

    5. 總結(jié)

    優(yōu)點

    • 實現(xiàn)了基本的完整算式識別流程
    • 實現(xiàn)了全字符的識別和捆綁
    • 在當前框架上拓展文法較方便,可以支持更多運算

    缺點

    • 全字符識別導(dǎo)致分類器對于相似字符的辨別效果較差(如稍有點彎曲的1和括號)
    • 當前的處理流程輸入圖片先送入CNN完成識別和捆綁后將捆綁后的符號送進Parser進行語法分析,這樣的方式導(dǎo)致書寫潦草時效果較差,出現(xiàn)非同類符號識別時將導(dǎo)致整個表達式理解錯誤,簡單地概括就是詞法分析限制了語法分析,可以考慮在語法分析中加入冗余容錯,例如不該讀到括號時嘗試重新解析當前的字符為數(shù)字。

    Postmoterm報告

    總述

    • 成員
      • 每個成員在beta階段更加積極配合完成任務(wù),由于課業(yè)影響,整個項目執(zhí)行期較短,但成員基本都能加急完成分配的任務(wù),并致力于找bug和debug。
    • 吸收教訓
      • 在alpha和beta階段的時間安排都不算很合理,不過beta階段的預(yù)備時間比alpha階段多了50%以上,算是做了一定的準備工作。其次由于目標更為清晰,但實現(xiàn)難度較大,實現(xiàn)過程不那么順利。
    • 開發(fā)評價
      • 實現(xiàn)過程遇到的主要苦難時在圖像處理階段而不是模型訓練階段
      • 如何將字符切割出來并將不連續(xù)字符根據(jù)空間關(guān)系進行捆綁是很瑣碎的工作,很容易出現(xiàn)邏輯錯誤
      • 語法制導(dǎo)翻譯的過程中由于運算符關(guān)系優(yōu)先級相當復(fù)雜,手工實現(xiàn)的工作量太大,我們最終沒實現(xiàn)較多復(fù)雜運算符的復(fù)合運算支持,只實現(xiàn)了+-*/分式的表達式識別。

    設(shè)想和目標

    • 設(shè)想
      • 我們的軟件要解決什么問題?是否定義得很清楚?是否對典型用戶和典型場景有清晰的描述?
        • 我們希望設(shè)計一個支持算式識別解析的工具,實現(xiàn)的初衷是提供一個包輸入一張表達式圖解析出計算結(jié)果,用于驗證碼識別,在更復(fù)雜的運算符集上拓展后可用于智能的算式解析。
        • 出于展示目的我們在上一階段的GUI基礎(chǔ)上做了修改也支持了gui展示功能。
    • 目標
      • 我們達到目標了么(原計劃的功能做到了幾個? 按照原計劃交付時間交付了么? 原計劃達到的用戶數(shù)量達到了么?)
      • 實現(xiàn)了。Alpha版本實現(xiàn)了對單個數(shù)字的識別,Beta版本實現(xiàn)了手寫算式識別。按照預(yù)定時間交付。目前暫未推向市場,未獲得用戶。
    • 軟件質(zhì)量
      • 和上一個階段相比,團隊軟件工程的質(zhì)量提高了么? 在什么地方有提高,具體提高了多少,如何衡量的?
      • 我們在代碼質(zhì)量上有所提高,具體是計算核心算法被更新,UI被重寫。
    • 經(jīng)驗教訓:有什么經(jīng)驗教訓? 如果歷史重來一遍, 我們會做什么改進?
      • 項目難度較大,需要關(guān)于圖像處理的一些知識,還需要編譯的知識。
      • 組員的水平差異較大,半數(shù)以上不是計算機學院的,沒有相關(guān)的知識積累,所以部分核心功能的實現(xiàn)團隊成員參與度不高。

    計劃

    是否有充足的時間來做計劃?

    • 是的。

    團隊在計劃階段是如何解決同事們對于計劃的不同意見的?

    • 微信在線討論。

    你原計劃的工作是否最后都做完了? 如果有沒做完的,為什么?

    • 我們原計劃的工作基本完成,但未實現(xiàn)在驗證碼工具上的完整應(yīng)用程序,暫未將識別范圍拓展至更多類型的算式。

    是否項目的整個過程都按照計劃進行,項目出了什么意外?有什么風險是當時沒有估計到的,為什么沒有估計到?

    • 圖像切割后捆綁算符、詞法分析、語法分析都有很多細枝末節(jié)的問題,實現(xiàn)起來很頭疼。算是預(yù)估到的難題,但是依然解決起來比較艱難。

    我們學到了什么? 如果歷史重來一遍, 我們會做什么改進?

    • 提前開始基礎(chǔ)知識的學習,提高成員參與度。

    資源

    我們有足夠的資源來完成各項任務(wù)么?

    • 充足,模型訓練不算是項目的核心問題,其他核心功能都有成員之前有過接觸。

    測試的時間,人力和軟件/硬件資源是否足夠? 對于那些不需要編程的資源 (美工設(shè)計/文案)是否低估難度?

    • 充足,UI不是我們設(shè)計初衷的重點,只是為了展示。

    變更管理

    每個相關(guān)的成員都及時知道了變更的消息?

    • 是的。

    我們采用了什么辦法決定“推遲”和“必須實現(xiàn)”的功能?

    • 取決于當時所有人員的空閑情況,以及交付的緊急程度。

    成員是否能夠有效地處理意料之外的工作請求?

    • 目前都已處理。

    設(shè)計/實現(xiàn)

    設(shè)計工作在什么時候,由誰來完成的?是合適的時間,合適的人么?

    • 是在項目的啟動階段,由團隊討論完成。

    設(shè)計工作有沒有碰到模棱兩可的情況,團隊是如何解決的?

    • 比如對于產(chǎn)品功能的定位,最初的設(shè)計意見不一,最終討論決定先做穩(wěn)一點的驗證碼識別工具。

    什么功能產(chǎn)生的Bug最多,為什么?在發(fā)布之后發(fā)現(xiàn)了什么重要的bug? 為什么我們在設(shè)計/開發(fā)的時候沒有想到這些情況?

    • 字符識別功能Bug最多,原因是初始時野心較大,希望支持較多的運算符,從而分類類別比我們實際使用的多,識別效果有所下降。
    • 詞法分析、語法分析等遞歸調(diào)用的函數(shù)中都容易有未觸及的分支,由于時間限制和成員技能差異,我們沒有進行高覆蓋率的單元測試,測試都是在嘗試使用中進行的,效率較低,可靠性較低。

    完整處理流程代碼展示

    • gui
    import solver from PIL import Imagefrom 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, Lineclass 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.# 按下動作:# 如果觸摸位置在畫板內(nèi),則在畫板上劃線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:returntouch.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:returntouch.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# 抬起動作:# 結(jié)束畫線,保存圖片成文件,并調(diào)用預(yù)測相關(guān)的組件做預(yù)測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.sizep = 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 保存識別的數(shù)字的變量self.orientation = 'horizontal' # UI related UI相關(guān)self.draw_window()# function to declare the components of the application, and add them to the window# 聲明程序UI組件的函數(shù),并且將它們添加到窗口上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 識別數(shù)字展示標簽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 將各個組件加到應(yīng)用窗口上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函數(shù)上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 初始化應(yīng)用狀態(tài)# 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 = -1self.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# 從預(yù)測結(jié)果中提取信息,并展示在窗口上def show_info(self, result, detected_expression='8+7'):if result == None:self.number = 'Error'else:self.number = resultself.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_expressiondef 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()
    • solver
      • 各模塊功能匯總腳本
      • 依次進行圖片二值處理
      • 進行圖像分割
      • 進行非連續(xù)符號合并捆綁
      • 調(diào)用CNN分類器進行分類
      • 根據(jù)位置進行從左到右從上到下排序,符合算式符號的結(jié)合邏輯
        • 至此相當于實現(xiàn)了lexer
      • 調(diào)用parser進行語法制導(dǎo)計算,返回結(jié)果
    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, strelse:return (round(result,2),str)

    轉(zhuǎn)載于:https://www.cnblogs.com/lixiaoda/p/10969634.html

    總結(jié)

    以上是生活随笔為你收集整理的人工智能团队博客的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。