Google Cloud Vision は画像を分析し、そこに何が写っているかを教えてくれます。説明的なラベルを返し、印刷文字や手書き文字を読み取り(OCR)、顔を検出し、有名なランドマークやロゴを認識するなど、さまざまな機能があります。sgcWebSockets Enterprise には TsgcGRPCClient の上に配置される型付き Vision gRPC クライアントが付属しているため、外部ランタイムや手書きの protobuf なしで、Delphi や C++Builder から画像を送信してそのアノテーションを読み取れます。
仕組み
Cloud Vision は ImageAnnotator gRPC サービスを公開しています。リクエストは 1 つ以上の画像のバッチで、各画像には検出したい機能のリストが対になり、レスポンスはそれに対応するアノテーションのバッチです。やり取り全体は、HTTP/2 上でフレーミングされた Protocol Buffers メッセージです。
sgcWebSockets には完全な HTTP/2 スタックがすでに付属しているため、トランスポートは TLS 経由で vision.googleapis.com:443 に向けた TsgcHTTP2Client です。その上に TsgcGRPCClient が配置され、gRPC のフレーミング、ヘッダー、タイムアウト、トレーラー解析を行います。sgcGRPC_Google_Vision 内の Vision メッセージクラスは型付きの protobuf ヘルパーです。リクエストオブジェクトに値を入れ、ToBytes を呼び出してシリアライズし、汎用クライアントで送信し、レスポンスのバイト列を LoadFromBytes で型付きレスポンスオブジェクトに読み込みます。
認証は標準的な Google サービスアカウントのフローです。自己署名 JWT がベアラートークンと交換され、すべての呼び出しで gRPC メタデータとして送信されます。JWT はオーディエンスにバインドされるため、vision.googleapis.com が受け入れるよう、トークンは Vision エンドポイントを対象にします。
クライアントのセットアップ
HTTP/2 トランスポートを作成し、それに gRPC クライアントをアタッチし、チャネルにバイナリ protobuf コンテンツタイプを使うよう指示します。Vision は 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;
認証
ベアラートークンはサービスアカウントの認証情報から得られます。ダウンロードした JSON キーの値で JWT オプションを構成し、オーディエンスを Vision エンドポイントに向け、得られたトークンを DefaultMetadata に追加すると、すべての 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);
画像へのアノテーション
画像を分析するには、TsgcGRPCVisionBatchAnnotateImagesRequest を構築し、画像リクエストを 1 つ追加し、それを画像(ここでは Google Cloud Storage の URI ですが、生のバイト列を送ることもできます)に向け、1 つ以上の機能を追加します。各機能には FeatureType と省略可能な MaxResults があります。ToBytes でシリアライズし、ImageAnnotator サービスの BatchAnnotateImages メソッドを呼び出します。
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;
FeatureType の値は Vision API の列挙に従います。1 FACE_DETECTION、2 LANDMARK_DETECTION、3 LOGO_DETECTION、4 LABEL_DETECTION、5 TEXT_DETECTION、6 DOCUMENT_TEXT_DETECTION、そしてその他です。同じ画像に対して複数の検出を 1 回の往復で実行するには、複数の機能を追加します。
アノテーションの読み取り
レスポンスのバイト列は、そのまま型付きバッチレスポンスに読み込まれます。バッチ内の各画像は、ラベル、ランドマーク、ロゴ、テキストのアノテーションについて別々のリストを持ちます。各エントリは Description を持ち、ラベルの場合は信頼度の Score も持つ TsgcGRPCVisionEntityAnnotation です。
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;
ストレージまたはバイト列からの画像
画像のソースは柔軟です。Google Cloud Storage 内のオブジェクトには Image.Source.GcsImageUri を、公開された HTTP(S) URL には Image.Source.ImageUri を設定します。ローカルファイルにアノテーションを付けるには、それを TBytes に読み込んで代わりに Image.Content に割り当て、画像をリクエスト内にインラインで送ります。同じリクエスト/レスポンスクラスがすべてのソースを処理します。
同期または非同期
上記の例ではブロッキングの Call を使っており、StatusCode、生の Data バイト列、トレーラーを持つ TsgcGRPCResponse を返します。UI の応答性を保つには CallAsync を使い、OnGRPCResponse イベントでレスポンスを処理します。そこで aResponse.Data をまったく同じ方法で解析します。OK 以外のステータスは OnGRPCError から、トランスポートの失敗は OnGRPCException から通知されます。
提供状況
型付き Vision gRPC クライアントは sgcWebSockets Enterprise エディションの一部で、Windows、macOS、Linux、iOS、Android で動作します。すぐに実行できるサンプルは Demos\21.GRPC\13.Vision にあり、完全なリファレンスは gRPC Client 製品ページにあります。
ご質問やご意見はありますか? お問い合わせください。コードを書いた本人から返信いたします。
