手把手教你线得,一個案例學(xué)會用Matlab App Designer設(shè)計文字識別工具(附源碼)

一饶唤、前言

有時候在讀電子文檔的過程中,往往會遇到圖片形式的文本贯钩,想要復(fù)制下來募狂,記個筆記甚是不便办素,需要對照著打字輸入,活生生被逼成鍵盤俠啊......

image

被逼無奈祸穷,何不自己造個輪子性穿,開發(fā)一款自己專屬的文字識別工具呢,于是我們找到了Matlab App Designer雷滚。

玩過 Matlab 的朋友們都知道需曾,構(gòu)建圖形用戶界面,Matlab提供了兩種工具祈远,一是用guide構(gòu)建呆万,俗稱GUI,在未來版本中會移除车份;二是用App Designer谋减,俗稱App,這是官方推薦的躬充,也是以后主流的框架逃顶。

今天我們就通過一個簡單案例來介紹如何利用App設(shè)計一個圖片文字識別工具。

搭建的方式主要有兩種:

  1. App設(shè)計器:靈活充甚、方便、簡單霸褒,現(xiàn)代化方法伴找;

  2. 基于uifigure的編程方式:靈活、重構(gòu)方便废菱,適合構(gòu)建復(fù)雜技矮、大型的圖形用戶界面,原始社會方法殊轴。

這里我們就以編程方式進(jìn)行創(chuàng)建衰倦。

二、預(yù)備

1. API接口

文字識別涉及到光學(xué)字符識別(Optical Character Recognition旁理,OCR)技術(shù)樊零,如果我們自己造這種底層的輪子,要有高精度的識別率孽文,那估計累得夠嗆驻襟。

幸運(yùn)的是市場上已經(jīng)有成熟的工具了,如百度智能云芋哭、阿里云沉衣、科大訊飛等均提供了API接口,只需借過來用就完事减牺。這里主要以百度智能云提供的文字識別API為例豌习。

免費(fèi)申請文字識別功能后存谎,在控制臺可以查看到API KeySecret Key,由這兩個參數(shù)可以獲得access_token肥隆,它是調(diào)用API接口的必需參數(shù)(如下圖紅色方框所示)愕贡。

image

通過查看文字識別的技術(shù)文檔,我們可以得到通用文字識別(標(biāo)準(zhǔn)版)的請求接口巷屿,如下:

HTTP 方法POST

請求URLhttps://aip.baidubce.com/rest/2.0/ocr/v1/general_basic

URL參數(shù):屬性名:access_token固以,值:通過API KeySecret Key獲取的access_token,參考“Access Token獲取

Header:屬性名:Content-Type嘱巾,值:application/x-www-form-urlencoded

請求參數(shù):屬性名:image憨琳,值:圖像數(shù)據(jù),base64編碼后進(jìn)行urlencode旬昭,要求base64編碼和urlencode后大小不超過4M篙螟,最短邊至少15px,最長邊最大4096px问拘,支持jpg/jpeg/png/bmp格式

返回參數(shù):屬性名:words_result遍略,值:識別結(jié)果數(shù)組

關(guān)于具體的HTTP請求過程接下來會細(xì)聊。

2. 圖像的Base64編碼

Base64是網(wǎng)絡(luò)上最常見的用于傳輸8Bit字節(jié)碼的編碼方式之一骤坐,它是包括小寫字母a-z绪杏、大寫字母A-Z、數(shù)字0-9纽绍、符號+蕾久、/共64個字符的字符集,等號=用來作為后綴用途拌夏。任何符號都可以轉(zhuǎn)換成這個字符集中的字符僧著,該轉(zhuǎn)換過程就叫做Base64編碼。Base64編碼具有不可讀性障簿,需要解碼后才能閱讀盹愚。

許多編程語言都提供了現(xiàn)成的Base64編碼庫函數(shù),Matlab也不例外站故,大家不妨 help matlab.net.base64encode查看細(xì)節(jié)皆怕。

下面提供三種Matlab中的實現(xiàn)方式:

  • Java類---org.apache.commons.codec.binary.Base64 和 matlab.net.base64encode

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n40" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> function base64string = img2base64(fileName)
%IMG2BASE64 Coding an image to base64 file
% INPUTS:
% fileName string, an image file name
% OUTPUTS:
% base64string string, the input image's base64 code
% USAGE:
% >>base64string = img2base64('1.jpg')
% >>base64string = 'xxx'
%
try
fid = fopen(fileName, 'rb');
bytes = fread(fid);
fclose(fid);
% -------------------------------------------
% First method
% -------------------------------------------
encoder = org.apache.commons.codec.binary.Base64;
base64string = char(encoder.encode(bytes))';
% -------------------------------------------
% Second method
% -------------------------------------------
% base64string = matlab.net.base64encode(bytes);
catch
disp('The file does not exist!');
base64string = '';
end % end try
end % end function</pre>

  • 使用Python base64模塊

