diff --git a/vision/cloud-client/src/main/java/com/example/vision/Detect.java b/vision/cloud-client/src/main/java/com/example/vision/Detect.java index 28423f432da..4daab79314e 100644 --- a/vision/cloud-client/src/main/java/com/example/vision/Detect.java +++ b/vision/cloud-client/src/main/java/com/example/vision/Detect.java @@ -18,6 +18,7 @@ import com.google.cloud.vision.spi.v1.ImageAnnotatorClient; +import com.google.cloud.vision.spi.v1.ImageAnnotatorSettings; import com.google.cloud.vision.v1.AnnotateImageRequest; import com.google.cloud.vision.v1.AnnotateImageResponse; import com.google.cloud.vision.v1.BatchAnnotateImagesResponse; @@ -28,10 +29,13 @@ import com.google.cloud.vision.v1.Feature; import com.google.cloud.vision.v1.Feature.Type; import com.google.cloud.vision.v1.Image; +import com.google.cloud.vision.v1.ImageSource; import com.google.cloud.vision.v1.LocationInfo; import com.google.cloud.vision.v1.SafeSearchAnnotation; import com.google.protobuf.ByteString; +import org.joda.time.Duration; + import java.io.FileInputStream; import java.io.IOException; import java.io.PrintStream; @@ -78,43 +82,43 @@ public static void argsHelper(String[] args, PrintStream out) throws IOException detectSafeSearch("resources/wakeupcat.jpg", out); } else if (command.equals("faces")) { if (path.startsWith("gs://")) { - // TODO: See https://goo.gl/uWgYhQ + detectFacesGcs(path, out); } else { detectFaces(path, out); } } else if (command.equals("labels")) { if (path.startsWith("gs://")) { - // TODO: See https://goo.gl/uWgYhQ + detectLabelsGcs(path, out); } else { detectLabels(path, out); } } else if (command.equals("landmarks")) { if (path.startsWith("gs://")) { - // TODO: See https://goo.gl/uWgYhQ + detectLandmarksGcs(path, out); } else { detectLandmarks(path, out); } } else if (command.equals("logos")) { if (path.startsWith("gs://")) { - // TODO: See https://goo.gl/uWgYhQ + detectLogosGcs(path, out); } else { detectLogos(path, out); } } else if (command.equals("text")) { if (path.startsWith("gs://")) { - // TODO: See https://goo.gl/uWgYhQ + detectTextGcs(path, out); } else { detectText(path, out); } } else if (command.equals("properties")) { if (path.startsWith("gs://")) { - // TODO: See https://goo.gl/uWgYhQ + detectPropertiesGcs(path, out); } else { detectProperties(path, out); } } else if (command.equals("safe-search")) { if (path.startsWith("gs://")) { - // TODO: See https://goo.gl/uWgYhQ + detectSafeSearchGcs(path, out); } else { detectSafeSearch(path, out); } @@ -131,7 +135,7 @@ public Detect(ImageAnnotatorClient client) { } /** - * Detects faces in the specified image. + * Detects faces in the specified local image. * @param filePath The path to the file to perform face detection on. * @param out A {@link PrintStream} to write detected features to. * @throws IOException on Input/Output errors. @@ -170,7 +174,53 @@ public static void detectFaces(String filePath, PrintStream out) throws IOExcept } /** - * Detects labels in the specified image. + * Detects faces in the specified remote image. + * @param gcsPath The path to the remote file to perform face detection on. + * @param out A {@link PrintStream} to write detected features to. + * @throws IOException on Input/Output errors. + */ + public static void detectFacesGcs(String gcsPath, PrintStream out) throws IOException { + List requests = new ArrayList<>(); + + ImageAnnotatorSettings.Builder imageAnnotatorSettingsBuilder = + ImageAnnotatorSettings.defaultBuilder(); + imageAnnotatorSettingsBuilder.batchAnnotateImagesSettings().getRetrySettingsBuilder() + .setTotalTimeout(Duration.standardSeconds(30)); + ImageAnnotatorSettings settings = imageAnnotatorSettingsBuilder.build(); + + ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build(); + Image img = Image.newBuilder().setSource(imgSource).build(); + Feature feat = Feature.newBuilder().setType(Type.FACE_DETECTION).build(); + + AnnotateImageRequest request = AnnotateImageRequest.newBuilder() + .addFeatures(feat) + .setImage(img) + .build(); + requests.add(request); + + ImageAnnotatorClient client = ImageAnnotatorClient.create(settings); + BatchAnnotateImagesResponse response = client.batchAnnotateImages(requests); + List responses = response.getResponsesList(); + + for (AnnotateImageResponse res : responses) { + if (res.hasError()) { + out.printf("Error: %s\n", res.getError().getMessage()); + return; + } + + // For full list of available annotations, see http://g.co/cloud/vision/docs + for (FaceAnnotation annotation : res.getFaceAnnotationsList()) { + out.printf("anger: %s\njoy: %s\nsurprise: %s\nposition: %s", + annotation.getAngerLikelihood(), + annotation.getJoyLikelihood(), + annotation.getSurpriseLikelihood(), + annotation.getBoundingPoly()); + } + } + } + + /** + * Detects labels in the specified local image. * @param filePath The path to the file to perform label detection on. * @param out A {@link PrintStream} to write detected labels to. * @throws IOException on Input/Output errors. @@ -205,7 +255,41 @@ public static void detectLabels(String filePath, PrintStream out) throws IOExcep } /** - * Detects landmarks in the specified image. + * Detects labels in the specified remote image. + * @param gcsPath The path to the remote file to perform label detection on. + * @param out A {@link PrintStream} to write detected features to. + * @throws IOException on Input/Output errors. + */ + public static void detectLabelsGcs(String gcsPath, PrintStream out) throws IOException { + List requests = new ArrayList<>(); + + ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build(); + Image img = Image.newBuilder().setSource(imgSource).build(); + Feature feat = Feature.newBuilder().setType(Type.LABEL_DETECTION).build(); + AnnotateImageRequest request = AnnotateImageRequest.newBuilder() + .addFeatures(feat) + .setImage(img) + .build(); + requests.add(request); + + BatchAnnotateImagesResponse response = visionApi.batchAnnotateImages(requests); + List responses = response.getResponsesList(); + + for (AnnotateImageResponse res : responses) { + if (res.hasError()) { + out.printf("Error: %s\n", res.getError().getMessage()); + return; + } + + // For full list of available annotations, see http://g.co/cloud/vision/docs + for (EntityAnnotation annotation : res.getLabelAnnotationsList()) { + annotation.getAllFields().forEach((k, v)->out.printf("%s : %s\n", k, v.toString())); + } + } + } + + /** + * Detects landmarks in the specified local image. * @param filePath The path to the file to perform landmark detection on. * @param out A {@link PrintStream} to write detected landmarks to. * @throws IOException on Input/Output errors. @@ -240,8 +324,43 @@ public static void detectLandmarks(String filePath, PrintStream out) throws IOEx } /** - * Detects logos in the specified image. - * @param filePath The path to the file to perform logo detection on. + * Detects landmarks in the specified remote image. + * @param gcsPath The path to the remote file to perform landmark detection on. + * @param out A {@link PrintStream} to write detected landmarks to. + * @throws IOException on Input/Output errors. + */ + public static void detectLandmarksGcs(String gcsPath, PrintStream out) throws IOException { + List requests = new ArrayList<>(); + + ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build(); + Image img = Image.newBuilder().setSource(imgSource).build(); + Feature feat = Feature.newBuilder().setType(Type.LANDMARK_DETECTION).build(); + AnnotateImageRequest request = AnnotateImageRequest.newBuilder() + .addFeatures(feat) + .setImage(img) + .build(); + requests.add(request); + + BatchAnnotateImagesResponse response = visionApi.batchAnnotateImages(requests); + List responses = response.getResponsesList(); + + for (AnnotateImageResponse res : responses) { + if (res.hasError()) { + out.printf("Error: %s\n", res.getError().getMessage()); + return; + } + + // For full list of available annotations, see http://g.co/cloud/vision/docs + for (EntityAnnotation annotation : res.getLandmarkAnnotationsList()) { + LocationInfo info = annotation.getLocationsList().listIterator().next(); + out.printf("Landmark: %s\n %s\n", annotation.getDescription(), info.getLatLng()); + } + } + } + + /** + * Detects logos in the specified local image. + * @param filePath The path to the local file to perform logo detection on. * @param out A {@link PrintStream} to write detected logos to. * @throws IOException on Input/Output errors. */ @@ -274,6 +393,41 @@ public static void detectLogos(String filePath, PrintStream out) throws IOExcept } } + /** + * Detects logos in the specified remote image. + * @param gcsPath The path to the remote file to perform logo detection on. + * @param out A {@link PrintStream} to write detected logos to. + * @throws IOException on Input/Output errors. + */ + public static void detectLogosGcs(String gcsPath, PrintStream out) throws IOException { + List requests = new ArrayList<>(); + + ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build(); + Image img = Image.newBuilder().setSource(imgSource).build(); + Feature feat = Feature.newBuilder().setType(Type.LOGO_DETECTION).build(); + AnnotateImageRequest request = AnnotateImageRequest.newBuilder() + .addFeatures(feat) + .setImage(img) + .build(); + requests.add(request); + + BatchAnnotateImagesResponse response = visionApi.batchAnnotateImages(requests); + List responses = response.getResponsesList(); + + for (AnnotateImageResponse res : responses) { + if (res.hasError()) { + out.printf("Error: %s\n", res.getError().getMessage()); + return; + } + + // For full list of available annotations, see http://g.co/cloud/vision/docs + for (EntityAnnotation annotation : res.getLogoAnnotationsList()) { + out.println(annotation.getDescription()); + } + } + } + + /** * Detects text in the specified image. * @param filePath The path to the file to detect text in. @@ -311,7 +465,42 @@ public static void detectText(String filePath, PrintStream out) throws IOExcepti } /** - * Detects image properties such as color frequency from the specified image. + * Detects text in the specified remote image. + * @param gcsPath The path to the remote file to detect text in. + * @param out A {@link PrintStream} to write the detected text to. + * @throws IOException on Input/Output errors. + */ + public static void detectTextGcs(String gcsPath, PrintStream out) throws IOException { + List requests = new ArrayList<>(); + + ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build(); + Image img = Image.newBuilder().setSource(imgSource).build(); + Feature feat = Feature.newBuilder().setType(Type.TEXT_DETECTION).build(); + AnnotateImageRequest request = AnnotateImageRequest.newBuilder() + .addFeatures(feat) + .setImage(img) + .build(); + requests.add(request); + + BatchAnnotateImagesResponse response = visionApi.batchAnnotateImages(requests); + List responses = response.getResponsesList(); + + for (AnnotateImageResponse res : responses) { + if (res.hasError()) { + out.printf("Error: %s\n", res.getError().getMessage()); + return; + } + + // For full list of available annotations, see http://g.co/cloud/vision/docs + for (EntityAnnotation annotation : res.getTextAnnotationsList()) { + out.printf("Text: %s\n", annotation.getDescription()); + out.printf("Position : %s\n", annotation.getBoundingPoly()); + } + } + } + + /** + * Detects image properties such as color frequency from the specified local image. * @param filePath The path to the file to detect properties. * @param out A {@link PrintStream} to write * @throws IOException on Input/Output errors. @@ -350,9 +539,49 @@ public static void detectProperties(String filePath, PrintStream out) throws IOE } } + /** + * Detects image properties such as color frequency from the specified remote image. + * @param gcsPath The path to the remote file to detect properties on. + * @param out A {@link PrintStream} to write + * @throws IOException on Input/Output errors. + */ + public static void detectPropertiesGcs(String gcsPath, PrintStream out) throws IOException { + List requests = new ArrayList<>(); + + ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build(); + Image img = Image.newBuilder().setSource(imgSource).build(); + Feature feat = Feature.newBuilder().setType(Type.IMAGE_PROPERTIES).build(); + AnnotateImageRequest request = AnnotateImageRequest.newBuilder() + .addFeatures(feat) + .setImage(img) + .build(); + requests.add(request); + + BatchAnnotateImagesResponse response = visionApi.batchAnnotateImages(requests); + List responses = response.getResponsesList(); + + for (AnnotateImageResponse res : responses) { + if (res.hasError()) { + out.printf("Error: %s\n", res.getError().getMessage()); + return; + } + + // For full list of available annotations, see http://g.co/cloud/vision/docs + DominantColorsAnnotation colors = res.getImagePropertiesAnnotation().getDominantColors(); + for (ColorInfo color : colors.getColorsList()) { + out.printf("fraction: %f\nr: %f, g: %f, b: %f\n", + color.getPixelFraction(), + color.getColor().getRed(), + color.getColor().getGreen(), + color.getColor().getBlue()); + } + } + } + + /** * Detects whether the specified image has features you would want to moderate. - * @param filePath The path to the file used for safe search detection. + * @param filePath The path to the local file used for safe search detection. * @param out A {@link PrintStream} to write the results to. * @throws IOException on Input/Output errors. */ @@ -387,4 +616,41 @@ public static void detectSafeSearch(String filePath, PrintStream out) throws IOE annotation.getViolence()); } } + + /** + * Detects whether the specified remote image has features you would want to moderate. + * @param gcsPath The path to the remote file to detect safe-search on. + * @param out A {@link PrintStream} to write the results to. + * @throws IOException on Input/Output errors. + */ + public static void detectSafeSearchGcs(String gcsPath, PrintStream out) throws IOException { + List requests = new ArrayList<>(); + + ImageSource imgSource = ImageSource.newBuilder().setGcsImageUri(gcsPath).build(); + Image img = Image.newBuilder().setSource(imgSource).build(); + Feature feat = Feature.newBuilder().setType(Type.SAFE_SEARCH_DETECTION).build(); + AnnotateImageRequest request = AnnotateImageRequest.newBuilder() + .addFeatures(feat) + .setImage(img) + .build(); + requests.add(request); + + BatchAnnotateImagesResponse response = visionApi.batchAnnotateImages(requests); + List responses = response.getResponsesList(); + + for (AnnotateImageResponse res : responses) { + if (res.hasError()) { + out.printf("Error: %s\n", res.getError().getMessage()); + return; + } + + // For full list of available annotations, see http://g.co/cloud/vision/docs + SafeSearchAnnotation annotation = res.getSafeSearchAnnotation(); + out.printf("adult: %s\nmedical: %s\nspoofed: %s\nviolence: %s\n", + annotation.getAdult(), + annotation.getMedical(), + annotation.getSpoof(), + annotation.getViolence()); + } + } } diff --git a/vision/cloud-client/src/test/java/com/example/vision/DetectIT.java b/vision/cloud-client/src/test/java/com/example/vision/DetectIT.java index 06af01b940e..0bcf8afb027 100644 --- a/vision/cloud-client/src/test/java/com/example/vision/DetectIT.java +++ b/vision/cloud-client/src/test/java/com/example/vision/DetectIT.java @@ -76,6 +76,19 @@ public void testFaces() throws Exception { assertThat(got).contains("joy: POSSIBLE"); assertThat(got).contains("surprise: UNLIKELY"); } + + @Test + public void testFacesGcs() throws Exception { + // Act + String[] args = {"faces", "gs://cloud-samples-tests/vision/face_no_surprise.jpg"}; + Detect.argsHelper(args, out); + + // Assert + String got = bout.toString(); + assertThat(got).contains("anger: POSSIBLE"); + assertThat(got).contains("joy: POSSIBLE"); + assertThat(got).contains("surprise: UNLIKELY"); + } @Test public void testLabels() throws Exception { @@ -87,6 +100,17 @@ public void testLabels() throws Exception { String got = bout.toString(); assertThat(got).contains("whiskers"); } + + @Test + public void testLabelsGcs() throws Exception { + // Act + String[] args = {"labels", "gs://cloud-samples-tests/vision/wakeupcat.jpg"}; + Detect.argsHelper(args, out); + + // Assert + String got = bout.toString(); + assertThat(got).contains("whiskers"); + } @Test public void testLandmarks() throws Exception { @@ -99,6 +123,17 @@ public void testLandmarks() throws Exception { assertThat(got).contains("Palace of Fine Arts"); } + @Test + public void testLandmarksGcs() throws Exception { + // Act + String[] args = {"landmarks", "gs://cloud-samples-tests/vision/landmark.jpg"}; + Detect.argsHelper(args, out); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Palace of Fine Arts"); + } + @Test public void testLogos() throws Exception { // Act @@ -110,6 +145,17 @@ public void testLogos() throws Exception { assertThat(got).contains("Google"); } + @Test + public void testLogosGcs() throws Exception { + // Act + String[] args = {"logos", "gs://cloud-samples-tests/vision/logos.png"}; + Detect.argsHelper(args, out); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Google"); + } + @Test public void testText() throws Exception { // Act @@ -121,6 +167,17 @@ public void testText() throws Exception { assertThat(got).contains("37%"); } + @Test + public void testTextGcs() throws Exception { + // Act + String[] args = {"text", "gs://cloud-samples-tests/vision/text.jpg"}; + Detect.argsHelper(args, out); + + // Assert + String got = bout.toString(); + assertThat(got).contains("37%"); + } + @Test public void testSafeSearch() throws Exception { // Act @@ -132,6 +189,17 @@ public void testSafeSearch() throws Exception { assertThat(got).contains("adult: VERY_UNLIKELY"); } + @Test + public void testSafeSearchGcs() throws Exception { + // Act + String[] args = {"safe-search", "gs://cloud-samples-tests/vision/wakeupcat.jpg"}; + Detect.argsHelper(args, out); + + // Assert + String got = bout.toString(); + assertThat(got).contains("adult: VERY_UNLIKELY"); + } + @Test public void testProperties() throws Exception { // Act @@ -145,4 +213,18 @@ public void testProperties() throws Exception { assertThat(got).contains("g:"); assertThat(got).contains("b:"); } + + @Test + public void testPropertiesGcs() throws Exception { + // Act + String[] args = {"properties", "gs://cloud-samples-tests/vision/landmark.jpg"}; + Detect.argsHelper(args, out); + + // Assert + String got = bout.toString(); + assertThat(got).contains("fraction:"); + assertThat(got).contains("r:"); + assertThat(got).contains("g:"); + assertThat(got).contains("b:"); + } }