相关文章推荐
体贴的甘蔗  ·  .NetCore ...·  1 年前    · 
深情的砖头  ·  jquery ...·  2 年前    · 
手把手教你,一个案例学会用Matlab App Designer设计文字识别工具(附源码)

手把手教你,一个案例学会用Matlab App Designer设计文字识别工具(附源码)

【目录】





一、前言

有时候在读电子文档的过程中,往往会遇到图片形式的文本,想要复制下来,记个笔记甚是不便,需要对照着打字输入,活生生被逼成键盘侠啊......

被逼无奈,何不自己造个轮子,开发一款自己专属的文字识别工具呢,于是我们找到了Matlab App Designer。

玩过 Matlab 的朋友们都知道,构建图形用户界面,Matlab提供了两种工具,一是用 guide 构建,俗称 GUI ,在未来版本中会移除;二是用 App Designer ,俗称 App ,这是官方推荐的,也是以后主流的框架。

今天我们就通过一个简单案例来介绍如何利用 App 设计一个图片文字识别工具。

搭建的方式主要有两种:

  1. App设计器:灵活、方便、简单,现代化方法;
  2. 基于 uifigure 的编程方式:灵活、重构方便,适合构建复杂、大型的图形用户界面,原始社会方法。

这里我们就以编程方式进行创建。

二、预备

1. API接口

文字识别涉及到光学字符识别(Optical Character Recognition,OCR)技术,如果我们自己造这种底层的轮子,要有高精度的识别率,那估计累得够呛。

幸运的是市场上已经有成熟的工具了,如百度智能云、阿里云、科大讯飞等均提供了API接口,只需借过来用就完事。这里主要以 百度智能云 提供的文字识别API为例。

免费申请文字识别功能后,在控制台可以查看到 API Key Secret Key ,由这两个参数可以获得 access_token ,它是调用 API 接口的必需参数(如下图红色方框所示)。

通过查看文字识别的技术文档,我们可以得到 通用文字识别(标准版) 的请求接口,如下:

HTTP 方法 POST
请求URL https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic
URL参数 :属性名:access_token,值:通过 API Key Secret Key 获取的 access_token ,参考“ Access Token获取
Header :属性名:Content-Type,值:application/x-www-form-urlencoded
请求参数 :属性名:image,值:图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式
返回参数 :属性名:words_result,值:识别结果数组

关于具体的HTTP请求过程接下来会细聊。

2. 图像的Base64编码

Base64是网络上最常见的用于传输8Bit 字节码 的编码方式之一,它是包括小写字母 a-z 、大写字母 A-Z 、数字 0-9 、符号 + / 共64个字符的字符集,等号 = 用来作为后缀用途。任何符号都可以转换成这个字符集中的字符,该转换过程就叫做Base64编码。Base64编码具有不可读性,需要解码后才能阅读。

许多编程语言都提供了现成的Base64编码库函数,Matlab也不例外,大家不妨 help matlab.net.base64encode 查看细节。

下面提供三种Matlab中的实现方式:

  • Java类---org.apache.commons.codec.binary.Base64 和 matlab.net.base64encode
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'
    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
  • 使用Python base64 模块

Matlab中可以直接使用Python,那Python中提供的模块 base64 就可以直接使用了,源代码如下:

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'
    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

我们可以对如下所示的同一张图片(500 x 500)进行base64编码,比较一下编码速度:

结果: '/9j/4AAQSkZ...AAAAAAD/9k='
  • Java类---org.apache.commons.codec.binary.Base64 :timer_clock: 0.000783 秒
  • matlab.net.base64encode :timer_clock: 0.017589 秒
  • Python base64 模块 :timer_clock: 0.000709 秒

可以发现使用Java类和Python base64 模块的方法,速度相当,而使用 matlab.net.base64encode 速度要慢20多倍,但编码一张大小为500 x 500的图像耗时0.02秒左右,其速度是非常之快了。

综合一下,我们推荐使用 org.apache.commons.codec.binary.Base64 类进行base64编码。

3. 屏幕截图

识别扫描版pdf文档、视频教程等中的文字时,我们需要对待识别文字所在区域截个图,保存为图像再进行后续识别操作。要实现上述过程,首先需要对屏幕进行截图,Matlab通过借助 java.awt.Robot 这个Java类来实现,截屏源代码如下所示:

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, [])';

