小程序模板網(wǎng)

Serverless 打造智能微信小程序:圖像識別分析文本

發(fā)布時間:2018-05-16 15:26 所屬欄目:小程序開發(fā)教程

結(jié)束了五一國慶的八天假期后,便開始著手為微信小程序《代碼協(xié)作》制作一個圖片識別代碼的功能。這個需求的主要來源是,在有的公司、組織、團(tuán)隊(duì)上,代碼是不能直接拷貝出來的。但是,拍照是允許的。為了協(xié)作方便,一般會拍照在微信群里討論。對于我而言,因此這樣一個真實(shí)需求的存在,我便想試試能不能做這樣的一個功能。

對于圖片識別功能來說,只需要兩步:

  1. 上傳圖片到 AWS S3 上
  2. 找到一個合適的圖片識別服務(wù),來識別這張圖片

然而,第一步是最難的一步。

Serverless 上傳圖片

按理來說,我們只需要在 Serverless 應(yīng)用里,接受這個數(shù)據(jù),然后再存儲到 AWS S3 就可以了。

微信小程序上傳圖片時,采用的 ContentType 是 multipart/form-data ,這就意味著上傳的圖片不是 base64 形式的。在 AWS Gateway 里,接受到的數(shù)據(jù)變成了:

{ fieldname: 'file',
  originalname: 'tmp_41852593e221427e029327f987f3d588.png',
  encoding: '7bit',
  mimetype: 'image/png',
  buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 03 e8 00 00 02 80 08 06 00 00 00 0f 73 52 67 00 00 00 01 73 52 47 42 00 ae ce 1c e9 00 00 40 00 ... >,
  size: 870857 }

最開始的時候,我以為是微信小程序上傳了。于是,我開始用 curl 來測試上傳圖片:

curl -v -F file=@test.jpg https://code.wdsm.io/upload

然后對比了本地 readFileSync 的 Buffer 數(shù)據(jù),發(fā)現(xiàn)圖片的編碼變了。

然后,我測試了文本上傳:

curl -v -F file=@hello.txt https://code.wdsm.io/upload

發(fā)現(xiàn)文本的編碼結(jié)果是不變的。在 Google 了一番之后,發(fā)現(xiàn)是因?yàn)?AWS Gateway 是能識別文本編碼的。

在我嘗試了 N 次之后,并在本地構(gòu)建了個類似的環(huán)境。發(fā)現(xiàn)了 AWS Gateway 做了一個神奇的轉(zhuǎn)換: Buffer.from(imageData, 'utf8').toString('utf8') 。理論上,經(jīng)過這樣的轉(zhuǎn)換,數(shù)據(jù)應(yīng)該是變回原來的格式。然而,這個圖片并不是 utf8 編碼,所以這個數(shù)據(jù)無法轉(zhuǎn)換回去。

在繼續(xù) Google 了一番之后,發(fā)現(xiàn)了一個 Serverless Framework 的插件:serverless-apigw-binary。它可以將圖片轉(zhuǎn)換為二進(jìn)制形式的,而 AWS Gateway 不會對二進(jìn)制的內(nèi)容進(jìn)行特殊編碼。其配置如下所示:

custom:
  apigwBinary:
    types:
      - 'image/jpeg'
      - 'image/png'
      - 'text/html'
      - 'multipart/form-data'

上面配置中,最重要的其實(shí)是 'multipart/form-data' ,它會將我們的請求轉(zhuǎn)換為二進(jìn)制形式的。

正在我以為要大功告成的時候,我發(fā)現(xiàn)直接用 AWS Lambda 解析出來還是有問題。在嘗試了多次之后,結(jié)合了一下 express 里的 multer 來解析這個數(shù)據(jù),然后它工作了:

const express = require("express");
const multer = require('multer');

const multerupload = multer();
const app = express();

app.post('/upload', multerupload.any(), function (req, res) {
  let file = req.files[0];
  ...
});

果然,編碼是要靠猜的。

Serverless 圖片識別

在開始這部分之前,需要先了解一下 AWS Rekognition。