Matlab中可以直接使用Python,那Python中提供的模塊base64就可以直接使用了世蔗,源代碼如下:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n45" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> function base64string = img2base64_(fileName)
%IMG2BASE64 Coding an image to base64 file
% INPUTS:
% fileName string, an image file name
% OUTPUTS:
% base64string string, the input image's base64 code
% USAGE:
% >>base64string = img2base64('1.jpg')
% >>base64string = 'xxx'
%
try
f = py.open(fileName, 'rb');
bytes = f.read();
f.close();
temp = char(py.base64.b64encode(bytes));
temp = regexp(temp, '(?<=b'').+(?='')', 'match');
base64string = temp{1};
catch
disp('The file does not exist!');
base64string = '';
end % end try
end % end function</pre>

我們可以對如下所示的同一張圖片(500 x 500)進(jìn)行base64編碼端逼,比較一下編碼速度:

image

結(jié)果:'/9j/4AAQSkZ...AAAAAAD/9k='

  • Java類---org.apache.commons.codec.binary.Base64 ? 0.000783 秒
  • matlab.net.base64encode ? 0.017589 秒
  • Python base64模塊 ? 0.000709 秒

可以發(fā)現(xiàn)使用Java類和Python base64模塊的方法,速度相當(dāng)污淋,而使用matlab.net.base64encode速度要慢20多倍顶滩,但編碼一張大小為500 x 500的圖像耗時0.02秒左右,其速度是非常之快了寸爆。

綜合一下礁鲁,我們推薦使用org.apache.commons.codec.binary.Base64類進(jìn)行base64編碼盐欺。

3. 屏幕截圖

識別掃描版pdf文檔、視頻教程等中的文字時仅醇,我們需要對待識別文字所在區(qū)域截個圖冗美,保存為圖像再進(jìn)行后續(xù)識別操作。要實現(xiàn)上述過程析二,首先需要對屏幕進(jìn)行截圖粉洼,Matlab通過借助java.awt.Robot這個Java類來實現(xiàn),截屏源代碼如下所示:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n61" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> function imgData = screenSnipping
%screenSnipping Capturel full-screen to an image
% Output:
% imgData, uint8, image data.
% Source code from: https://www.mathworks.com/support/search.html/answers/362358-how-do-i-take-a-screenshot-using-matlab.html?fq=asset_type_name:answer%20category:matlab/audio-and-video&page=1
% Modified: Qingpinwangzi
% Date: Apr 14, 2021.

% Take screen capture
robo = java.awt.Robot;
tk = java.awt.Toolkit.getDefaultToolkit();
rectSize = java.awt.Rectangle(tk.getScreenSize());
cap = robo.createScreenCapture(rectSize);

% Convert to an RGB image
rgb = typecast(cap.getRGB(0, 0, cap.getWidth, cap.getHeight, [], 0, cap.getWidth), 'uint8');
imgData = zeros(cap.getHeight, cap.getWidth, 3, 'uint8');
imgData(:, :, 1) = reshape(rgb(3:4:end), cap.getWidth, [])';
imgData(:, :, 2) = reshape(rgb(2:4:end), cap.getWidth, [])';
imgData(:, :, 3) = reshape(rgb(1:4:end), cap.getWidth, [])';
end</pre>

4. 調(diào)用百度API識別文字

上述第1節(jié)中我們提到過叶摄,access_token是調(diào)用API接口的必需參數(shù)属韧。通過閱讀技術(shù)文檔得知,需要API KeySecret Key進(jìn)行http請求就可以獲得蛤吓,核心代碼如下:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n64" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> url = ['https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=', apiKey, '&client_secret=', secretKey];
res = webread(url, options);
access_token = res.access_token;</pre>

有了access_token我們就可以調(diào)用文字識別API進(jìn)行文字識別了宵喂,這里再分享下識別文字的源代碼:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n66" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> function result = getWordsByBaiduOCR(fileName, apiKey, secretKey, accessToken, apiURL, outType)
%GETWORDSBYBAIDUOCR return recognition words
% INPUTS:
% fileName string, an image file name
% apiKey string, the API Key of the application
% secretKey string, The Secret Key of the application
% accessToken string, default is '', get the Access Token by API
% Key and Secret Key.
% apiURL string, such as:
% 'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate'
% 'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic'
% 'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic'
% outType, 'MultiLine|SingleLine'
% OUTPUTS:
% result []|struct
% USAGE:
% >>result = getWordsByBaiduOCR(fileName, apiKey, secretKey, accessToken, apiURL)
% Date: Mar 18, 2021.
% Author: 清貧王子
%

options = weboptions('RequestMethod', 'post');
if isempty(outType)
outType = 'MultiLine';
end

if isempty(accessToken)
url = ['https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=', apiKey, '&client_secret=', secretKey];
res = webread(url, options);
access_token = res.access_token;
else
access_token = accessToken;
end % end if

url = [apiURL, '?access_token=', access_token];
options.HeaderFields = { 'Content-Type', 'application/x-www-form-urlencoded'};
imgBase64String = img2base64(fileName);
if isempty(imgBase64String)
result = '';
return
end % end if
res = webwrite(url, 'image', imgBase64String, options);
wordsRsult = res.words_result;

data.ocrResultChar = '';

if strcmp(outType, 'SingleLine')
for ii = 1 : size(wordsRsult, 1)
data.ocrResultChar = [data.ocrResultChar, wordsRsult(ii,1).words];
end % end for

