[文章]基于AI通用文字识别能力,检测和识别文档翻拍、街景翻拍等图片中的文字

阅读量0
0
2
1. 介绍      
AI的通用文字识别可以对文档翻拍、街景翻拍等图片来源的文字检测和识别,可以集成在其他应用中,提供文字检测、识别的功能,并根据识别结果提供翻译、搜索等相关服务。该功能在一定程度上支持文本倾斜、拍摄角度倾斜、复杂光照条件以及复杂文本背景等场景的文字识别。通用文字识别详细介绍可参考AI-通用文字识别,分词详细介绍可参考AI-分词

说明
  • 分词文本限制在500字以内,编码格式必须为utf-8。
  • 分词目前只支持中文语境。
  • 支持处理的图片格式包括JPEG、JPG、PNG、GIF、BMP。
  • 目前支持的语言有:中文、英文、日语、韩语、俄语、意大利语、西班牙语、葡萄牙语、德语,以及法语(将来会增加更多语种),但不支持手写字体识别。
          本教程将通过以下内容为您展示如何实现基于AI的通用文字识别功能。

2. 搭建HarmonyOS环境
我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
  • 安装DevEco Studio,详情请参考下载和安装软件
  • 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
  • 开发者可以参考以下链接,完成设备调试的相关配置:

3. 代码结构解读      
基于AI的通用文字识别示例教程主要内容包括:图片列表展示、输入文本、分词、通用文字识别、结果展示等功能,可在9 完整示例中查看工程代码。DevEco Studio工程代码结构如下:

  • provider:PictureProvider图片适配类,获取所有图片,并将图片放到图片列表中。
  • slice:MainAbilitySlice本示例教程主页面。
  • util:工具类
    • LogUtil是日志打印类,对HiLog日志进行了封装。
    • WordRecognition是通用文字识别类,对图片中的文字进行识别并保存。
    • WordSegment是分词类,对输入文本进行分词。
  • MainAbility:主程序入口,DevEco Studio生成,未添加逻辑,不需变更。
  • MyApplication:DevEco Studio生成,不需变更。
  • resources:存放工程使用到的资源文件
    • resourcesbaseelement中存放DevEco studio自动生成的配置文件string.json,不用变更。
    • resourcesbasegraphic中存放页面样式文件:
      background_ability_page.xml用于设置界面背景颜色。
      background_ability_main.xml用于设置界面布局样式。
      button_element.xml用于设置按钮样式。
    • resourcesbaselayout中布局文件:
      ability_main.xml用于展示图片和输入文本。
      item_image_layout.xml用于设置图片滑动区域图片。
    • resourcesbasemedia下存放图片资源(本教程使用了8张.jpg图片,开发者自行准备;icon.png由DevEco Studio生成不需变更)。
  • config.json:配置文件。
   
4. 添加并展示图片      
  • 在"resourcesbasemedia"目录下添加8张jpg图片(分别命名为1-8.jpg),并加载图片id数组,代码如下:
    1. private int[] pictureLists = new int[]{ResourceTable.Media_1, ResourceTable.Media_2,
    2. ResourceTable.Media_3, ResourceTable.Media_4, ResourceTable.Media_5,
    3. ResourceTable.Media_6, ResourceTable.Media_7, ResourceTable.Media_8};
    复制代码

  • 获取图片id数组和MainAbilitySlice对象,代码如下:
    1. public PictureProvider(int[] pictureLists, Context context) {
    2.         this.pictureLists = pictureLists;
    3.         this.context = context;
    4. }
    复制代码

  • 展示图片到页面,代码如下:
    1. [url=home.php?mod=space&uid=2735960]@Override[/url]
    2. public Component getComponent(int var1, Component var2, ComponentContainer var3) {
    3.         ViewHolder viewHolder = null;// Component中展示图片类
    4.         Component component = var2;
    5.         if (component == null) {
    6.                 component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_image_layout,
    7.                                 null, false);
    8.                 viewHolder = new ViewHolder();
    9.                 Component componentImage = component.findComponentById(ResourceTable.Id_select_picture_list);
    10.                 if (componentImage instanceof Image) {
    11.                         viewHolder.image = (Image) componentImage;
    12.                 }
    13.                 component.setTag(viewHolder);//设置需要展示的图片
    14.         } else {
    15.                 if (component.getTag() instanceof ViewHolder) {
    16.                         viewHolder = (ViewHolder) component.getTag();
    17.                 }
    18.         }
    19.         if (viewHolder != null) {
    20.                 viewHolder.image.setPixelMap(pictureLists[var1]);
    21.         }
    22.         return component;
    23. }
    复制代码

  • 定义ViewHolder类,用于列表中展示图片,代码如下:
    1. private static class ViewHolder {
    2.         Image image;
    3. }
    复制代码


