Google Cloud Vision przez gRPC w Delphi

· Komponenty

Google Cloud Vision analizuje obrazy i informuje Cię, co się na nich znajduje: zwraca opisowe etykiety, odczytuje tekst drukowany i odręczny (OCR), wykrywa twarze, rozpoznaje znane punkty orientacyjne i logotypy oraz wiele więcej. sgcWebSockets Enterprise dostarcza typowanego klienta gRPC Vision, który działa na TsgcGRPCClient, więc możesz wysłać obraz i odczytać jego adnotacje z Delphi i C++Builder bez żadnego zewnętrznego środowiska uruchomieniowego ani ręcznie pisanych protobufów.

Jak to działa

Cloud Vision udostępnia usługę gRPC ImageAnnotator. Żądanie to pakiet jednego lub więcej obrazów, z których każdy jest sparowany z listą funkcji, które chcesz wykryć, a odpowiedź to pasujący pakiet adnotacji. Cała wymiana to komunikaty Protocol Buffers opakowane w HTTP/2.

sgcWebSockets dostarcza już kompletny stos HTTP/2, więc transportem jest TsgcHTTP2Client wskazujący na vision.googleapis.com:443 przez TLS. TsgcGRPCClient działa na jego podstawie i wykonuje opakowywanie gRPC, nagłówki, limity czasu i parsowanie trailerów. Klasy komunikatów Vision w sgcGRPC_Google_Vision to typowane funkcje pomocnicze protobuf: wypełniasz obiekt żądania, wywołujesz ToBytes, aby go zserializować, wysyłasz go ogólnym klientem i wczytujesz bajty odpowiedzi z powrotem do typowanego obiektu odpowiedzi za pomocą LoadFromBytes.

Uwierzytelnianie to standardowy przepływ konta usługi Google. Samodzielnie podpisany JWT jest wymieniany na token bearer i wysyłany jako metadane gRPC przy każdym wywołaniu. Ponieważ JWT jest powiązany z odbiorcą, token jest skierowany na punkt końcowy Vision, aby vision.googleapis.com go zaakceptował.

Konfigurowanie klientów

Utwórz transport HTTP/2, dołącz do niego klienta gRPC i poinstruuj kanał, aby używał binarnego typu zawartości protobuf. Vision mówi w application/grpc+proto.

uses
  sgcHTTP2_Client, sgcGRPC_Types, sgcGRPC_Client,
  sgcGRPC_Google_Vision;

var
  HTTP2: TsgcHTTP2Client;
  GRPC: TsgcGRPCClient;
begin
  HTTP2 := TsgcHTTP2Client.Create(nil);
  HTTP2.Host := 'vision.googleapis.com';
  HTTP2.Port := 443;
  HTTP2.TLS  := True;

  GRPC := TsgcGRPCClient.Create(nil);
  GRPC.Client := HTTP2;
  GRPC.ChannelOptions.ContentType := grpcProto;
  GRPC.ChannelOptions.Compression := grpcNoCompression;
end;

Uwierzytelnianie

Token bearer pochodzi z poświadczeń Twojego konta usługi. Skonfiguruj opcje JWT wartościami z pobranego klucza JSON, skieruj odbiorcę na punkt końcowy Vision i dodaj otrzymany token do DefaultMetadata, aby towarzyszył każdemu wywołaniu gRPC.

// configure the service-account JWT (values from the JSON key file)
CloudClient.GoogleCloudOptions.Authentication := gcaJWT;
CloudClient.GoogleCloudOptions.JWT.ClientEmail  := ClientEmail;
CloudClient.GoogleCloudOptions.JWT.PrivateKeyId := PrivateKeyId;
CloudClient.GoogleCloudOptions.JWT.PrivateKey.Text := PrivateKey;
CloudClient.GoogleCloudOptions.JWT.ProjectId := ProjectId;
// the self-signed JWT is audience-bound to the Vision endpoint
CloudClient.GoogleCloudOptions.JWT.API_Endpoint :=
  'https://vision.googleapis.com/';

// once the token is acquired, send it as gRPC metadata
GRPC.DefaultMetadata.Clear;
GRPC.DefaultMetadata.Add('authorization', 'Bearer ' + Token);

Adnotowanie obrazu

Aby przeanalizować obraz, budujesz TsgcGRPCVisionBatchAnnotateImagesRequest, dodajesz jedno żądanie obrazu, wskazujesz je na obraz (tutaj identyfikator URI Google Cloud Storage, ale możesz też wysłać surowe bajty) i dodajesz jedną lub więcej funkcji. Każda funkcja ma FeatureType i opcjonalne MaxResults. Zserializuj za pomocą ToBytes i wywołaj metodę BatchAnnotateImages usługi ImageAnnotator.

