#放码来战.端云一体化开发#HarmonyOS 5 【农民叔叔】20.【端侧工程】病虫害AI诊断预测功能实现 原创

鸿花粉H
发布于 2025-6-8 09:17
浏览
0收藏

在华为云的AI ModelArts平台已部署图像分类模型的在线服务,且平台提供了在线服务的公网API。

打开PestInfoPage.ets文件,在PestDiagnosisView组件内,

1.定义复制文件的方法,将拍照或相册选取的图片复制到APP当前运行的缓存区

/**
   * 复制文件
   * @param from
   * @param to
   */
  copyFile(from:string,to:string):void{
    let fFile=fileIo.openSync(from);
    let tFile=fileIo.openSync(to,fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); // 替换或创建
    fileIo.copyFileSync(fFile.fd,tFile.fd);
    fileIo.closeSync(fFile);
    fileIo.closeSync(tFile);
  }

2.从缓存区读取文件,并压缩

/**
   * 读取文件内容(压缩后)
   * @param cacheImgUri
   * @returns
   */
  async readFileContent(cacheImgUri :string):Promise<ArrayBuffer>{
    let fFile=fileIo.openSync(cacheImgUri,fileIo.OpenMode.READ_ONLY);
    let fStat=fileIo.lstatSync(cacheImgUri);
    let arrayBufFile:ArrayBuffer=new ArrayBuffer(fStat.size); // 压缩前文件大小
    let imgPacker=image.createImagePacker();
    let imgSource=image.createImageSource(fFile.fd);
    await imgPacker.packing(imgSource,{format:'image/jpeg',quality:40})
      .then((data:ArrayBuffer) => {
        arrayBufFile=data;
      })
      .catch((err:BusinessError) => {

      })
    return arrayBufFile;
  }

3.构建请求体body,含需要上传的图片文件内容

/**
   * 构建请求体
   * @param boundary
   * @param fileName
   * @param fileContent
   * @returns
   */
  buildBodyContent(boundary:string,fileName:string,fileContent:Uint8Array):ArrayBuffer{
    // 构建请求体前面内容
    let bodyPre=`--${boundary}\r\n`;
    bodyPre =bodyPre + `Content-Disposition: form-data; name="images"; filename="${fileName}"\r\n`;
    bodyPre =bodyPre + 'Content-Type: application/octet-stream\r\n';
    bodyPre =bodyPre + `\r\n`;
    let txtEncoder=new util.TextEncoder();
    let arrayPre=txtEncoder.encodeInto(bodyPre);

    // 构建请求体后面内容
    let bodyAft='\r\n';
    bodyAft =bodyAft + `--${boundary}`;
    bodyAft=bodyAft + '--\r\n';
    let arrayAft=txtEncoder.encode(bodyAft);

    let body=buffer.concat([arrayPre,fileContent,arrayAft]) // 构建完整请求体
    return body.buffer;
  }

4.解析AI在线服务接口返回的JSON数据

{\"predicted_label\": \"c_3\", \"scores\": [[\"c_3\", \"1.000\"], [\"c_24\", \"0.000\"], [\"c_25\", \"0.000\"], [\"c_26\", \"0.000\"], [\"c_27\", \"0.000\"]]}

并通过key值找到其对应的置信度value值

/**
   * 根据key查找value
   * @param key
   * @param dataArray
   * @returns
   */
  findValueByKey(key:string,dataArray:string[][]){
    const value=dataArray.find((item) => item[0] === key)?.[1];
    return value;
  }

5.AI诊断预测按钮click完整代码如下

/**
   * 调用AI模型接口
   * @param imgUri
   * @returns
   */
  async aiAnalyseImg(imgUri:string):Promise<void>{
    // 文件名
    let fileName=imgUri.split('/').pop() as string;
    let cacheFilePath=`${getContext().cacheDir}/${fileName}`;
    // 复制图片
    this.copyFile(imgUri,cacheFilePath);
    // 从缓存文件读取图片数据
    let fileContent:Uint8Array =new Uint8Array(await this.readFileContent(cacheFilePath));
    // 构建请求体body
    let boundary:string='-------' + (await systemDateTime.getCurrentTime(true)).toString();
    let bodyContent=this.buildBodyContent(boundary,fileName,fileContent);
    console.debug('请求体是:' +bodyContent);
    // 记得替换你自己的接口地址
    let url:string='https://b07b6d6054d241dc8776d5e44203f97e.apig.cn-north-4.huaweicloudapis.com/v1/infers/c9149048-c678-4e73-9dd4-37c01808683b';
    let request=http.createHttp();
    let reqOpts:http.HttpRequestOptions={
      // 请求头
      method:http.RequestMethod.POST,
      header:{
        'X-Apig-AppCode':'7990c0e44c5d422ab7cb5c42a0b23831f62eccb25cc34ee7b450d17445f1c630', // 记得替换你自己的APP Code
        'Content-Type':`multipart/form-data; boundary=${boundary}`,
        'Content-Length':bodyContent.byteLength.toString()
      },
      extraData:bodyContent,
    };
    let model:PestModel | undefined;
    // 发起请求
    request.request(url,reqOpts)
      .then((resp) => {
        console.debug('请求结果是:' +resp.result);
        let aiModel=JSON.parse(resp.result.toString()) as AiPestModel;
        let label=aiModel.predicted_label??'';
        let scores=aiModel.scores??[];
        let code=aiModel.error_code??'';
        let msg=aiModel.error_msg??'';
        if (code !='') {
          AlertDialog.show({
            title:'服务异常~',
            message:'AI诊断预测服务不可用,请稍后再试。'
          });
        }else {
          let value=this.findValueByKey(label,scores)??0; // AI预测结果的置信度
          let pest:PestModel[]=LIST_PEST_DATA.filter(PestModel => PestModel.PredictedLabel === label);
          if(value<0.9 || pest==undefined || pest.length==0){
            AlertDialog.show({
              title:'诊断结果',
              message:'未发现病虫害,仅供参考。',
              cancel:()=>{
                // 关闭对话框
              }
            });
          }else {
            model=pest[0];
            this.pestObj!.PestName=model.PestName;
            this.pestObj!.Type=model.Type;
            this.pestObj!.ID=model.ID;
            this.pestObj!.PestCtrl=model.PestCtrl;
          }

        }
      })
      .catch((err:BusinessError) => {
        AlertDialog.show({
          title:'网络异常~',
          message:err.message
        });
        console.error('网络异常:' + err.message);
      })
  }

AI诊断预测成功后,解析完接口返回的数据并在PestInfoView组件中显示。

下一篇:实现“保存到我的诊断记录”功能

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