elseif strcmp(outType, 'MultiLine')
for ii = 1 : size(wordsRsult, 1)
data.ocrResultChar{ii} = wordsRsult(ii,1).words;
end % end for
end
result = data.ocrResultChar;
end % end function</pre>

簡單測試下這個函數(shù),輸入下面所示的圖片会傲,我們進(jìn)行圖片(截圖地址:https://ww2.mathworks.cn/products/matlab/app-designer.html)中的文字識別锅棕。

image

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n69" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> >> result =

1×7 cell 數(shù)組

列 1 至 4

{'App設(shè)計工具幫助您…'} {'開發(fā)專業(yè)背景。您只…'} {'面(GUI)設(shè)計布局,…'} {'編程淌山。'}

列 5 至 7

{'要共享App,您可以使…'} {' MATLAB Compile…'} {'桌面App或 Web App'}

result{1}

ans =

'App設(shè)計工具幫助您創(chuàng)建專業(yè)的App,同時并不要求軟件'</pre>

識別結(jié)果中共有7個cell裸燎,代表識別了圖片中的7行文字,即1個cell對應(yīng)1行識別的文字艾岂,如result{1}的結(jié)果顺少。

三、工具搭建

以基于uifigure的編程方式創(chuàng)建APP王浴,我們推薦面向?qū)ο螅∣OP)方法編程,簡單起見梅猿,這里主要封裝一個類來實現(xiàn)所需的功能氓辣。當(dāng)然更標(biāo)準(zhǔn)的做法是利用MVC等設(shè)計模式將界面和邏輯分離,能達(dá)到對擴(kuò)展開放袱蚓,對修改封閉的軟件設(shè)計原則钞啸。

1. 功能需求

我們的功能需求非常簡單,主要有以下兩個功能:

  • 識別已經(jīng)存在的圖像中的文字

  • 識別掃描版pdf文檔喇潘、視頻教程等中的文字

實現(xiàn)第1個功能体斩,我們只需要加載圖像,然后調(diào)用識別函數(shù)進(jìn)行識別颖低,將識別結(jié)果顯示到文本區(qū)域就可以了絮吵;而實現(xiàn)第2個功能,首先需要屏幕截圖忱屑,選取待識別文字所在的區(qū)域蹬敲,存儲為圖像暇昂,后續(xù)處理和實現(xiàn)第1個功能的一樣。

根據(jù)上述描述伴嗡,我們需要的控件有:加載圖像按鈕急波,截圖按鈕,圖像顯示器瘪校,識別結(jié)果顯示文本域澄暮。另外,需要一個清理按鈕阱扬,用于清除顯示的圖像和識別結(jié)果泣懊;還需要一個設(shè)置按鈕,用于配置API KeySecret Key价认。

便于敘述嗅定,我們先展示下最終設(shè)計的結(jié)果,如下圖所示:

image
image
文字識別工具主界面 設(shè)置界面

在設(shè)置界面中用踩,需要兩個標(biāo)簽和兩個文本框渠退,兩外需要兩個按鈕。據(jù)此脐彩,我們需要的控件都清楚了碎乃,接下來讓我們一起來創(chuàng)建他們吧!

2. 實現(xiàn)細(xì)節(jié)

主要封裝一個類來實現(xiàn)所需的功能惠奸,我們給這個類起個名:ReadWords梅誓,這個類需要繼承matlab.apps.AppBase,它的屬性就是界面中的所有控件,那么這個類看上去應(yīng)該是這樣的:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n93" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> classdef ReadWords < matlab.apps.AppBase
%%
properties
UIFig matlab.ui.Figure

ContainerForMain matlab.ui.container.GridLayout
ThisTB matlab.ui.container.Toolbar
SnippingToolBtn matlab.ui.container.toolbar.PushTool
ImgLoadToolBtn matlab.ui.container.toolbar.PushTool
SetupToolBtn matlab.ui.container.toolbar.PushTool
CleanToolBtn matlab.ui.container.toolbar.PushTool
ImgShow matlab.ui.control.Image
WordsShowTA matlab.ui.control.TextArea

ContainerForSetup matlab.ui.container.GridLayout
APIKeyText matlab.ui.control.EditField
SecrectKeyText matlab.ui.control.EditField
ResetBtn matlab.ui.control.Button
SaveBtn matlab.ui.control.Button
end % end properties

%%
properties(Hidden, Dependent)
APIKeyVal
SecrectKeyVal
end % end properties

%%
properties(Access = protected)
HasSetup = false
end % end properties

end % end classdef</pre>

下面說明下一些重要的屬性

公有屬性:

  • UIFig 必須是matlab.ui.Figure類的屬性佛南,通過uifigure構(gòu)造梗掰,這是整個工具的主窗口

  • ContainerForMain 必須是matlab.ui.container.GridLayout類的屬性,通過uigridlayout構(gòu)造嗅回,這是主窗口的布局容器

  • ThisTB 必須是matlab.ui.container.Toolbar類的屬性及穗,通過uitoolbar構(gòu)造,這是工具欄的容器绵载,用于放置SnippingToolBtn埂陆、ImgLoadToolBtnSetupToolBtn娃豹、CleanToolBtn這4個工具按鈕

  • ImgShow 必須是matlab.ui.control.Image類的屬性焚虱,通過uiimage構(gòu)造,用于顯示加載或者截圖后的圖像

  • WordsShowTA 必須是matlab.ui.control.TextArea類的屬性懂版,通過uitextarea構(gòu)造鹃栽,用于顯示文字識別結(jié)果

  • ContainerForSetup 設(shè)置界面中的網(wǎng)格容器

  • APIKeyTextSecrectKeyText 主要用于輸入APIKeySecrectKey

  • ResetBtnSaveBtn兩個按鈕分別用來實現(xiàn)重置和保存APIKeySecrectKey