5. 识别图片中的文字      
  • 调用文字识别方法对图片文字进行识别,代码如下:
    1. wordRecognition(slice, pictureLists[index], handle); //index为待识别图片下标
    2. public void wordRecognition(Context context, int resId, MainAbilitySlice.MyEventHandle myEventHandle) {
    3.         mediaId = resId;
    4.         // 实例化ITextDetector接口
    5.         iTextDetector = VisionManager.getTextDetector(context);

    6.         // 实例化VisionImage对象image,并传入待检测图片pixelMap
    7.         pixelMap = getPixelMap(resId);
    8.         VisionImage image = VisionImage.fromPixelMap(pixelMap);

    9.         // 定义VisionCallback<Text>回调,异步模式下用到
    10.         VisionCallback<Text> visionCallback = getVisionCallback();

    11.         // 定义ConnectionCallback回调,实现连接能力引擎成功与否后的操作
    12.         ConnectionCallback connectionCallback = getConnectionCallback(image, visionCallback);

    13.         // 建立与能力引擎的连接
    14.         VisionManager.init(context, connectionCallback);
    15. }
    复制代码

  • 异步模式下回调方法,将图片中文字识别结果通过sendResult()方法发送到主线程,代码如下:
    1. private VisionCallback getVisionCallback() {
    2. return new VisionCallback<Text>() {
    3.      @Override
    4.      public void onResult(Text text) {
    5.          sendResult(text.getValue());
    6.      }
    7. };
    8. }
    复制代码

  • 连接引擎成功后进行文字识别,并将识别结果通过sendResult()方法发送到主线程,代码如下:
    1. private ConnectionCallback getConnectionCallback(VisionImage image, VisionCallback<Text> visionCallback) {
    2. return new ConnectionCallback() {
    3.      @Override
    4.      public void onServiceConnect() {
    5.          // 实例化Text对象text
    6.          Text text = new Text();
    7.          // 通过TextConfiguration配置textDetector()方法的运行参数
    8.          TextConfiguration.Builder builder = new TextConfiguration.Builder();
    9.          builder.setProcessMode(VisionConfiguration.MODE_IN);
    10.          builder.setDetectType(TextDetectType.TYPE_TEXT_DETECT_FOCUS_SHOOT); // 此处变量名将会被调整
    11.          builder.setLanguage(TextConfiguration.AUTO);
    12.          TextConfiguration config = builder.build();
    13.          iTextDetector.setVisionConfiguration(config);
    14.          // 调用ITextDetector的detect()方法
    15.          if (!IS_ASYNC) {
    16.              int result2 = iTextDetector.detect(image, text, null); // 同步
    17.              sendResult(text.getValue());
    18.          } else {
    19.              int result2 = iTextDetector.detect(image, null, visionCallback); // 异步
    20.          }
    21.      }

    22.      @Override
    23.      public void onServiceDisconnect() {
    24.          // 释放 成功:同步结果码为0,异步结果码为700
    25.          if ((!IS_ASYNC && (result == 0)) || (IS_ASYNC && (result == IS_ASYNC_CODE))) {
    26.                iTextDetector.release();
    27.          }
    28.          if (pixelMap != null) {
    29.              pixelMap.release();
    30.              pixelMap = null;
    31.          }
    32.          VisionManager.destroy();
    33.      }
    34. };
    35. }
    复制代码

    说明
    1.引擎使用TextDetectType.TYPE_TEXT_DETECT_FOCUS_SHOOT(聚焦拍照OCR)。
    2.同步模式调用成功时,该函数返回结果码0。异步模式调用请求发送成功时,该函数返回结果码700。
    3.同步模式下visionCallback为null,结果码由方法返回,检测识别结果由text中返回。
    4.异步模式下visionCallback不为null,函数返回时text中的值无效(即:text参数为null),实际识别结果由回调函数visionCallback返回。
    5.IS_ASYNC为boolean变量,同步模式时该值为false,异步模式时该值为true。
  • 将文字识别结果发送到主线程(MainAbilitySlice类中接收),代码如下:
    1. public void sendResult(String value) {
    2.     if (iTextDetector != null) {
    3.         iTextDetector.release();
    4.     }
    5.     if (pixelMap != null) {
    6.         pixelMap.release();
    7.         pixelMap = null;
    8.         VisionManager.destroy();
    9.     }
    10.     if (value != null) {
    11.         maps.put(mediaId, value);
    12.     }
    13.     if ((maps != null) && (maps.size() == pictureLists.length)) {
    14.         InnerEvent event = InnerEvent.get(1, 0, maps);
    15.         handle.sendEvent(event);
    16.     } else {
    17.         wordRecognition(slice, pictureLists[index], handle);
    18.         index++;
    19.     }
    20. }
    复制代码


