Google Cloud Vision via gRPC in Delphi

· Componenten

Google Cloud Vision analyseert afbeeldingen en vertelt je wat erin zit: het retourneert beschrijvende labels, leest gedrukte en handgeschreven tekst (OCR), detecteert gezichten, herkent beroemde landmarks en logo's, en meer. sgcWebSockets Enterprise levert een getypeerde Vision gRPC-client die bovenop TsgcGRPCClient draait, zodat je een afbeelding kunt versturen en de annotaties ervan kunt teruglezen vanuit Delphi en C++Builder zonder enige externe runtime of handgeschreven protobufs.

Hoe het werkt

Cloud Vision biedt een ImageAnnotator gRPC-service. Een request is een batch van een of meer afbeeldingen, elk gekoppeld aan de lijst met features die je gedetecteerd wilt hebben, en de response is een bijbehorende batch annotaties. De hele uitwisseling bestaat uit Protocol Buffers-berichten ingekapseld over HTTP/2.

sgcWebSockets levert al een complete HTTP/2-stack, dus de transport is een TsgcHTTP2Client gericht op vision.googleapis.com:443 over TLS. TsgcGRPCClient draait daarbovenop en doet de gRPC-framing, headers, timeouts en trailer-parsing. De Vision-berichtklassen in sgcGRPC_Google_Vision zijn getypeerde protobuf-helpers: je vult het request-object, roept ToBytes aan om het te serialiseren, verstuurt het met de generieke client, en laadt de antwoordbytes terug in een getypeerd response-object met LoadFromBytes.

Authenticatie is de standaard Google-service-account-flow. Een zelfondertekende JWT wordt ingewisseld voor een bearer-token en als gRPC-metadata bij elke call verzonden. Omdat de JWT audience-gebonden is, wordt het token gericht op het Vision-endpoint zodat vision.googleapis.com het accepteert.

De clients opzetten

Maak de HTTP/2-transport, koppel de gRPC-client eraan, en vertel het kanaal het binaire protobuf-contenttype te gebruiken. Vision spreekt 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;

Authenticatie

Het bearer-token komt van je service-account-credentials. Configureer de JWT-opties met de waarden uit de gedownloade JSON-sleutel, richt de audience op het Vision-endpoint, en voeg het resulterende token toe aan DefaultMetadata zodat het bij elke gRPC-call meereist.

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

Een afbeelding annoteren

Om een afbeelding te analyseren bouw je een TsgcGRPCVisionBatchAnnotateImagesRequest, voeg je één image-request toe, richt je het op de afbeelding (hier een Google Cloud Storage-URI, maar je kunt ook ruwe bytes versturen), en voeg je een of meer features toe. Elke feature heeft een FeatureType en een optionele MaxResults. Serialiseer met ToBytes en roep de BatchAnnotateImages-methode van de ImageAnnotator-service aan.

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;

De FeatureType-waarden volgen de Vision API-enum: 1 FACE_DETECTION, 2 LANDMARK_DETECTION, 3 LOGO_DETECTION, 4 LABEL_DETECTION, 5 TEXT_DETECTION, 6 DOCUMENT_TEXT_DETECTION, en de rest. Om meerdere detecties op dezelfde afbeelding in één round trip uit te voeren, voeg je meer dan één feature toe.

De annotaties uitlezen

De antwoordbytes laden rechtstreeks in een getypeerde batch-response. Elke afbeelding in de batch draagt afzonderlijke lijsten voor label-, landmark-, logo- en tekstannotaties. Elke vermelding is een TsgcGRPCVisionEntityAnnotation met een Description en, voor labels, een betrouwbaarheids-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;

Afbeeldingen uit storage of uit bytes

De afbeeldingsbron is flexibel. Stel Image.Source.GcsImageUri in voor een object in Google Cloud Storage, of Image.Source.ImageUri voor een openbare HTTP(S)-URL. Om een lokaal bestand te annoteren, lees je het in een TBytes en wijs je het toe aan Image.Content, zodat de afbeelding inline in de request reist. Dezelfde request- en response-klassen verwerken elke bron.

Synchroon of asynchroon

Het bovenstaande voorbeeld gebruikt de blokkerende Call, die een TsgcGRPCResponse retourneert met de StatusCode, de ruwe Data-bytes en de trailers. Om de UI responsief te houden, gebruik je CallAsync en handel je het antwoord af in de OnGRPCResponse-gebeurtenis, waar je aResponse.Data op precies dezelfde manier parset. Een niet-OK-status komt naar voren via OnGRPCError, en een transportfout via OnGRPCException.

Beschikbaarheid

De getypeerde Vision gRPC-client maakt deel uit van de sgcWebSockets Enterprise-editie en draait op Windows, macOS, Linux, iOS en Android. Een kant-en-klaar voorbeeld staat in Demos\21.GRPC\13.Vision, en de volledige referentie staat op de productpagina van de gRPC Client.

Vragen of feedback? Neem contact op. Je krijgt antwoord van de mensen die de code hebben geschreven.