從屬灭将、隱藏屬性:

  • APIKeyVal 用于接收APIKeyText中輸入的APIKey的值

  • SecrectKeyVal 用于接收SecrectKeyText中輸入的SecrectKey的值

受保護(hù)屬性:

  • HasSetup 用于標(biāo)識是否配置了APIKeySecrectKey咧最,默認(rèn)為false

至此脊岳,我們設(shè)置好了所有的屬性包个,然后進(jìn)行構(gòu)造方法、析構(gòu)方法以及類方法的編寫摹察。

加上構(gòu)造方法恩掷、析構(gòu)方法以及從屬屬性APIKeyValSecrectKeyValget方法的代碼后看上去是這樣的:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n125" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> classdef ReadWords < matlab.apps.AppBase
%%
properties
UIFig matlab.ui.Figure

ContainerForMain matlab.ui.container.GridLayout
ThisTB matlab.ui.container.Toolbar
SnippingToolBtn matlab.ui.container.toolbar.PushTool
ImgLoadToolBtn matlab.ui.container.toolbar.PushTool
SetupToolBtn matlab.ui.container.toolbar.PushTool
CleanToolBtn matlab.ui.container.toolbar.PushTool
ImgShow matlab.ui.control.Image
WordsShowTA matlab.ui.control.TextArea

ContainerForSetup matlab.ui.container.GridLayout
APIKeyText matlab.ui.control.EditField
SecrectKeyText matlab.ui.control.EditField
ResetBtn matlab.ui.control.Button
SaveBtn matlab.ui.control.Button
end % end properties

%%
properties(Hidden, Dependent)
APIKeyVal
SecrectKeyVal
end % end properties

%%
properties(Access = protected)
HasSetup = false
end % end properties

%%
methods
% --------------------------------------
% % Constructor
% --------------------------------------
function app = ReadWords
% Create UIFigure and components
app.buildApp();
% Register the app with App Designer
registerApp(app, app.UIFig)

if nargout == 0
clear app
end
end % end Constructor

% --------------------------------------
% % Destructor
% --------------------------------------
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFig)
end % end Constructor

% --------------------------------------
% % Get/Set methods
% --------------------------------------
% get.APIKeyVal
function apiKeyVal = get.APIKeyVal(app)
apiKeyVal = app.APIKeyText.Value;
end

% get.SecrectKeyVal
function secrectKeyVal = get.SecrectKeyVal(app)
secrectKeyVal = app.SecrectKeyText.Value;
end
end % end methods
end % end classdef</pre>

析構(gòu)方法(Destructor)的寫法是固定的,構(gòu)造方法中的registerApp(app, app.UIFig)也是固定的供嚎,另外的buildApp()方法就用來創(chuàng)建界面黄娘、注冊各個控件。

我們將后續(xù)的方法都創(chuàng)建為私有方法克滴,添加了buildApp()方法后的整個ReadWords類是下面這樣的:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n128" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> classdef ReadWords < matlab.apps.AppBase
%%
properties
UIFig matlab.ui.Figure

ContainerForMain matlab.ui.container.GridLayout
ThisTB matlab.ui.container.Toolbar
SnippingToolBtn matlab.ui.container.toolbar.PushTool
ImgLoadToolBtn matlab.ui.container.toolbar.PushTool
SetupToolBtn matlab.ui.container.toolbar.PushTool
CleanToolBtn matlab.ui.container.toolbar.PushTool
ImgShow matlab.ui.control.Image
WordsShowTA matlab.ui.control.TextArea

ContainerForSetup matlab.ui.container.GridLayout
APIKeyText matlab.ui.control.EditField
SecrectKeyText matlab.ui.control.EditField
ResetBtn matlab.ui.control.Button
SaveBtn matlab.ui.control.Button
end % end properties

%%
properties(Hidden, Dependent)
APIKeyVal
SecrectKeyVal
end % end properties

%%
properties(Access = protected)
HasSetup = false
end % end properties

%%
methods
% --------------------------------------
% % Constructor
% --------------------------------------
function app = ReadWords
% Create UIFigure and components
app.buildApp();
% Register the app with App Designer
registerApp(app, app.UIFig)

if nargout == 0
clear app
end
end % end Constructor

% --------------------------------------
% % Destructor
% --------------------------------------
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFig)
end % end Constructor

% --------------------------------------
% % Get/Set methods
% --------------------------------------
% get.APIKeyVal
function apiKeyVal = get.APIKeyVal(app)
apiKeyVal = app.APIKeyText.Value;
end

% get.SecrectKeyVal
function secrectKeyVal = get.SecrectKeyVal(app)
secrectKeyVal = app.SecrectKeyText.Value;
end
end % end methods