Amazon Rekognition 讓您能夠輕松地為應(yīng)用程序添加圖像和視頻分析功能。您只需向 Rekognition API 提供圖像或視頻,然后此服務(wù)就能識別對象、人員、文字、場景和活動,以及檢測任何不適宜的內(nèi)容。

由于,我們的《代碼協(xié)作》應(yīng)用整個是基于 AWS 的,因此我們也就繼續(xù)使用 AWS 的服務(wù)來識別文本。先將圖片放到 AWS S3 上,然后才是識別:

s3.putObject({
  Body: file.buffer,
  Bucket: bucketName,
  Key: file.originalname,
  ContentType: file.mimetype
}, function (err, data) {
  const s3Config = {
    bucket: bucketName,
    imageName: file.originalname,
  };

  return ImageAnalyser
    .getImageText(s3Config)
    .then((text) => {
      console.log(JSON.stringify(text, null, '\t'));
      res.status(200).send(text)
    })
    ...
})

識別部分代碼如下:

const rek = new AWS.Rekognition();

class ImageAnalyser {
  static getImageText(s3Config) {
    ...

    return new Promise((resolve, reject) => {
      rek.detectText(params, (err, data) => {
        if (err) {
          console.log(params, err);
          return reject(new Error(err));
        }
        return resolve(data);
      });
    });
  }
}

對應(yīng)的返回結(jié)果:

{"TextDetections":[{"DetectedText":"test","Type":"LINE","Id":0,"Confidence":94.28083038330078,"Geometry":{"BoundingBox":{"Width":1.0391244888305664,"Height":1.0596693754196167,"Left":-0.023785971105098724,"Top":0.0029582083225250244},"Polygon":[{"X":-0.023785971105098724,"Y":0.0029582083225250244},{"X":1.0153385400772095,"Y":-0.012681752443313599},{"X":1.018007755279541,"Y":1.046987533569336},{"X":-0.021116789430379868,"Y":1.0626275539398193}]}},{"DetectedText":"test","Type":"WORD","Id":1,"ParentId":0,"Confidence":94.28083038330078,"Geometry":{"BoundingBox":{"Width":1.0354670286178589,"Height":1.058911919593811,"Left":-0.02123582363128662,"Top":-0.0029199719429016113},"Polygon":[{"X":-0.023785971105098724,"Y":0.0029582083225250244},{"X":1.0153385400772095,"Y":-0.012681752443313599},{"X":1.018007755279541,"Y":1.046987533569336},{"X":-0.021116789430379868,"Y":1.0626275539398193}]}}]}

微信小程序展示

于是在小程序端,我們只需要處理對應(yīng)的結(jié)果即可:

wx.uploadFile({
  url: 'https://code.wdsm.io/upload',
  filePath: path,
  name: 'file',
  success: function (res) {
    let textDetections = JSON.parse(res.data)['TextDetections'];
    let code = '';

    for (let i = 0; i < textDetections.length; i++) {
      let textDetection = textDetections[i];
      if (textDetection.Type === 'LINE') {
        code = code + textDetection.DetectedText + '\n';
      }
    }

    that.setData({
      code: code,
      isUploading: false
    });
  },
  ...
})

然后,在頁面上顯示即可:

<view class="ai">
  <button type="default" class="btn" bindtap="chooseImage">上傳圖片</button>
  <view wx:if="{{code}}" class="weui-cells__title" size="mini">(點(diǎn)擊復(fù)制文本)</view>
  <view wx:if="{{code}}" bindtap="copyCode">
     {{code}}
  </view>
</view>

<loading hidden="{{!isUploading}}">
  上傳中...
</loading>

不過,這里有一個問題,這個 loading 好像有問題。


易優(yōu)小程序(企業(yè)版)+靈活api+前后代碼開源 碼云倉庫:starfork
本文地址:http://22321a.com/wxmini/doc/course/24428.html 復(fù)制鏈接 如需定制請聯(lián)系易優(yōu)客服咨詢:800182392 點(diǎn)擊咨詢
QQ在線咨詢