4. 调用百度API识别文字

上述第1节中我们提到过, access_token 是调用 API 接口的必需参数。通过阅读技术文档得知,需要 API Key Secret Key 进行http请求就可以获得,核心代码如下:

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;

有了 access_token 我们就可以调用文字识别API进行文字识别了,这里再分享下识别文字的源代码:

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';
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;
    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
result = data.ocrResultChar;
end  % end function

简单测试下这个函数,输入下面所示的图片,我们进行图片(截图地址: ww2.mathworks.cn/produc )中的文字识别。

>> result =
  1×7 cell 数组
  列 14
    {'App设计工具帮助您…'}    {'开发专业背景。您只…'}    {'面(GUI)设计布局,…'}    {'编程。'}57
    {'要共享App,您可以使…'}    {' MATLAB Compile…'}    {'桌面App或 Web App'}
>> result{1}
ans =
    'App设计工具帮助您创建专业的App,同时并不要求软件'

识别结果中共有7个 cell ,代表识别了图片中的 7行 文字,即1个 cell 对应 1行 识别的文字,如 result{1} 的结果。

三、工具搭建

以基于 uifigure 的编程方式创建APP,我们推荐面向对象(OOP)方法编程,简单起见,这里主要封装一个类来实现所需的功能。当然更标准的做法是利用 MVC 等设计模式将界面和逻辑分离,能达到 对扩展开放,对修改封闭 的软件设计原则。

1. 功能需求

我们的功能需求非常简单,主要有以下两个功能:

  • 识别已经存在的图像中的文字
  • 识别扫描版pdf文档、视频教程等中的文字

实现第1个功能,我们只需要加载图像,然后调用识别函数进行识别,将识别结果显示到文本区域就可以了;而实现第2个功能,首先需要屏幕截图,选取待识别文字所在的区域,存储为图像,后续处理和实现第1个功能的一样。

根据上述描述,我们需要的控件有:加载图像按钮,截图按钮,图像显示器,识别结果显示文本域。另外,需要一个清理按钮,用于清除显示的图像和识别结果;还需要一个设置按钮,用于配置 API Key Secret Key

便于叙述,我们先展示下最终设计的结果,如下图所示:

在设置界面中,需要两个标签和两个文本框,两外需要两个按钮。据此,我们需要的控件都清楚了,接下来让我们一起来创建他们吧!

2. 实现细节

主要封装一个类来实现所需的功能,我们给这个类起个名: ReadWords ,这个类需要继承 matlab.apps.AppBase ,它的属性就是界面中的所有控件,那么这个类看上去应该是这样的:

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

下面说明下一些重要的属性

公有属性:

  • UIFig 必须是 matlab.ui.Figure 类的属性,通过 uifigure 构造,这是整个工具的主窗口
  • ContainerForMain 必须是 matlab.ui.container.GridLayout 类的属性,通过 uigridlayout 构造,这是主窗口的布局容器
  • ThisTB 必须是 matlab.ui.container.Toolbar 类的属性,通过 uitoolbar 构造,这是工具栏的容器,用于放置 SnippingToolBtn ImgLoadToolBtn SetupToolBtn CleanToolBtn 这4个工具按钮
  • ImgShow 必须是 matlab.ui.control.Image 类的属性,通过 uiimage 构造,用于显示加载或者截图后的图像
  • WordsShowTA 必须是 matlab.ui.control.TextArea 类的属性,通过 uitextarea 构造,用于显示文字识别结果
  • ContainerForSetup 设置界面中的网格容器
  • APIKeyText SecrectKeyText 主要用于输入 APIKey SecrectKey
  • ResetBtn SaveBtn 两个按钮分别用来实现重置和保存 APIKey SecrectKey

从属、隐藏属性:

  • APIKeyVal 用于接收 APIKeyText 中输入的 APIKey 的值
  • SecrectKeyVal 用于接收 SecrectKeyText 中输入的 SecrectKey 的值

受保护属性:

  • HasSetup 用于标识是否配置了 APIKey SecrectKey ,默认为 false

至此,我们设置好了所有的属性,然后进行构造方法、析构方法以及类方法的编写。