%%
methods(Access = private)
% buildApp
function buildApp(app)
%
% --------------------------------------
% % Main Figure
% --------------------------------------
app.UIFig = uifigure();
app.UIFig.Icon = 'icons/img2text.png';
app.UIFig.Name = 'ReadWords';
app.UIFig.Visible = 'off';
app.UIFig.Position = [app.UIFig.Position(1), app.UIFig.Position(2), 745, 420];
app.UIFig.AutoResizeChildren = 'on';
app.UIFig.Units = 'Normalized';
app.setAutoResize(app.UIFig, true);

% --------------------------------------
% % Toolbar
% --------------------------------------
app.ThisTB = uitoolbar(app.UIFig);
% SetupToolBtn
app.SetupToolBtn = uipushtool(app.ThisTB);
app.SetupToolBtn.Icon = 'icons/setup.png';
app.SetupToolBtn.Tooltip = 'Setup';

% SnippingToolBtn
app.SnippingToolBtn = uipushtool(app.ThisTB);
app.SnippingToolBtn.Icon = 'icons/snip.png';
app.SnippingToolBtn.Tooltip = 'Screenshot';

% ImgLoadToolBtn
app.ImgLoadToolBtn = uipushtool(app.ThisTB);
app.ImgLoadToolBtn.Icon = 'icons/load.png';
app.ImgLoadToolBtn.Tooltip = 'Load image';

% CleanToolBtn
app.CleanToolBtn = uipushtool(app.ThisTB);
app.CleanToolBtn.Icon = 'icons/clean.png';
app.CleanToolBtn.Tooltip = 'Clean';

% --------------------------------------
% % ContainerForMain
% --------------------------------------
app.ContainerForMain = uigridlayout(app.UIFig, [1, 2]);

% ContainerForMain
imgShowPanel = uipanel(app.ContainerForMain, 'Title', 'Original');
resultShowPanel = uipanel(app.ContainerForMain, 'Title', 'Result');
% ImgShow
imgShowPanelLay = uigridlayout(imgShowPanel, [1, 1]);
imgShowPanelLay.RowSpacing = 0;
imgShowPanelLay.ColumnSpacing = 0;
app.ImgShow = uiimage(imgShowPanelLay);
% WordsShowTA
resultShowPanelLay = uigridlayout(resultShowPanel, [1, 1]);
resultShowPanelLay.RowSpacing = 0;
resultShowPanelLay.ColumnSpacing = 0;
app.WordsShowTA = uitextarea(resultShowPanelLay);
app.WordsShowTA.FontSize = 22;

% --------------------------------------
% % ContainerForSetup
% --------------------------------------
app.ContainerForSetup = uigridlayout(app.UIFig, [4, 3]);
app.ContainerForSetup.RowHeight = {22, 22, 22, '1x'};
app.ContainerForSetup.ColumnWidth = {'1x', '1x', '2.5x'};
app.ContainerForSetup.Visible = 'off';
apiKeyLabel = uilabel(app.ContainerForSetup, 'Text', 'API Key');
apiKeyLabel.HorizontalAlignment = 'right';
apiKeyLabel.Layout.Row = 1;
apiKeyLabel.Layout.Column = 1;
% APIKeyText
app.APIKeyText = uieditfield(app.ContainerForSetup);
app.APIKeyText.Layout.Row = 1;
app.APIKeyText.Layout.Column = 2;
secrectKeyLabel = uilabel(app.ContainerForSetup, 'Text', 'Secrect Key');
secrectKeyLabel.HorizontalAlignment = 'right';
secrectKeyLabel.Layout.Row = 2;
secrectKeyLabel.Layout.Column = 1;
% SecrectKeyText
app.SecrectKeyText = uieditfield(app.ContainerForSetup);
app.SecrectKeyText.Layout.Row = 2;
app.SecrectKeyText.Layout.Column = 2;
% ResetBtn
app.ResetBtn = uibutton(app.ContainerForSetup, 'Text', 'Reset');
app.ResetBtn.Layout.Row = 3;
app.ResetBtn.Layout.Column = 1;
% SaveBtn
app.SaveBtn = uibutton(app.ContainerForSetup, 'Text', 'Save');
app.SaveBtn.Layout.Row = 3;
app.SaveBtn.Layout.Column = 2;
% Set visibility for UIFig
movegui(app.UIFig, 'center');
app.UIFig.Visible = 'on';

% --------------------------------------
% % RunstartupFcn
% --------------------------------------
app.runStartupFcn(@startupFcn);

end % end buildApp
end % methods
end % end classdef</pre>

需要注意的是逼争,工具欄按鈕和窗口的圖標(biāo)來源于:https://www.easyicon.cc/。一些常見的圖標(biāo)素材都可以從中免費(fèi)下載劝赔。我們已經(jīng)將圖標(biāo)下載完畢誓焦,需要的朋友可以點擊下方鏈接來下載:

鏈接:https://pan.baidu.com/s/11kIvt4SX-MhQ2ltEeC18ZA 提取碼:5i3k

另外,app.runStartupFcn(@startupFcn);語句調(diào)用的是父類matlab.apps.AppBase的方法着帽,我們將各個控件的注冊任務(wù)放在startupFcn這個方法中完成杂伟。這里不妨先注釋掉這個語句,直接運(yùn)行ReadWords.m便可以顯示出我們剛才在buildApp方法中構(gòu)造的界面了仍翰,動圖演示如下:

image

可以看到赫粥,我們在點擊工具欄各個按鈕時,沒有反應(yīng)予借,這是因為到目前為止我們還沒有給各個控件注冊回調(diào)方法越平,那接下來將會在startupFcn這個方法中完成各個控件的注冊任務(wù),代碼如下:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n135" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> classdef ReadWords < matlab.apps.AppBase
%%
properties
UIFig matlab.ui.Figure

ContainerForMain matlab.ui.container.GridLayout
ThisTB matlab.ui.container.Toolbar
SnippingToolBtn matlab.ui.container.toolbar.PushTool
ImgLoadToolBtn matlab.ui.container.toolbar.PushTool
SetupToolBtn matlab.ui.container.toolbar.PushTool
CleanToolBtn matlab.ui.container.toolbar.PushTool
ImgShow matlab.ui.control.Image
WordsShowTA matlab.ui.control.TextArea

ContainerForSetup matlab.ui.container.GridLayout
APIKeyText matlab.ui.control.EditField
SecrectKeyText matlab.ui.control.EditField
ResetBtn matlab.ui.control.Button
SaveBtn matlab.ui.control.Button
end % end properties

%%
properties(Hidden, Dependent)
APIKeyVal
SecrectKeyVal
end % end properties

%%
properties(Access = protected)
HasSetup = false
end % end properties

%%
methods
% --------------------------------------
% % Constructor
% --------------------------------------
function app = ReadWords
% Create UIFigure and components
app.buildApp();
% Register the app with App Designer
registerApp(app, app.UIFig)

if nargout == 0
clear app
end
end % end Constructor

% --------------------------------------
% % Destructor
% --------------------------------------
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFig)
end % end Constructor

% --------------------------------------
% % Get/Set methods
% --------------------------------------
% get.APIKeyVal
function apiKeyVal = get.APIKeyVal(app)
apiKeyVal = app.APIKeyText.Value;
end

% get.SecrectKeyVal
function secrectKeyVal = get.SecrectKeyVal(app)
secrectKeyVal = app.SecrectKeyText.Value;
end
end % end methods

%%
methods(Access = private)
% buildApp
function buildApp(app)
%
% --------------------------------------
% % Main Figure
% --------------------------------------
app.UIFig = uifigure();
app.UIFig.Icon = 'icons/img2text.png';
app.UIFig.Name = 'ReadWords';
app.UIFig.Visible = 'off';
app.UIFig.Position = [app.UIFig.Position(1), app.UIFig.Position(2), 745, 420];
app.UIFig.AutoResizeChildren = 'on';
app.UIFig.Units = 'Normalized';
app.setAutoResize(app.UIFig, true);

% --------------------------------------
% % Toolbar
% --------------------------------------
app.ThisTB = uitoolbar(app.UIFig);
% SetupToolBtn
app.SetupToolBtn = uipushtool(app.ThisTB);
app.SetupToolBtn.Icon = 'icons/setup.png';
app.SetupToolBtn.Tooltip = 'Setup';

% SnippingToolBtn
app.SnippingToolBtn = uipushtool(app.ThisTB);
app.SnippingToolBtn.Icon = 'icons/snip.png';
app.SnippingToolBtn.Tooltip = 'Screenshot';

% ImgLoadToolBtn
app.ImgLoadToolBtn = uipushtool(app.ThisTB);
app.ImgLoadToolBtn.Icon = 'icons/load.png';
app.ImgLoadToolBtn.Tooltip = 'Load image';

% CleanToolBtn
app.CleanToolBtn = uipushtool(app.ThisTB);
app.CleanToolBtn.Icon = 'icons/clean.png';
app.CleanToolBtn.Tooltip = 'Clean';

% --------------------------------------
% % ContainerForMain
% --------------------------------------
app.ContainerForMain = uigridlayout(app.UIFig, [1, 2]);

% ContainerForMain
imgShowPanel = uipanel(app.ContainerForMain, 'Title', 'Original');
resultShowPanel = uipanel(app.ContainerForMain, 'Title', 'Result');
% ImgShow
imgShowPanelLay = uigridlayout(imgShowPanel, [1, 1]);
imgShowPanelLay.RowSpacing = 0;
imgShowPanelLay.ColumnSpacing = 0;
app.ImgShow = uiimage(imgShowPanelLay);
% WordsShowTA
resultShowPanelLay = uigridlayout(resultShowPanel, [1, 1]);
resultShowPanelLay.RowSpacing = 0;
resultShowPanelLay.ColumnSpacing = 0;
app.WordsShowTA = uitextarea(resultShowPanelLay);
app.WordsShowTA.FontSize = 22;