6. 提取用户输入的关键词      
  • 获取MainAbilitySlice传递的环境参数并进行分词操作,同步方式调用sendResult()方法将分词结果发送到主线程,代码如下:
    1. public void wordSegment(Context context, String requestData, MainAbilitySlice.MyEventHandle myEventHandle) {
    2.         slice = context; // MainAbilitySlice.this
    3.         handle = myEventHandle; // MyEventHandle对象

    4.         // 使用NluClient静态类进行初始化,通过异步方式获取服务的连接。
    5.         NluClient.getInstance().init(context, new OnResultListener<Integer>() {
    6.                 @Override
    7.                 public void onResult(Integer resultCode) {
    8.                         if (!IS_ASYNC) {
    9.                                 // 分词同步方法
    10.                                 ResponseResult responseResult = NluClient.getInstance().getWordSegment(requestData,
    11.                                                 NluRequestType.REQUEST_TYPE_LOCAL);
    12.                                 sendResult(responseResult.getResponseResult());
    13.                                 release();
    14.                         } else {
    15.                                 // 分词异步方法
    16.                                 wordSegmentAsync(requestData);
    17.                         }
    18.                 }
    19.         }, true);
    20. }
    复制代码

    说明
    1.IS_ASYNC为boolean变量,同步模式时该值为false,异步模式时该值为true。
    2.responseResult对象中code属性为0表示分词成功。
  • 异步请求回调此方法,通过sendResult()方法将分词结果发送到主线程,代码如下:
    1. private void wordSegmentAsync(String requestData) {
    2.         ResponseResult responseResult = NluClient.getInstance().getWordSegment(requestData,
    3.                         NluRequestType.REQUEST_TYPE_LOCAL, new OnResultListener<ResponseResult>() {
    4.                                 @Override
    5.                                 public void onResult(ResponseResult asyncResult) {
    6.                                         sendResult(asyncResult.getResponseResult());
    7.                                         release();
    8.                                 }
    9.                         });
    10. }
    复制代码

  • 将分词结果发送到主线程中(MainAbilitySlice类中接收),代码如下:
    1. private void sendResult(String result) {
    2.         List lists = null;// 分词识别结果
    3.         // 将result中分词结果转换成list
    4.         if (result.contains(""message":"success"")) {
    5.                 String words = result.substring(result.indexOf(WORDS) + STEP,
    6.                                 result.lastIndexOf("]")).replaceAll(""", "");
    7.                 if ((words == null) || ("".equals(words))) {
    8.                         lists = new ArrayList(1);// 未识别到分词结果,返回"no keywords"
    9.                         lists.add("no keywords");
    10.                 } else {
    11.                         lists = Arrays.asList(words.split(","));
    12.                 }
    13.         }

    14.         InnerEvent event = InnerEvent.get(TWO, ZERO, lists);
    15.         handle.sendEvent(event);
    16. }
    复制代码


7. 根据关键词匹配图片      
  • 根据关键词匹配待识别图片,代码如下:
    1. private void matchImage(List<String> list) {
    2.         Set<Integer> matchSets = new HashSet<>();
    3.         for (String str: list) { // 遍历分词结果
    4.                 // imageInfos待识别图片通用文字识别结果
    5.                 for (Integer key : imageInfos.keySet()) {
    6.                         if (imageInfos.get(key).indexOf(str) != NEG_ONE) {
    7.                                 matchSets.add(key);
    8.                         }
    9.                 }
    10.         }
    11.         // 获得匹配的图片
    12.         matchPictures = new int[matchSets.size()];
    13.         int i = 0;
    14.         for (int match: matchSets) {
    15.                 matchPictures[i] = match;
    16.                 i++;
    17.         }
    18.         // 展示图片
    19.         setSelectPicture(matchPictures, LIST_CONTAINER_ID_MATCH);
    20. }
    复制代码

  • 展示结果图片到页面,代码如下:
    1. private void setSelectPicture(int[] pictures, int id) {
    2.         // 获取图片
    3.         PictureProvider newsTypeAdapter = new PictureProvider(pictures, this);

    4.         Component componentById = findComponentById(id);
    5.         if (componentById instanceof ListContainer) {
    6.                 ListContainer listContainer = (ListContainer) componentById;
    7.                 listContainer.setItemProvider(newsTypeAdapter);
    8.         }
    9. }
    复制代码

最终实现效果
在"请输入关键词"下面的输入框中输入需要分词的关键词,点击【开始通用文字识别】按钮进行关键词搜索图片,您将会在"搜索结果"下方看到包含关键词的图片。
  • 垃圾分类人人做 做好分类为人人
  • 可回收物 其他垃圾

   
通过本教程的学习,你已学会如何使用AI能力中的通用文字识别和分词。

完整示例代码(2).pdf
(122.97 KB, 下载次数: 0)




回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友