var
  oRequest: TsgcGRPCVisionBatchAnnotateImagesRequest;
  oImgReq: TsgcGRPCVisionAnnotateImageRequest;
  oFeature: TsgcGRPCVisionFeature;
  oResponse: TsgcGRPCResponse;
begin
  oRequest := TsgcGRPCVisionBatchAnnotateImagesRequest.Create;
  try
    oImgReq := oRequest.AddRequest;
    oImgReq.Image.Source.GcsImageUri :=
      'gs://cloud-samples-data/vision/demo-image.jpg';

    oFeature := oImgReq.AddFeature;
    oFeature.FeatureType := 4;   // LABEL_DETECTION
    oFeature.MaxResults := 10;

    oResponse := GRPC.Call('google.cloud.vision.v1.ImageAnnotator',
      'BatchAnnotateImages', oRequest.ToBytes);
  finally
    oRequest.Free;
  end;
end;

Wartości FeatureType odpowiadają wyliczeniu API Vision: 1 FACE_DETECTION, 2 LANDMARK_DETECTION, 3 LOGO_DETECTION, 4 LABEL_DETECTION, 5 TEXT_DETECTION, 6 DOCUMENT_TEXT_DETECTION i pozostałe. Aby wykonać kilka wykryć na tym samym obrazie w jednej rundzie, dodaj więcej niż jedną funkcję.

Odczytywanie adnotacji

Bajty odpowiedzi wczytują się bezpośrednio do typowanej odpowiedzi pakietowej. Każdy obraz w pakiecie zawiera oddzielne listy adnotacji etykiet, punktów orientacyjnych, logotypów i tekstu. Każdy wpis to TsgcGRPCVisionEntityAnnotation z Description oraz, dla etykiet, oceną pewności Score.

var
  oResponse: TsgcGRPCVisionBatchAnnotateImagesResponse;
  oImgResp: TsgcGRPCVisionAnnotateImageResponse;
  i, j: Integer;
begin
  oResponse := TsgcGRPCVisionBatchAnnotateImagesResponse.Create;
  try
    oResponse.LoadFromBytes(aData);
    for i := 0 to oResponse.ResponseCount - 1 do
    begin
      oImgResp := oResponse.Response(i);

      for j := 0 to oImgResp.LabelAnnotationCount - 1 do
        Memo1.Lines.Add('Label: ' + oImgResp.LabelAnnotation(j).Description +
          ' (score: ' + FloatToStr(oImgResp.LabelAnnotation(j).Score) + ')');

      for j := 0 to oImgResp.TextAnnotationCount - 1 do
        Memo1.Lines.Add('Text: ' + oImgResp.TextAnnotation(j).Description);

      for j := 0 to oImgResp.LandmarkAnnotationCount - 1 do
        Memo1.Lines.Add('Landmark: ' + oImgResp.LandmarkAnnotation(j).Description);
    end;
  finally
    oResponse.Free;
  end;
end;

Obrazy z magazynu lub z bajtów

Źródło obrazu jest elastyczne. Ustaw Image.Source.GcsImageUri dla obiektu w Google Cloud Storage lub Image.Source.ImageUri dla publicznego adresu URL HTTP(S). Aby adnotować plik lokalny, wczytaj go do TBytes i zamiast tego przypisz do Image.Content, dzięki czemu obraz podróżuje osadzony w treści żądania. Te same klasy żądań i odpowiedzi obsługują każde źródło.

Synchronicznie lub asynchronicznie

Powyższy przykład używa blokującego Call, które zwraca TsgcGRPCResponse z StatusCode, surowymi bajtami Data i trailerami. Aby zachować responsywność interfejsu użytkownika, użyj CallAsync i obsłuż odpowiedź w zdarzeniu OnGRPCResponse, gdzie parsujesz aResponse.Data dokładnie tak samo. Status inny niż OK ujawnia się przez OnGRPCError, a awaria transportu przez OnGRPCException.

Dostępność

Typowany klient gRPC Vision jest częścią edycji Enterprise sgcWebSockets i działa na Windows, macOS, Linux, iOS oraz Android. Gotowy do uruchomienia przykład znajduje się w Demos\21.GRPC\13.Vision, a pełna dokumentacja jest na stronie produktu gRPC Client.

Pytania lub uwagi? Skontaktuj się z nami. Otrzymasz odpowiedź od osób, które napisały ten kod.