% --------------------------------------
% % ContainerForSetup
% --------------------------------------
app.ContainerForSetup = uigridlayout(app.UIFig, [4, 3]);
app.ContainerForSetup.RowHeight = {22, 22, 22, '1x'};
app.ContainerForSetup.ColumnWidth = {'1x', '1x', '2.5x'};
app.ContainerForSetup.Visible = 'off';
apiKeyLabel = uilabel(app.ContainerForSetup, 'Text', 'API Key');
apiKeyLabel.HorizontalAlignment = 'right';
apiKeyLabel.Layout.Row = 1;
apiKeyLabel.Layout.Column = 1;
% APIKeyText
app.APIKeyText = uieditfield(app.ContainerForSetup);
app.APIKeyText.Layout.Row = 1;
app.APIKeyText.Layout.Column = 2;
secrectKeyLabel = uilabel(app.ContainerForSetup, 'Text', 'Secrect Key');
secrectKeyLabel.HorizontalAlignment = 'right';
secrectKeyLabel.Layout.Row = 2;
secrectKeyLabel.Layout.Column = 1;
% SecrectKeyText
app.SecrectKeyText = uieditfield(app.ContainerForSetup);
app.SecrectKeyText.Layout.Row = 2;
app.SecrectKeyText.Layout.Column = 2;
% ResetBtn
app.ResetBtn = uibutton(app.ContainerForSetup, 'Text', 'Reset');
app.ResetBtn.Layout.Row = 3;
app.ResetBtn.Layout.Column = 1;
% SaveBtn
app.SaveBtn = uibutton(app.ContainerForSetup, 'Text', 'Save');
app.SaveBtn.Layout.Row = 3;
app.SaveBtn.Layout.Column = 2;
% Set visibility for UIFig
movegui(app.UIFig, 'center');
app.UIFig.Visible = 'on';

% --------------------------------------
% % RunstartupFcn
% --------------------------------------
app.runStartupFcn(@startupFcn);
end % end buildApp

% startupFcn
function startupFcn(app, ~, ~)
% Setup APIKeyText and SecrectKeyText
if exist('apikey.mat', 'file')
temp = load('apikey.mat');
app.APIKeyText.Value = temp.key.apiKeyVal;
app.APIKeyText.Editable = 'off';
app.SecrectKeyText.Value = temp.key.secrectKeyVal;
app.SecrectKeyText.Editable = 'off';
end

% Register callback
app.SnippingToolBtn.ClickedCallback = @app.clickedSnippingToolBtn;
app.ImgLoadToolBtn.ClickedCallback = @app.clickedImgLoadToolBtn;
app.SetupToolBtn.ClickedCallback = @app.clickedSetupToolBtn;
app.CleanToolBtn.ClickedCallback = @app.clickedCleanToolBtn;

app.ResetBtn.ButtonPushedFcn = @app.callbackResetBtn;
app.SaveBtn.ButtonPushedFcn = @app.callbackSaveBtn;
end % end function
end % methods
end % end classdef</pre>

由此灵迫,我們總共為6個按鈕注冊了6個回調(diào)方法秦叛,需要都進(jìn)行實現(xiàn),不然觸發(fā)按鈕時瀑粥,該按鈕不會做出響應(yīng)书闸。簡單起見,這里我們以實現(xiàn)設(shè)置界面中的SaveBtn的回調(diào)方法callbackSaveBtn為例子來說明利凑。

在沒有設(shè)置APIKeySecrectKey前,觸發(fā)SnippingToolBtn或者ImgLoadToolBtn會有先進(jìn)行設(shè)置的提示:

image

callbackSaveBtn方法實現(xiàn)的邏輯:首先由HasSetup屬性判斷是否進(jìn)行了APIKeySecrectKey的設(shè)置(初始默認(rèn)是false沒有設(shè)置)嫌术,如果沒有設(shè)置哀澈,會提示沒有APIKeySecrectKey,則需要輸入APIKeySecrectKey的值度气,然后點擊保存按鈕割按,那么后臺會將獲取到的值存儲下來(.mat文件),更新HasSetup的值為true磷籍,后續(xù)我們就不必要再次輸入了适荣,要想更換值的話现柠,點擊重置按鈕重新配置即可;如果進(jìn)行了設(shè)置(HasSetup屬性為true)弛矛,直接保存即可够吩。

具體的代碼如下:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n141" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> % --------------------------------------
% % Callback functions
% --------------------------------------
% callbackSaveBtn
function callbackSaveBtn(app, ~, ~)
if ~isempty(app.SecrectKeyText.Value) && ~isempty(app.APIKeyText.Value)
key.apiKeyVal = app.APIKeyText.Value;
key.secrectKeyVal = app.SecrectKeyText.Value;
if exist('apikey.mat', 'file')
delete('apikey.mat');
end
save('apikey.mat', 'key');
!attrib +s +h apikey.mat
uialert(app.UIFig, 'Save successfully!', 'Confirm', 'Icon', 'success');
app.APIKeyText.Editable = 'off';
app.SecrectKeyText.Editable = 'off';
else
uialert(app.UIFig, 'API Key or Secrect Key is empty!', 'Confirm', 'Icon', 'warning');
end % end if
end % callbackSaveBtn</pre>

實現(xiàn)了保存按鈕的功能后,就可以得到如下動圖所示的效果了丈氓。

image

