在HarmonyOS中用AI识别图中文字

系统 OpenHarmony
文章由鸿蒙社区产出,想要了解更多内容请前往:51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com

[[392886]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

1. 介绍

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

🕮 说明

● 分词文本限制在500字以内,编码格式必须为utf-8。

● 分词目前只支持中文语境。

● 支持处理的图片格式包括JPEG、JPG、PNG、GIF、BMP。

● 目前支持的语言有:中文、英文、日语、韩语、俄语、意大利语、西班牙语、葡萄牙语、德语,以及法语(将来会增加更多语种),但不支持手写字体识别。

本教程将通过以下内容为您展示如何实现基于AI的通用文字识别功能。

2. 代码结构解读

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

● provider:PictureProvider图片适配类,获取所有图片,并将图片放到图片列表中。

● slice:MainAbilitySlice本示例教程主页面。

● util:工具类

○ LogUtil是日志打印类,对HiLog日志进行了封装。

○ WordRecognition是通用文字识别类,对图片中的文字进行识别并保存。

○ WordSegment是分词类,对输入文本进行分词。

● MainAbility:主程序入口,DevEco Studio生成,未添加逻辑,不需变更。

● MyApplication:DevEco Studio生成,不需变更。

● resources:存放工程使用到的资源文件

○ resources\base\element中存放DevEco studio自动生成的配置文件string.json,不用变更。

○ resources\base\graphic中存放页面样式文件:

◼ ️background_ability_page.xml用于设置界面背景颜色。

◼ ️background_ability_main.xml用于设置界面布局样式。

◼ ️button_element.xml用于设置按钮样式。

○ resources\base\layout中布局文件:

◼ ️ability_main.xml用于展示图片和输入文本。

◼ ️item_image_layout.xml用于设置图片滑动区域图片。

resources\base\media下存放图片资源(本教程使用了8张.jpg图片,开发者自行准备;icon.png由DevEco Studio生成不需变更)。

● config.json:配置文件。

3. 添加并展示图片

(1)在"resources\base\media"目录下添加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}; 
  4. 1. 

(2)获取图片id数组和MainAbilitySlice对象,代码如下:

  1. public PictureProvider(int[] pictureLists, Context context) {  
  2.     this.pictureLists = pictureLists;  
  3.     this.context = context;  

(3)展示图片到页面,代码如下:

  1. @Override  
  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.                 nullfalse);  
  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;  