加上构造方法、析构方法以及从属属性 APIKeyVal SecrectKeyVal get 方法的代码后看上去是这样的:

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 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;
        % get.SecrectKeyVal
        function secrectKeyVal = get.SecrectKeyVal(app)
            secrectKeyVal = app.SecrectKeyText.Value;
    end  % end methods
end  % end classdef

析构方法(Destructor)的写法是固定的,构造方法中的 registerApp(app, app.UIFig) 也是固定的,另外的 buildApp() 方法就用来创建界面、注册各个控件。

我们将后续的方法都创建为私有方法,添加了 buildApp() 方法后的整个 ReadWords 类是下面这样的:

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 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;
        % get.SecrectKeyVal
        function secrectKeyVal = get.SecrectKeyVal(app)
            secrectKeyVal = app.SecrectKeyText.Value;
    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

需要注意的是,工具栏按钮和窗口的图标来源于: easyicon.cc/ 。一些常见的图标素材都可以从中免费下载。我们已经将图标下载完毕,需要的朋友可以点击下方链接来下载:

链接: pan.baidu.com/s/11kIvt4 提取码:5i3k

另外, app.runStartupFcn(@startupFcn); 语句调用的是父类 matlab.apps.AppBase 的方法,我们将各个控件的注册任务放在 startupFcn 这个方法中完成。这里不妨先注释掉这个语句,直接运行 ReadWords.m 便可以显示出我们刚才在 buildApp 方法中构造的界面了,动图演示如下:

可以看到,我们在点击工具栏各个按钮时,没有反应,这是因为到目前为止我们还没有给各个控件注册回调方法,那接下来将会在 startupFcn 这个方法中完成各个控件的注册任务,代码如下:

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 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;
        % get.SecrectKeyVal
        function secrectKeyVal = get.SecrectKeyVal(app)
            secrectKeyVal = app.SecrectKeyText.Value;
    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';
            % 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

由此,我们总共为6个按钮注册了6个回调方法,需要都进行实现,不然触发按钮时,该按钮不会做出响应。简单起见,这里我们以实现设置界面中的 SaveBtn 的回调方法 callbackSaveBtn 为例子来说明。

在没有设置 APIKey SecrectKey 前,触发 SnippingToolBtn 或者 ImgLoadToolBtn 会有先进行设置的提示:

callbackSaveBtn 方法实现的逻辑 :首先由 HasSetup 属性判断是否进行了 APIKey SecrectKey 的设置(初始默认是 false 没有设置),如果没有设置,会提示没有 APIKey SecrectKey ,则需要输入 APIKey SecrectKey 的值,然后点击保存按钮,那么后台会将获取到的值存储下来(.mat文件),更新 HasSetup 的值为 true ,后续我们就不必要再次输入了,要想更换值的话,点击重置按钮重新配置即可;如果进行了设置( HasSetup 属性为 true ),直接保存即可。

具体的代码如下:

% --------------------------------------
% % 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');
        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';
        uialert(app.UIFig, 'API Key or Secrect Key is empty!', 'Confirm', 'Icon', 'warning');
    end  % end if
end  % callbackSaveBtn

实现了保存按钮的功能后,就可以得到如下动图所示的效果了。

其他的回调函数源代码:

% 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;
        msg = {'API Key or Secrect Key is empty!'; 'Please set it up first!'};
        uialert(app.UIFig, msg, 'Confirm', 'Icon', 'warning');
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)
            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;
            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 clickedImgLoadToolBtn
% clickedSetupToolBtn
function clickedSetupToolBtn(app, ~, ~)
    if ~app.HasSetup
        app.ContainerForMain.Visible = 'off';
        app.ContainerForSetup.Visible = 'on';
        app.HasSetup = true;
        app.ContainerForMain.Visible = 'on';
        app.ContainerForSetup.Visible = 'off';
        app.HasSetup = false;
end  % end clickedSetupToolBtn
% clickedCleanToolBtn
function clickedCleanToolBtn(app, ~, ~)
    app.WordsShowTA.Value = '';
    app.ImgShow.ImageSource = '';
end  % end clickedCleanToolBtn
% callbackResetBtn
function callbackResetBtn(app, ~, ~)