在 Firebase 函数中使用 Google Cloud AutoML 模型预测存储在 Google Cloud storage 中的图像

Use Google Cloud AutoML model predict an image which is stored in Google Cloud storage in Firebase function

我正在尝试通过 Firebase 函数中经过训练的 AutoML 模型为图像提供预测标签。此图像存储在 Google 云存储中。 我尝试以这种方式阅读图像:

const gcs = require('@google-cloud/storage')();
const myBucket = gcs.bucket(object.bucket);
const file = myBucket.file(object.name);
const stream = file.createReadStream();

var data = '';
stream.on('error', function(err) {
  console.log("error");
})
.on('data', function(chunk) {
  data = data + chunk;
  console.log("Writing data");
})
.on('end', function() {
});

我读完数据后,我把数据转成'binary'格式

var encoded = new Buffer(data)
encoded = encoded.toString('binary');

但我将这些编码数据输入 'imageBytes':

const payload = {
  "image": {
    "imageBytes": encoded
  },
};
var formattedName = client.modelPath(project, location, model);

var request = {
  name: formattedName,
  payload: payload,
};

client.predict(request)
.then(responses => {
  console.log("responses:", responses);
  var response = responses[0];

  console.log("response:", response);
})
.catch(err => {
  console.error(err);
});

它会抛出一个错误:

Error: invalid encoding
at Error (native)
at Object.decode (/user_code/node_modules/@google-cloud/automl/node_modules/@protobufjs/base64/index.js:105:19)
at Type.Image$fromObject [as fromObject] (eval at Codegen (/user_code/node_modules/@google-cloud/automl/node_modules/@protobufjs/codegen/index.js:50:33), <anonymous>:9:15)
at Type.ExamplePayload$fromObject [as fromObject] (eval at Codegen (/user_code/node_modules/@google-cloud/automl/node_modules/@protobufjs/codegen/index.js:50:33), <anonymous>:10:20)
at Type.PredictRequest$fromObject [as fromObject] (eval at Codegen (/user_code/node_modules/@google-cloud/automl/node_modules/@protobufjs/codegen/index.js:50:33), <anonymous>:13:22)
at serialize (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/protobuf_js_6_common.js:70:23)
at Object.final_requester.sendMessage (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:802:37)
at InterceptingCall._callNext (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:418:43)
at InterceptingCall.sendMessage (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:460:8)
at InterceptingCall._callNext (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:424:12)

但是如果我在'base64'中编码图像,它会抛出一个错误:

Error: 3 INVALID_ARGUMENT: Provided image is not valid.
at Object.exports.createStatusError (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/common.js:87:15)
at Object.onReceiveStatus (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:1188:28)
at InterceptingListener._callNext (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:564:42)
at InterceptingListener.onReceiveStatus (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:614:8)
at callback (/user_code/node_modules/@google-cloud/automl/node_modules/grpc/src/client_interceptors.js:841:24)
code: 3,
metadata: Metadata { _internal_repr: { 'grpc-server-stats-bin': [Object] } },
details: 'Provided image is not valid.' 

我也在 Python 中尝试了本地图像文件预测,它使用 'binary' 二进制表示并且效果很好。当我在 Python 中使用 'base64' 时,它会像在 firebase 函数中一样 return "Provided image is not valid."。

我很困惑是我以错误的方式从云存储读取图像还是以错误的方式对图像进行编码。

Firebase 函数中的完整代码:

const automl = require('@google-cloud/automl');
var client = new automl.v1beta1.PredictionServiceClient();
const gcs = require('@google-cloud/storage')();
const myBucket = gcs.bucket(object.bucket);
const file = myBucket.file(object.name);
const stream = file.createReadStream();
var data = '';
stream.on('error', function(err) {
  console.log("error");
})
.on('data', function(chunk) {
  data = data + chunk;
  console.log("Writing data");
})
.on('end', function() {
  var encoded = new Buffer(data)
  encoded = encoded.toString('binary');
  console.log("binary:", encoded);

  const payload = {
    "image": {
      "imageBytes": encoded
    },

  };

  var formattedName = client.modelPath(project, location, model);

  var request = {
    name: formattedName,
    payload: payload,
  };

  client.predict(request)
  .then(responses => {
    console.log("responses:", responses);
    var response = responses[0];

    console.log("response:", response);
  })
  .catch(err => {
    console.error(err);
  });
  stream.destroy();
});

Python中的完整代码:

import sys

from google.cloud import automl_v1beta1
from google.cloud.automl_v1beta1.proto import service_pb2

# Import the base64 encoding library.
import base64


def get_prediction(content, project_id, model_id):
  prediction_client = automl_v1beta1.PredictionServiceClient()

  name = 'projects/{}/locations/us-central1/models/{}'.format(project_id, model_id)
  payload = {'image': {'image_bytes': content }}

  params = {}
  request = prediction_client.predict(name, payload, params)
  return request  # waits till request is returned

if __name__ == '__main__':
  file_path = sys.argv[1]
  project_id = sys.argv[2]
  model_id = sys.argv[3]
  with open(file_path, 'rb') as ff:
    content = ff.read()
    print(content)
    # Encoded as base64
    # content = base64.b64encode(content)

  print(get_prediction(content, project_id,  model_id))

我用的是file.download(),很管用。

file.download().then(imageData => {
  const image = imageData[0];
  const buffer = image.toString('base64');
  const payload = {
    "image": {
      "imageBytes": buffer
    }
  }
  const request = {
    name: formattedName,
    payload: payload
  };
  client.predict(request).then(result => {
    console.log('predict:', result);
  }).catch(err => console.error(err));
});