(4)定义ViewHolder类,用于列表中展示图片,代码如下:

  1. private static class ViewHolder {  
  2.     Image image;  

4. 识别图片中的文字

(1)调用文字识别方法对图片文字进行识别,代码如下:

  1. wordRecognition(slice, pictureLists[index], handle); //index为待识别图片下标  
  2. public void wordRecognition(Context context, int resId, MainAbilitySlice.MyEventHandle myEventHandle) {  
  3.     mediaId = resId;  
  4.     // 实例化ITextDetector接口  
  5.     textDetector = VisionManager.getTextDetector(context);  
  6.   
  7.     // 实例化VisionImage对象image,并传入待检测图片pixelMap  
  8.     pixelMap = getPixelMap(resId);  
  9.     VisionImage image = VisionImage.fromPixelMap(pixelMap);  
  10.   
  11.     // 定义VisionCallback<Text>回调,异步模式下用到  
  12.     VisionCallback<Text> visionCallback = getVisionCallback();  
  13.   
  14.     // 定义ConnectionCallback回调,实现连接能力引擎成功与否后的操作  
  15.     ConnectionCallback connectionCallback = getConnectionCallback(image, visionCallback);  
  16.   
  17.     // 建立与能力引擎的连接  
  18.     VisionManager.init(context, connectionCallback);  

(2)异步模式下回调方法,将图片中文字识别结果通过sendResult()方法发送到主线程,代码如下:

  1. private VisionCallback getVisionCallback() {  
  2.  return new VisionCallback<Text>() {  
  3.      @Override  
  4.      public void onResult(Text text) {  
  5.          sendResult(text.getValue());  
  6.      }  
  7.  };  

(3)连接引擎成功后进行文字识别,并将识别结果通过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.          textDetector.setVisionConfiguration(config);  
  14.          // 调用ITextDetector的detect()方法  
  15.          if (!IS_ASYNC) {  
  16.              int result2 = textDetector.detect(image, text, null); // 同步  
  17.              sendResult(text.getValue());  
  18.          } else {  
  19.              int result2 = textDetector.detect(image, null, visionCallback); // 异步  
  20.          }  
  21.      }  
  22.   
  23.      @Override  
  24.      public void onServiceDisconnect() {  
  25.          // 释放 成功:同步结果码为0,异步结果码为700  
  26.          if ((!IS_ASYNC && (result == 0)) || (IS_ASYNC && (result == IS_ASYNC_CODE))) {  
  27.            textDetector.release();  
  28.          }  
  29.          if (pixelMap != null) {  
  30.              pixelMap.release();  
  31.              pixelMap = null;  
  32.          }  
  33.          VisionManager.destroy();  
  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 (textDetector != null) {  
  3.      textDetector.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.  }  

5. 提取用户输入的关键词

(1)获取MainAbilitySlice传递的环境参数并进行分词操作,同步方式调用sendResult()方法将分词结果发送到主线程,代码如下:

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

🕮 说明

(1)IS_ASYNC为boolean变量,同步模式时该值为false,异步模式时该值为true。

(2)responseResult对象中code属性为0表示分词成功。

(3)异步请求回调此方法,通过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. 1. 

(4)将分词结果发送到主线程中(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.   
  15.     InnerEvent event = InnerEvent.get(TWO, ZERO, lists);  
  16.     handle.sendEvent(event);  

6. 根据关键词匹配图片

(1)根据关键词匹配待识别图片,代码如下:

  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);  

(2)展示结果图片到页面,代码如下:

  1. private void setSelectPicture(int[] pictures, int id) {  
  2.     // 获取图片  
  3.     PictureProvider newsTypeAdapter = new PictureProvider(pictures, this);  
  4.   
  5.     Component componentById = findComponentById(id);  
  6.     if (componentById instanceof ListContainer) {  
  7.         ListContainer listContainer = (ListContainer) componentById;  
  8.         listContainer.setItemProvider(newsTypeAdapter);  
  9.     }  

最终实现效果

在"请输入关键词"下面的输入框中输入需要分词的关键词,点击【开始通用文字识别】按钮进行关键词搜索图片,您将会在"搜索结果"下方看到包含关键词的图片。

● 垃圾分类人人做 做好分类为人人

● 可回收物 其他垃圾

7. 完整示例代码

编写布局与样式

(1)base/graphic/background_ability_main.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <shape xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  3.        ohos:shape="rectangle">  
  4.     <solid  
  5.         ohos:color="#FFFFFF"/>  
  6. </shape> 

(2)base/graphic/background_ability_page.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2.  <shape xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  3.         ohos:shape="rectangle">  
  4.      <solid  
  5.          ohos:color="#FFFAF0"/>  
  6.  </shape> 

(3)base/graphic/button_element.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2.  <shape  
  3.      xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  4.      ohos:shape="rectangle">  
  5.      <corners  
  6.          ohos:radius="100"/>  
  7.      <solid  
  8.          ohos:color="#FF007DFE"/>  
  9.  </shape> 

(4)base/layout/ability_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <DirectionalLayout  
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  4.     ohos:height="match_parent"  
  5.     ohos:width="match_parent"  
  6.     ohos:orientation="vertical"  
  7.     ohos:background_element="$graphic:background_ability_page"  
  8.     >  
  9.   
  10.     <Text  
  11.         ohos:id="$+id:text_helloworld"  
  12.         ohos:height="match_content"  
  13.         ohos:width="match_content"  
  14.         ohos:background_element="$graphic:background_ability_main"  
  15.         ohos:layout_alignment="horizontal_center"  
  16.         ohos:text="关键词搜索图片"  
  17.         ohos:text_size="30fp"  
  18.         ohos:top_margin="5vp"  
  19.         />  
  20.   
  21.     <Text  
  22.         ohos:id="$+id:picture_list"  
  23.         ohos:height="match_content"  
  24.         ohos:width="match_content"  
  25.         ohos:background_element="$graphic:background_ability_main"  
  26.         ohos:layout_alignment="horizontal_center"  
  27.         ohos:text="图片列表"  
  28.         ohos:text_size="20fp"  
  29.         ohos:top_margin="15vp"  
  30.         />  
  31.   
  32.     <ListContainer  
  33.         ohos:id="$+id:picture_list_show"  
  34.         ohos:height="200vp"  
  35.         ohos:width="match_parent"  
  36.         ohos:orientation="horizontal"  
  37.         ohos:left_margin="5vp"  
  38.         ohos:right_margin="5vp"  
  39.         />  
  40.   
  41.     <Text  
  42.         ohos:id="$+id:word_seg_title"  
  43.         ohos:height="match_content"  
  44.         ohos:width="match_content"  
  45.         ohos:background_element="$graphic:background_ability_main"  
  46.         ohos:left_margin="5vp"  
  47.         ohos:text="请输入关键词:"  
  48.         ohos:text_size="25fp"  
  49.         ohos:top_margin="10vp"  
  50.         />  
  51.   
  52.     <TextField  
  53.         ohos:id="$+id:word_seg_text"  
  54.         ohos:height="match_content"  
  55.         ohos:width="match_parent"  
  56.         ohos:background_element="$graphic:background_ability_main"  
  57.         ohos:hint="Enter a statement."  
  58.         ohos:left_padding="5vp"  
  59.         ohos:right_padding="5vp"  
  60.         ohos:text_alignment="vertical_center"  
  61.         ohos:text_size="20fp"  
  62.         ohos:top_margin="5vp"/>  
  63.   
  64.     <Button  
  65.         ohos:id="$+id:button_search"  
  66.         ohos:width="match_content"  
  67.         ohos:height="match_content"  
  68.         ohos:text_size="20fp"  
  69.         ohos:text="开始通用文字识别"  
  70.         ohos:layout_alignment="horizontal_center"  
  71.         ohos:top_margin="10vp"  
  72.         ohos:top_padding="1vp"  
  73.         ohos:bottom_padding="1vp"  
  74.         ohos:right_padding="20vp"  
  75.         ohos:left_padding="20vp"  
  76.         ohos:text_color="white"  
  77.         ohos:background_element="$graphic:button_element"  
  78.         ohos:center_in_parent="true"  
  79.         ohos:align_parent_bottom="true"  
  80.         ohos:bottom_margin="5vp"/>  
  81.   
  82.     <Text  
  83.         ohos:id="$+id:picture_list_result"  
  84.         ohos:height="match_content"  
  85.         ohos:width="match_content"  
  86.         ohos:background_element="$graphic:background_ability_main"  
  87.         ohos:layout_alignment="horizontal_center"  
  88.         ohos:text="搜索结果"  
  89.         ohos:text_size="20fp"  
  90.         ohos:top_margin="5vp"  
  91.         />  
  92.   
  93.     <ListContainer  
  94.         ohos:id="$+id:picture_list_match"  
  95.         ohos:height="200vp"  
  96.         ohos:width="match_parent"  
  97.         ohos:orientation="horizontal"  
  98.         ohos:left_margin="5vp"  
  99.         ohos:right_margin="5vp"  
  100.         />  
  101. </DirectionalLayout> 

(5)base/layout/item_image_layout.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  3.                    ohos:height="200vp"  
  4.                    ohos:width="205vp">  
  5.   
  6.     <Image  
  7.         ohos:id="$+id:select_picture_list"  
  8.         ohos:height="200vp"  
  9.         ohos:width="200vp"  
  10.         ohos:layout_alignment="horizontal_center"  
  11.         ohos:top_margin="1vp"  
  12.         ohos:scale_mode="stretch"  
  13.         />  
  14.   
  15. </DirectionalLayout> 

功能逻辑代码

(1)com/huawei/searchimagebykeywords/provider/PictureProvider

  1. import com.huawei.searchimagebykeywords.ResourceTable;  
  2.   
  3. import ohos.agp.components.BaseItemProvider;  
  4. import ohos.agp.components.Component;  
  5. import ohos.agp.components.ComponentContainer;  
  6. import ohos.agp.components.Image;  
  7. import ohos.agp.components.LayoutScatter;  
  8. import ohos.app.Context;  
  9.   
  10. import java.util.Optional;  
  11.   
  12. public class PictureProvider extends BaseItemProvider {  
  13.     private int[] pictureLists;  
  14.     private Context context;  
  15.   
  16.     /**  
  17.      *  picture provider  
  18.      *  
  19.      * @param pictureLists pictureLists  
  20.      * @param context context  
  21.      */  
  22.     public PictureProvider(int[] pictureLists, Context context) {  
  23.         this.pictureLists = pictureLists;  
  24.         this.context = context;  
  25.     }  
  26.   
  27.     @Override  
  28.     public int getCount() {  
  29.         return pictureLists == null ? 0 : pictureLists.length;  
  30.     }  
  31.   
  32.     @Override  
  33.     public Object getItem(int position) {  
  34.         return Optional.of(this.pictureLists[position]);  
  35.     }  
  36.   
  37.     @Override  
  38.     public long getItemId(int position) {  
  39.         return position;  
  40.     }  
  41.   
  42.     @Override  
  43.     public Component getComponent(int var1, Component var2, ComponentContainer var3) {  
  44.         ViewHolder viewHolder = null;  
  45.         Component component = var2;  
  46.         if (component == null) {  
  47.             component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_image_layout,  
  48.                     nullfalse);  
  49.             viewHolder = new ViewHolder();  
  50.             Component componentImage = component.findComponentById(ResourceTable.Id_select_picture_list);  
  51.             if (componentImage instanceof Image) {  
  52.                 viewHolder.image = (Image) componentImage;  
  53.             }  
  54.             component.setTag(viewHolder);  
  55.         } else {  
  56.             if (component.getTag() instanceof ViewHolder) {  
  57.                 viewHolder = (ViewHolder) component.getTag();  
  58.             }  
  59.         }  
  60.         if (viewHolder != null) {  
  61.             viewHolder.image.setPixelMap(pictureLists[var1]);  
  62.         }  
  63.         return component;  
  64.     }  
  65.   
  66.     private static class ViewHolder {  
  67.         Image image;  
  68.     }  

(2)com/huawei/searchimagebykeywords/slice/MainAbilitySlice

  1. import com.huawei.searchimagebykeywords.ResourceTable;  
  2. import com.huawei.searchimagebykeywords.provider.PictureProvider;  
  3. import com.huawei.searchimagebykeywords.util.WordRecognition;  
  4. import com.huawei.searchimagebykeywords.util.WordSegment;  
  5.   
  6. import ohos.aafwk.ability.AbilitySlice;  
  7. import ohos.aafwk.content.Intent;  
  8. import ohos.agp.components.Button;  
  9. import ohos.agp.components.Component;  
  10. import ohos.agp.components.ListContainer;  
  11. import ohos.agp.components.TextField;  
  12. import ohos.app.Context;  
  13. import ohos.eventhandler.EventHandler;  
  14. import ohos.eventhandler.EventRunner;  
  15. import ohos.eventhandler.InnerEvent;  
  16.   
  17. import java.util.HashSet;  
  18. import java.util.List;  
  19. import java.util.Map;  
  20. import java.util.Set;  
  21.   
  22. public class MainAbilitySlice extends AbilitySlice {  
  23.     private static final int LIST_CONTAINER_ID_SHOW = ResourceTable.Id_picture_list_show;  
  24.     private static final int LIST_CONTAINER_ID_MATCH = ResourceTable.Id_picture_list_match;  
  25.     private static final int NEG_ONE = -1;  
  26.     private static final int ZERO = 0;  
  27.     private static final int ONE = 1;  
  28.     private static final int TWO = 2;  
  29.     private Context slice;  
  30.     private EventRunner runner;  
  31.     private MyEventHandle myEventHandle;  
  32.     private int[] pictureLists = new int[]{ResourceTable.Media_1, ResourceTable.Media_2,  
  33.         ResourceTable.Media_3, ResourceTable.Media_4, ResourceTable.Media_5,  
  34.         ResourceTable.Media_6, ResourceTable.Media_7, ResourceTable.Media_8};  
  35.     private Component selectComponent;  
  36.     private int selectPosition;  
  37.     private Button button;  
  38.     private TextField textField;  
  39.     private Map<Integer, String> imageInfos;  
  40.     private int[] matchPictures;  
  41.   
  42.     @Override  
  43.     public void onStart(Intent intent) {  
  44.         super.onStart(intent);  
  45.         super.setUIContent(ResourceTable.Layout_ability_main);  
  46.   
  47.         slice = MainAbilitySlice.this;  
  48.   
  49.         // 展示图片列表  
  50.         setSelectPicture(pictureLists, LIST_CONTAINER_ID_SHOW);  
  51.   
  52.         // 所有图片通用文字识别  
  53.         wordRecognition();  
  54.   
  55.         // 设置需要分词的语句  
  56.         Component componentText = findComponentById(ResourceTable.Id_word_seg_text);  
  57.         if (componentText instanceof TextField) {  
  58.             textField = (TextField) componentText;  
  59.         }  
  60.   
  61.         // 点击按钮进行文字识别  
  62.         Component componentSearch = findComponentById(ResourceTable.Id_button_search);  
  63.         if (componentSearch instanceof Button) {  
  64.             button = (Button) componentSearch;  
  65.             button.setClickedListener(listener -> wordSegment());  
  66.         }  
  67.     }  
  68.   
  69.     @Override  
  70.     public void onActive() {  
  71.         super.onActive();  
  72.     }  
  73.   
  74.     @Override  
  75.     public void onForeground(Intent intent) {  
  76.         super.onForeground(intent);  
  77.     }  
  78.   
  79.     // 设置图片选择区域  
  80.     private void setSelectPicture(int[] pictures, int id) {  
  81.         // 获取图片  
  82.         PictureProvider newsTypeAdapter = new PictureProvider(pictures, this);  
  83.   
  84.         Component componentById = findComponentById(id);  
  85.         if (componentById instanceof ListContainer) {  
  86.             ListContainer listContainer = (ListContainer) componentById;  
  87.             listContainer.setItemProvider(newsTypeAdapter);  
  88.         }  
  89.     }  
  90.   
  91.     // 通用文字识别  
  92.     private void wordRecognition() {  
  93.         initHandler();  
  94.         WordRecognition wordRecognition = new WordRecognition();  
  95.         wordRecognition.setParams(slice, pictureLists, myEventHandle);  
  96.         wordRecognition.sendResult(null);  
  97.     }  
  98.   
  99.     // 分词  
  100.     private void wordSegment() {  
  101.         // 组装关键词,作为分词对象  
  102.         String requestData = "{\"text\":" + textField.getText() + ",\"type\":0}";  
  103.         initHandler();  
  104.         new WordSegment().wordSegment(slice, requestData, myEventHandle);  
  105.     }  
  106.   
  107.     // 匹配图片  
  108.     private void matchImage(List<String> list) {  
  109.         Set<Integer> matchSets = new HashSet<>();  
  110.         for (String str: list) {  
  111.             for (Integer key : imageInfos.keySet()) {  
  112.                 if (imageInfos.get(key).indexOf(str) != NEG_ONE) {  
  113.                     matchSets.add(key);  
  114.                 }  
  115.             }  
  116.         }  
  117.         // 获得匹配的图片  
  118.         matchPictures = new int[matchSets.size()];  
  119.         int i = 0;  
  120.         for (int match: matchSets) {  
  121.             matchPictures[i] = match;  
  122.             i++;  
  123.         }  
  124.         // 展示图片  
  125.         setSelectPicture(matchPictures, LIST_CONTAINER_ID_MATCH);  
  126.     }  
  127.   
  128.     private void initHandler() {  
  129.         runner = EventRunner.getMainEventRunner();  
  130.         if (runner == null) {  
  131.             return;  
  132.         }  
  133.         myEventHandle = new MyEventHandle(runner);  
  134.     }  
  135.   
  136.     public class MyEventHandle extends EventHandler {  
  137.         MyEventHandle(EventRunner runner) throws IllegalArgumentException {  
  138.             super(runner);  
  139.         }  
  140.   
  141.         @Override  
  142.         protected void processEvent(InnerEvent event) {  
  143.             super.processEvent(event);  
  144.             int eventId = event.eventId;  
  145.             if (eventId == ONE) {  
  146.                 // 通用文字识别  
  147.                 if (event.object instanceof Map) {  
  148.                     imageInfos = (Map) event.object;  
  149.                 }  
  150.             }  
  151.             if (eventId == TWO) {  
  152.                 // 分词  
  153.                 if (event.object instanceof List) {  
  154.                     List<String> lists = (List) event.object;  
  155.                     if ((lists.size() > ZERO) && (!"no keywords".equals(lists.get(ZERO)))) {  
  156.                         // 根据输入关键词 匹配图片  
  157.                         matchImage(lists);  
  158.                     }  
  159.                 }  
  160.             }  
  161.         }  
  162.     }  

(3)com/huawei/searchimagebykeywords/util/LogUtil

  1. import ohos.hiviewdfx.HiLog;  
  2. import ohos.hiviewdfx.HiLogLabel;  
  3.   
  4. public class LogUtil {  
  5.     private static final String TAG_LOG = "LogUtil";  
  6.   
  7.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(0, 0, LogUtil.TAG_LOG);  
  8.   
  9.     private static final String LOG_FORMAT = "%{public}s: %{public}s";  
  10.   
  11.     private LogUtil() {  
  12.     }  
  13.   
  14.     public static void info(String tag, String msg) {  
  15.         HiLog.info(LABEL_LOG, LOG_FORMAT, tag, msg);  
  16.     }  
  17.   
  18.     public static void error(String tag, String msg) {  
  19.         HiLog.info(LABEL_LOG, LOG_FORMAT, tag, msg);  
  20.     }  

(4)com/huawei/searchimagebykeywords/util/WordRecognition

  1. import com.huawei.searchimagebykeywords.slice.MainAbilitySlice;  
  2.   
  3. import ohos.ai.cv.common.ConnectionCallback;  
  4. import ohos.ai.cv.common.VisionCallback;  
  5. import ohos.ai.cv.common.VisionConfiguration;  
  6. import ohos.ai.cv.common.VisionImage;  
  7. import ohos.ai.cv.common.VisionManager;  
  8. import ohos.ai.cv.text.ITextDetector;  
  9. import ohos.ai.cv.text.Text;  
  10. import ohos.ai.cv.text.TextConfiguration;  
  11. import ohos.ai.cv.text.TextDetectType;  
  12. import ohos.app.Context;  
  13. import ohos.eventhandler.InnerEvent;  
  14. import ohos.global.resource.NotExistException;  
  15. import ohos.global.resource.Resource;  
  16. import ohos.global.resource.ResourceManager;  
  17. import ohos.media.image.ImageSource;  
  18. import ohos.media.image.PixelMap;  
  19. import ohos.media.image.common.PixelFormat;  
  20. import ohos.media.image.common.Rect;  
  21. import ohos.media.image.common.Size;  
  22.   
  23. import java.io.ByteArrayOutputStream;  
  24. import java.io.IOException;  
  25. import java.util.HashMap;  
  26. import java.util.Map;  
  27.   
  28. public class WordRecognition {  
  29.     private static final boolean IS_ASYNC = false;  
  30.     private static final int IS_ASYNC_CODE = 700;  
  31.     private Context slice;  
  32.     private ITextDetector textDetector;  
  33.     private PixelMap pixelMap;  
  34.     private MainAbilitySlice.MyEventHandle handle;  
  35.     private int[] pictureLists;  
  36.     private int mediaId;  
  37.     private Map maps = new HashMap<>();  
  38.     private int index;  
  39.     private int result;  
  40.   
  41.     public void setParams(Context context, int[] pictureIds, MainAbilitySlice.MyEventHandle myEventHandle) {  
  42.         slice = context;  
  43.         pictureLists = pictureIds;  
  44.         handle = myEventHandle;  
  45.     }  
  46.   
  47.     public void wordRecognition(Context context, int resId, MainAbilitySlice.MyEventHandle myEventHandle) {  
  48.         mediaId = resId;  
  49.         // 实例化ITextDetector接口  
  50.         textDetector = VisionManager.getTextDetector(context);  
  51.   
  52.         // 实例化VisionImage对象image,并传入待检测图片pixelMap  
  53.         pixelMap = getPixelMap(resId);  
  54.         VisionImage image = VisionImage.fromPixelMap(pixelMap);  
  55.   
  56.         // 定义VisionCallback<Text>回调,异步模式下用到  
  57.         VisionCallback<Text> visionCallback = getVisionCallback();  
  58.   
  59.         // 定义ConnectionCallback回调,实现连接能力引擎成功与否后的操作  
  60.         ConnectionCallback connectionCallback = getConnectionCallback(image, visionCallback);  
  61.   
  62.         // 建立与能力引擎的连接  
  63.         VisionManager.init(context, connectionCallback);  
  64.     }  
  65.   
  66.     private VisionCallback getVisionCallback() {  
  67.         return new VisionCallback<Text>() {  
  68.             @Override  
  69.             public void onResult(Text text) {  
  70.                 sendResult(text.getValue());  
  71.             }  
  72.   
  73.             @Override  
  74.             public void onError(int i) {  
  75.             }  
  76.   
  77.             @Override  
  78.             public void onProcessing(float v) {  
  79.             }  
  80.         };  
  81.     }  
  82.   
  83.     private ConnectionCallback getConnectionCallback(VisionImage image, VisionCallback<Text> visionCallback) {  
  84.         return new ConnectionCallback() {  
  85.             @Override  
  86.             public void onServiceConnect() {  
  87.                 // 实例化Text对象text  
  88.                 Text text = new Text();  
  89.   
  90.                 // 通过TextConfiguration配置textDetector()方法的运行参数  
  91.                 TextConfiguration.Builder builder = new TextConfiguration.Builder();  
  92.                 builder.setProcessMode(VisionConfiguration.MODE_IN);  
  93.                 builder.setDetectType(TextDetectType.TYPE_TEXT_DETECT_FOCUS_SHOOT);  
  94.                 builder.setLanguage(TextConfiguration.AUTO);  
  95.                 TextConfiguration config = builder.build();  
  96.                 textDetector.setVisionConfiguration(config);  
  97.                 // 调用ITextDetector的detect()方法  
  98.                 if (!IS_ASYNC) {  
  99.                     int result2 = textDetector.detect(image, text, null); // 同步  
  100.                     sendResult(text.getValue());  
  101.                 } else {  
  102.                     int result2 = textDetector.detect(image, null, visionCallback); // 异步  
  103.                 }  
  104.             }  
  105.   
  106.             @Override  
  107.             public void onServiceDisconnect() {  
  108.                 // 释放  
  109.                 if ((!IS_ASYNC && (result == 0)) || (IS_ASYNC && (result == IS_ASYNC_CODE))) {  
  110.                   textDetector.release();  
  111.                 }  
  112.                 if (pixelMap != null) {  
  113.                     pixelMap.release();  
  114.                     pixelMap = null;  
  115.                 }  
  116.                 VisionManager.destroy();  
  117.             }  
  118.         };  
  119.     }  
  120.   
  121.     public void sendResult(String value) {  
  122.         if (textDetector != null) {  
  123.             textDetector.release();  
  124.         }  
  125.         if (pixelMap != null) {  
  126.             pixelMap.release();  
  127.             pixelMap = null;  
  128.             VisionManager.destroy();  
  129.         }  
  130.         if (value != null) {  
  131.             maps.put(mediaId, value);  
  132.         }  
  133.         if ((maps != null) && (maps.size() == pictureLists.length)) {  
  134.             InnerEvent event = InnerEvent.get(1, 0, maps);  
  135.             handle.sendEvent(event);  
  136.         } else {  
  137.             wordRecognition(slice, pictureLists[index], handle);  
  138.             index++;  
  139.         }  
  140.     }  
  141.   
  142.     // 获取图片  
  143.     private PixelMap getPixelMap(int resId) {  
  144.         ResourceManager manager = slice.getResourceManager();  
  145.   
  146.         byte[] datas = new byte[0];  
  147.         try {  
  148.             Resource resource = manager.getResource(resId);  
  149.             datas = readBytes(resource);  
  150.             resource.close();  
  151.         } catch (IOException | NotExistException e) {  
  152.             LogUtil.error("get pixelmap failed, read resource bytes failed, ", e.getLocalizedMessage());  
  153.         }  
  154.   
  155.         ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();  
  156.         srcOpts.formatHint = "image/jpg";  
  157.         ImageSource imageSource;  
  158.         imageSource = ImageSource.create(datas, srcOpts);  
  159.         ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();  
  160.         decodingOpts.desiredSize = new Size(0, 0);  
  161.         decodingOpts.desiredRegion = new Rect(0, 0, 0, 0);  
  162.         decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888;  
  163.         pixelMap = imageSource.createPixelmap(decodingOpts);  
  164.         return pixelMap;  
  165.     }  
  166.   
  167.     private static byte[] readBytes(Resource resource) {  
  168.         final int bufferSize = 1024;  
  169.         final int ioEnd = -1;  
  170.   
  171.         ByteArrayOutputStream output = new ByteArrayOutputStream();  
  172.         byte[] buffers = new byte[bufferSize];  
  173.         byte[] results = new byte[0];  
  174.         while (true) {  
  175.             try {  
  176.                 int readLen = resource.read(buffers, 0, bufferSize);  
  177.                 if (readLen == ioEnd) {  
  178.                     results = output.toByteArray();  
  179.                     break;  
  180.                 }  
  181.                 output.write(buffers, 0, readLen);  
  182.             } catch (IOException e) {  
  183.                 LogUtil.error("OrcAbilitySlice.getPixelMap""read resource failed ");  
  184.                 break;  
  185.             } finally {  
  186.                 try {  
  187.                     output.close();  
  188.                 } catch (IOException e) {  
  189.                     LogUtil.error("OrcAbilitySlice.getPixelMap""close output failed");  
  190.                 }  
  191.             }  
  192.         }  
  193.         return results;  
  194.     }  

(5)com/huawei/searchimagebykeywords/util/WordSegment

  1. import com.huawei.searchimagebykeywords.slice.MainAbilitySlice;  
  2.   
  3. import ohos.ai.nlu.NluClient;  
  4. import ohos.ai.nlu.NluRequestType;  
  5. import ohos.ai.nlu.OnResultListener;  
  6. import ohos.ai.nlu.ResponseResult;  
  7. import ohos.app.Context;  
  8. import ohos.eventhandler.InnerEvent;  
  9.   
  10. import java.util.ArrayList;  
  11. import java.util.Arrays;  
  12. import java.util.List;  
  13.   
  14. public class WordSegment {  
  15.     private static final boolean IS_ASYNC = true;  
  16.     private static final String WORDS = "words";  
  17.     private static final int ZERO = 0;  
  18.     private static final int TWO = 2;  
  19.     private static final int STEP = 8;  
  20.     private Context slice;  
  21.     private MainAbilitySlice.MyEventHandle handle;  
  22.   
  23.     public void wordSegment(Context context, String requestData, MainAbilitySlice.MyEventHandle myEventHandle) {  
  24.         slice = context;  
  25.         handle = myEventHandle;  
  26.   
  27.         // 使用NluClient静态类进行初始化,通过异步方式获取服务的连接。  
  28.         NluClient.getInstance().init(context, new OnResultListener<Integer>() {  
  29.             @Override  
  30.             public void onResult(Integer resultCode) {  
  31.                 if (!IS_ASYNC) {  
  32.                     // 同步  
  33.                     ResponseResult responseResult = NluClient.getInstance().getWordSegment(requestData,  
  34.                             NluRequestType.REQUEST_TYPE_LOCAL);  
  35.                     sendResult(responseResult.getResponseResult());  
  36.                     release();  
  37.                 } else {  
  38.                     // 异步  
  39.                     wordSegmentAsync(requestData);  
  40.                 }  
  41.             }  
  42.         }, true);  
  43.     }  
  44.   
  45.     private void wordSegmentAsync(String requestData) {  
  46.         ResponseResult responseResult = NluClient.getInstance().getWordSegment(requestData,  
  47.                 NluRequestType.REQUEST_TYPE_LOCAL, new OnResultListener<ResponseResult>() {  
  48.                     @Override  
  49.                     public void onResult(ResponseResult asyncResult) {  
  50.                         sendResult(asyncResult.getResponseResult());  
  51.                         release();  
  52.                     }  
  53.                 });  
  54.     }  
  55.   
  56.     private void sendResult(String result) {  
  57.         List lists = null; // 分词识别结果  
  58.         // 将result中分词结果转换成list  
  59.         if (result.contains("\"message\":\"success\"")) {  
  60.             String words = result.substring(result.indexOf(WORDS) + STEP,  
  61.                     result.lastIndexOf("]")).replaceAll("\"""");  
  62.             if ((words == null) || ("".equals(words))) {  
  63.                 lists = new ArrayList(1);  
  64.                 lists.add("no keywords"); // 未识别到分词结果,返回"no keywords"  
  65.             } else {  
  66.                 lists = Arrays.asList(words.split(","));  
  67.             }  
  68.         }  
  69.   
  70.         InnerEvent event = InnerEvent.get(TWO, ZERO, lists);  
  71.         handle.sendEvent(event);  
  72.     }  
  73.   
  74.     private void release() {  
  75.         NluClient.getInstance().destroy(slice);  
  76.     }  

(6)com/huawei/searchimagebykeywords/MainAbility

  1. import com.huawei.searchimagebykeywords.slice.MainAbilitySlice;  
  2.   
  3. import ohos.aafwk.ability.Ability;  
  4. import ohos.aafwk.content.Intent;  
  5. public class MainAbility extends Ability {  
  6.     @Override  
  7.     public void onStart(Intent intent) {  
  8.         super.onStart(intent);  
  9.         super.setMainRoute(MainAbilitySlice.class.getName());  
  10.     }  

(7)com/huawei/searchimagebykeywords/MyApplication

  1. import ohos.aafwk.ability.AbilityPackage;  
  2.   
  3. public class MyApplication extends AbilityPackage {  
  4.     @Override  
  5.     public void onInitialize() {  
  6.         super.onInitialize();  
  7.     }  

🕮 说明

以上代码仅demo演示参考使用,产品化的代码需要考虑数据校验和国际化。

8. 恭喜您

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

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2010-02-04 09:37:31

2009-12-03 10:09:36

linux添加字体中文字体

2011-06-21 13:56:39

CSS

2010-03-05 16:09:44

Python中文字符

2011-01-11 10:05:29

Linux中文字体

2009-07-09 09:29:45

JDK中文Linux

2011-06-16 17:01:21

Qt MeeGo 排序

2010-02-02 16:49:32

C++中文字符

2010-09-01 14:20:19

CSS排版

2018-01-22 20:52:38

阿里巴巴AI字库

2010-03-15 15:51:35

Ubuntu 8.04

2009-06-16 13:57:00

netbeans 中文字体美化

2024-03-11 06:05:00

C++字符串

2010-01-12 16:50:07

Linux minig

2009-11-26 16:43:11

PHP截取中文字符串

2009-12-01 15:41:16

PHP substr截

2009-11-27 09:55:11

PHP截取中文字符

2010-06-08 09:30:20

UML图

2012-03-08 10:55:29

新一代iPad官方视频中文字幕

2015-11-17 17:30:16

点赞
收藏

51CTO技术栈公众号