其他的回調(diào)函數(shù)源代碼:

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="matlab" cid="n145" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.8rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: var(--codeboxes); position: relative !important; border-radius: 0.3rem; color: rgb(255, 255, 255); padding: 8px 1.5rem 6px 0px; margin-bottom: 1.5rem; margin-top: 1.5rem; width: inherit; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> % clickedSnippingToolBtn
function clickedSnippingToolBtn(app, ~, ~)
if ~isempty(app.SecrectKeyText.Value) && ~isempty(app.APIKeyText.Value)
app.UIFig.Visible = 'off';
pause(0.1);
outFileName = 'temp.png';
cropImg(outFileName);
!attrib +s +h temp.png
%
app.ImgShow.ImageSource = imread(outFileName);
app.UIFig.Visible = 'on';
%
apiURL = 'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic';
words = getWordsByBaiduOCR(outFileName, app.APIKeyVal, app.SecrectKeyVal, '', apiURL, 'MultiLine');
app.WordsShowTA.Value = words;
else
msg = {'API Key or Secrect Key is empty!'; 'Please set it up first!'};
uialert(app.UIFig, msg, 'Confirm', 'Icon', 'warning');
end
end % end clickedSnippingToolBtn

% clickedImgLoadToolBtn
function clickedImgLoadToolBtn(app, ~, ~)
if ~isempty(app.SecrectKeyText.Value) && ~isempty(app.APIKeyText.Value)
[fName, fPath] = uigetfile({'.png'; '.jpg'; '.bmp'; '.tif'}, 'Open image');
if ~isequal(any([fName, fPath]), 0)
img = imread(strcat(fPath, fName));
outFileName = 'temp.png';
if exist(outFileName, 'file')
delete(outFileName)
end
imwrite(img, outFileName);
!attrib +s +h temp.png
%
app.ImgShow.ImageSource = imread(outFileName);
app.UIFig.Visible = 'on';
%
apiURL = 'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic';
words = getWordsByBaiduOCR(outFileName, app.APIKeyVal, app.SecrectKeyVal, '', apiURL, 'MultiLine');
app.WordsShowTA.Value = words;
else
return
end % end if
else % end if
msg = {'API Key or Secrect Key is empty!'; 'Please set it up first!'};
uialert(app.UIFig, msg, 'Confirm', 'Icon', 'warning');
end
end % end clickedImgLoadToolBtn

% clickedSetupToolBtn
function clickedSetupToolBtn(app, ~, ~)
if ~app.HasSetup
app.ContainerForMain.Visible = 'off';
app.ContainerForSetup.Visible = 'on';
app.HasSetup = true;
else
app.ContainerForMain.Visible = 'on';
app.ContainerForSetup.Visible = 'off';
app.HasSetup = false;
end
end % end clickedSetupToolBtn

% clickedCleanToolBtn
function clickedCleanToolBtn(app, ~, ~)
app.WordsShowTA.Value = '';
app.ImgShow.ImageSource = '';
end % end clickedCleanToolBtn

% callbackResetBtn
function callbackResetBtn(app, ~, ~)
app.APIKeyText.Value = '';
app.APIKeyText.Editable = 'on';
app.SecrectKeyText.Value = '';
app.SecrectKeyText.Editable = 'on';
end % callbackResetBtn</pre>

四周循、使用演示

現(xiàn)在讓我們來測試一下搭建的圖像識別工具吧,比如万俗,某麻子同學(xué)是一名研究生湾笛,在閱讀那種掃描版的pdf文獻(xiàn)時,想把其中的一段語句復(fù)制下來用于記錄筆記或者做PPT用闰歪,這時我們的工具就派上用場了:

image

剎那間嚎研,某麻子同學(xué)得到了想要的結(jié)果,露出了久違的幸福的一笑库倘!

image

五临扮、結(jié)語

至此,我們完成了一個比較完整的文字識別工具于樟!希望您喜歡公条,并且可以從中獲得有用的東西。

本文完整代碼迂曲,請在GZH內(nèi)回復(fù)“文字識別工具”進(jìn)行下載靶橱。

【往期推薦】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末路捧,一起剝皮案震驚了整個濱河市关霸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杰扫,老刑警劉巖队寇,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異章姓,居然都是意外死亡佳遣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門凡伊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來零渐,“玉大人,你說我怎么就攤上這事系忙∷信危” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長风宁。 經(jīng)常有香客問我洁墙,道長,這世上最難降的妖魔是什么戒财? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任热监,我火速辦了婚禮,結(jié)果婚禮上固翰,老公的妹妹穿的比我還像新娘狼纬。我一直安慰自己,他們只是感情好骂际,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布疗琉。 她就那樣靜靜地躺著,像睡著了一般歉铝。 火紅的嫁衣襯著肌膚如雪盈简。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天太示,我揣著相機(jī)與錄音柠贤,去河邊找鬼。 笑死类缤,一個胖子當(dāng)著我的面吹牛臼勉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播餐弱,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宴霸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了膏蚓?” 一聲冷哼從身側(cè)響起瓢谢,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驮瞧,沒想到半個月后氓扛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡论笔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年采郎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狂魔。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡尉剩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出毅臊,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布管嬉,位于F島的核電站皂林,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蚯撩。R本人自食惡果不足惜础倍,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胎挎。 院中可真熱鬧沟启,春花似錦、人聲如沸犹菇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揭芍。三九已至胳搞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間称杨,已是汗流浹背肌毅。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留姑原,地道東北人悬而。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像锭汛,于是被迫代替她去往敵國和親笨奠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容