1// Copyright 2017, Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package vision 16 17import ( 18 "context" 19 20 gax "github.com/googleapis/gax-go/v2" 21 pb "google.golang.org/genproto/googleapis/cloud/vision/v1" 22 "google.golang.org/grpc/codes" 23 "google.golang.org/grpc/status" 24) 25 26// AnnotateImage runs image detection and annotation for a single image. 27func (c *ImageAnnotatorClient) AnnotateImage(ctx context.Context, req *pb.AnnotateImageRequest, opts ...gax.CallOption) (*pb.AnnotateImageResponse, error) { 28 res, err := c.BatchAnnotateImages(ctx, &pb.BatchAnnotateImagesRequest{ 29 Requests: []*pb.AnnotateImageRequest{req}, 30 }, opts...) 31 if err != nil { 32 return nil, err 33 } 34 return res.Responses[0], nil 35} 36 37// Called for a single image and a single feature. 38func (c *ImageAnnotatorClient) annotateOne(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, ftype pb.Feature_Type, maxResults int, opts []gax.CallOption) (*pb.AnnotateImageResponse, error) { 39 res, err := c.AnnotateImage(ctx, &pb.AnnotateImageRequest{ 40 Image: img, 41 ImageContext: ictx, 42 Features: []*pb.Feature{{Type: ftype, MaxResults: int32(maxResults)}}, 43 }, opts...) 44 if err != nil { 45 return nil, err 46 } 47 // When there is only one image and one feature, the response's Error field is 48 // unambiguously about that one detection, so we "promote" it to the error return 49 // value. 50 // res.Error is a google.rpc.Status. Convert to a Go error. Use a gRPC 51 // error because it preserves the code as a separate field. 52 // TODO(jba): preserve the details field. 53 if res.Error != nil { 54 return nil, status.Errorf(codes.Code(res.Error.Code), "%s", res.Error.Message) 55 } 56 return res, nil 57} 58 59// DetectFaces performs face detection on the image. 60// At most maxResults results are returned. 61func (c *ImageAnnotatorClient) DetectFaces(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.FaceAnnotation, error) { 62 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_FACE_DETECTION, maxResults, opts) 63 if err != nil { 64 return nil, err 65 } 66 return res.FaceAnnotations, nil 67} 68 69// DetectLandmarks performs landmark detection on the image. 70// At most maxResults results are returned. 71func (c *ImageAnnotatorClient) DetectLandmarks(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { 72 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_LANDMARK_DETECTION, maxResults, opts) 73 if err != nil { 74 return nil, err 75 } 76 return res.LandmarkAnnotations, nil 77} 78 79// DetectLogos performs logo detection on the image. 80// At most maxResults results are returned. 81func (c *ImageAnnotatorClient) DetectLogos(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { 82 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_LOGO_DETECTION, maxResults, opts) 83 if err != nil { 84 return nil, err 85 } 86 return res.LogoAnnotations, nil 87} 88 89// DetectLabels performs label detection on the image. 90// At most maxResults results are returned. 91func (c *ImageAnnotatorClient) DetectLabels(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { 92 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_LABEL_DETECTION, maxResults, opts) 93 if err != nil { 94 return nil, err 95 } 96 return res.LabelAnnotations, nil 97} 98 99// DetectTexts performs text detection on the image. 100// At most maxResults results are returned. 101func (c *ImageAnnotatorClient) DetectTexts(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { 102 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_TEXT_DETECTION, maxResults, opts) 103 if err != nil { 104 return nil, err 105 } 106 return res.TextAnnotations, nil 107} 108 109// DetectDocumentText performs full text (OCR) detection on the image. 110func (c *ImageAnnotatorClient) DetectDocumentText(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.TextAnnotation, error) { 111 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_DOCUMENT_TEXT_DETECTION, 0, opts) 112 if err != nil { 113 return nil, err 114 } 115 return res.FullTextAnnotation, nil 116} 117 118// DetectSafeSearch performs safe-search detection on the image. 119func (c *ImageAnnotatorClient) DetectSafeSearch(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.SafeSearchAnnotation, error) { 120 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_SAFE_SEARCH_DETECTION, 0, opts) 121 if err != nil { 122 return nil, err 123 } 124 return res.SafeSearchAnnotation, nil 125} 126 127// DetectImageProperties computes properties of the image. 128func (c *ImageAnnotatorClient) DetectImageProperties(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.ImageProperties, error) { 129 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_IMAGE_PROPERTIES, 0, opts) 130 if err != nil { 131 return nil, err 132 } 133 return res.ImagePropertiesAnnotation, nil 134} 135 136// DetectWeb computes a web annotation on the image. 137func (c *ImageAnnotatorClient) DetectWeb(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.WebDetection, error) { 138 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_WEB_DETECTION, 0, opts) 139 if err != nil { 140 return nil, err 141 } 142 return res.WebDetection, nil 143} 144 145// CropHints computes crop hints for the image. 146func (c *ImageAnnotatorClient) CropHints(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.CropHintsAnnotation, error) { 147 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_CROP_HINTS, 0, opts) 148 if err != nil { 149 return nil, err 150 } 151 return res.CropHintsAnnotation, nil 152} 153 154// LocalizeObject runs the localizer for object detection. 155func (c *ImageAnnotatorClient) LocalizeObjects(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) ([]*pb.LocalizedObjectAnnotation, error) { 156 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_OBJECT_LOCALIZATION, 0, opts) 157 if err != nil { 158 return nil, err 159 } 160 return res.LocalizedObjectAnnotations, nil 161} 162 163// ProductSearch searches the image for products. 164func (c *ImageAnnotatorClient) ProductSearch(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.ProductSearchResults, error) { 165 res, err := c.annotateOne(ctx, img, ictx, pb.Feature_PRODUCT_SEARCH, 0, opts) 166 if err != nil { 167 return nil, err 168 } 169 return res.ProductSearchResults, nil 170} 171