package org.myrobotlab.service; // FIXME ! loose the awt (can't work on Android !) import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.image.BufferedImage; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.ServiceType; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.Logging; import org.myrobotlab.logging.LoggingFactory; import org.slf4j.Logger; //[BEGIN import_libraries] import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.vision.v1.Vision; import com.google.api.services.vision.v1.VisionScopes; import com.google.api.services.vision.v1.model.AnnotateImageRequest; import com.google.api.services.vision.v1.model.AnnotateImageResponse; import com.google.api.services.vision.v1.model.BatchAnnotateImagesRequest; import com.google.api.services.vision.v1.model.BatchAnnotateImagesResponse; import com.google.api.services.vision.v1.model.EntityAnnotation; import com.google.api.services.vision.v1.model.FaceAnnotation; import com.google.api.services.vision.v1.model.Feature; import com.google.api.services.vision.v1.model.Image; import com.google.api.services.vision.v1.model.Vertex; import com.google.common.collect.ImmutableList; //[END import_libraries] public class GoogleCloud extends Service { private static final long serialVersionUID = 1L; final static Logger log = LoggerFactory.getLogger(GoogleCloud.class); /** * Be sure to specify the name of your application. If the application name is * {@code null} or blank, the application will log a warning. Suggested format * is "MyCompany-ProductName/1.0". */ private static final String APPLICATION_NAME = "Google-VisionFaceDetectSample/1.0"; transient Vision vision; int maxResults = 32; public GoogleCloud(String n) { super(n); } /** * This static method returns all the details of the class without it having * to be constructed. It has description, categories, dependencies, and peer * definitions. * * @return ServiceType - returns all the data * */ static public ServiceType getMetaData() { ServiceType meta = new ServiceType(GoogleCloud.class.getCanonicalName()); meta.addDescription("google api client service"); meta.setAvailable(true); // add dependency if necessary meta.addDependency("com.google.client", "1.22.0"); meta.addDependency("com.google.vision", "1.22.0"); meta.addCategory("cloud", "vision", "google"); return meta; } // [START main] /** * Annotates an image using the Vision API. */ // [END main] // [START get_vision_service] /** * Connects to the Vision API using Application Default Credentials. */ public Vision getVisionService(String credJsonFile) throws IOException, GeneralSecurityException { /* * GoogleCredential credential = new * GoogleCredential().setAccessToken(accessToken); Plus plus = new * Plus.builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), * credential) .setApplicationName("Google-PlusSample/1.0") .build(); */ GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(credJsonFile)).createScoped(VisionScopes.all()); /* * JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); * * HttpTransport httpTransport = * GoogleNetHttpTransport.newTrustedTransport(); * * InputStream inputStream = IOUtils.toInputStream(serviceAccountJson); * * GoogleCredential credential = GoogleCredential.fromStream(inputStream, * httpTransport, jsonFactory); * * credential = * credential.createScoped(Collections.singleton(AndroidPublisherScopes. * ANDROIDPUBLISHER)); * * AndroidPublisher androidPublisher = new AndroidPublisher(httpTransport, * jsonFactory, credential); */ // GoogleCredential credential = // GoogleCredential.getApplicationDefault().createScoped(VisionScopes.all()); JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); return new Vision.Builder(GoogleNetHttpTransport.newTrustedTransport(), jsonFactory, credential).setApplicationName(APPLICATION_NAME).build(); } // [END get_vision_service] public void connect(String credJsonFile) throws IOException, GeneralSecurityException { connect(getVisionService(credJsonFile)); } public void connect(Vision vision) { this.vision = vision; } // [START detect_face] public List<FaceAnnotation> detectFaces(String path) throws IOException { return detectFaces(Paths.get(path), maxResults); } public List<FaceAnnotation> detectFaces(Path path) throws IOException { return detectFaces(path, maxResults); } /** * Gets up to {@code maxResults} faces for an image stored at {@code path}. */ public List<FaceAnnotation> detectFaces(Path path, int maxResults) throws IOException { byte[] data = Files.readAllBytes(path); AnnotateImageRequest request = new AnnotateImageRequest().setImage(new Image().encodeContent(data)) .setFeatures(ImmutableList.of(new Feature().setType("FACE_DETECTION").setMaxResults(maxResults))); Vision.Images.Annotate annotate = vision.images().annotate(new BatchAnnotateImagesRequest().setRequests(ImmutableList.of(request))); // Due to a bug: requests to Vision API containing large images fail // when GZipped. annotate.setDisableGZipContent(true); BatchAnnotateImagesResponse batchResponse = annotate.execute(); assert batchResponse.getResponses().size() == 1; AnnotateImageResponse response = batchResponse.getResponses().get(0); if (response.getFaceAnnotations() == null) { throw new IOException(response.getError() != null ? response.getError().getMessage() : "Unknown error getting image annotations"); } return response.getFaceAnnotations(); } // [END detect_face] // [START highlight_faces] public void writeWithFaces(String inputPath, String outputPath, List<FaceAnnotation> faces) throws IOException { writeWithFaces(Paths.get(inputPath), Paths.get(outputPath), faces); } /** * Reads image {@code inputPath} and writes {@code outputPath} with * {@code faces} outlined. */ public void writeWithFaces(Path inputPath, Path outputPath, List<FaceAnnotation> faces) throws IOException { BufferedImage img = ImageIO.read(inputPath.toFile()); annotateWithFaces(img, faces); ImageIO.write(img, "jpg", outputPath.toFile()); } /** * Annotates an image {@code img} with a polygon around each face in * {@code faces}. */ public void annotateWithFaces(BufferedImage img, List<FaceAnnotation> faces) { for (FaceAnnotation face : faces) { annotateWithFace(img, face); } } /** * Annotates an image {@code img} with a polygon defined by {@code face}. */ private void annotateWithFace(BufferedImage img, FaceAnnotation face) { Graphics2D gfx = img.createGraphics(); Polygon poly = new Polygon(); for (Vertex vertex : face.getFdBoundingPoly().getVertices()) { poly.addPoint(vertex.getX(), vertex.getY()); } gfx.setStroke(new BasicStroke(5)); gfx.setColor(new Color(0x00ff00)); gfx.draw(poly); } // [END highlight_faces] /** * Prints the labels received from the Vision API. */ public void printLabels(PrintStream out, Path imagePath, List<EntityAnnotation> labels) { out.printf("Labels for image %s:\n", imagePath); for (EntityAnnotation label : labels) { out.printf("\t%s (score: %.3f)\n", label.getDescription(), label.getScore()); } if (labels.isEmpty()) { out.println("\tNo labels found."); } } public List<EntityAnnotation> labelImage(Path path) throws IOException { return labelImage(path, maxResults); } /** * Gets up to {@code maxResults} labels for an image stored at {@code path}. */ public List<EntityAnnotation> labelImage(Path path, int maxResults) throws IOException { // [START construct_request] byte[] data = Files.readAllBytes(path); AnnotateImageRequest request = new AnnotateImageRequest().setImage(new Image().encodeContent(data)) .setFeatures(ImmutableList.of(new Feature().setType("LABEL_DETECTION").setMaxResults(maxResults))); Vision.Images.Annotate annotate = vision.images().annotate(new BatchAnnotateImagesRequest().setRequests(ImmutableList.of(request))); // Due to a bug: requests to Vision API containing large images fail // when GZipped. // annotate.setDisableGZipContent(true); // [END construct_request] // [START parse_response] BatchAnnotateImagesResponse batchResponse = annotate.execute(); assert batchResponse.getResponses().size() == 1; AnnotateImageResponse response = batchResponse.getResponses().get(0); if (response.getLabelAnnotations() == null) { throw new IOException(response.getError() != null ? response.getError().getMessage() : "Unknown error getting image annotations"); } return response.getLabelAnnotations(); // [END parse_response] } public Map<String, Float> getLabels(String filename) throws IOException { LinkedHashMap<String, Float> ret = new LinkedHashMap<String, Float>(); byte[] data = Files.readAllBytes(Paths.get(filename)); AnnotateImageRequest request = new AnnotateImageRequest().setImage(new Image().encodeContent(data)) .setFeatures(ImmutableList.of(new Feature().setType("LABEL_DETECTION").setMaxResults(maxResults))); Vision.Images.Annotate annotate = vision.images().annotate(new BatchAnnotateImagesRequest().setRequests(ImmutableList.of(request))); // Due to a bug: requests to Vision API containing large images fail // when GZipped. // annotate.setDisableGZipContent(true); // [END construct_request] // [START parse_response] BatchAnnotateImagesResponse batchResponse = annotate.execute(); assert batchResponse.getResponses().size() == 1; AnnotateImageResponse response = batchResponse.getResponses().get(0); if (response.getLabelAnnotations() == null) { throw new IOException(response.getError() != null ? response.getError().getMessage() : "Unknown error getting image annotations"); } List<EntityAnnotation> labels = response.getLabelAnnotations(); log.info("Labels for image {}:", filename); for (EntityAnnotation label : labels) { String desc = label.getDescription(); Float score = label.getScore(); log.info("\t{} (score: {})", desc, score); ret.put(desc, score); } if (labels.isEmpty()) { log.info("\tNo labels found."); } return ret; } public static void main(String[] args) { try { LoggingFactory.getInstance().configure(); // LoggingFactory.getInstance().setLevel(Level.INFO); GoogleCloud google = (GoogleCloud) Runtime.start("google", "GoogleCloud"); // Runtime.start("gui", "GUIService"); if (args.length != 2) { System.err.println("Usage:"); System.err.printf("\tjava %s inputImagePath outputImagePath\n", GoogleCloud.class.getCanonicalName()); System.exit(1); } Path inputPath = Paths.get(args[0]); Path outputPath = Paths.get(args[1]); if (!outputPath.toString().toLowerCase().endsWith(".jpg")) { System.err.println("outputImagePath must have the file extension 'jpg'."); System.exit(1); } // "API Project-c90c3d12e7d3.json" // GoogleCloudService app = new // GoogleCloudService(getVisionService()); google.connect("../API Project-c90c3d12e7d3.json"); long ts = System.currentTimeMillis(); List<FaceAnnotation> faces = google.detectFaces(inputPath); System.out.printf("Found %d face%s\n", faces.size(), faces.size() == 1 ? "" : "s"); System.out.printf("Writing to file %s\n", outputPath); google.writeWithFaces(inputPath, outputPath, faces); google.getLabels("kitchen.jpg"); google.getLabels("plumbing.jpg"); google.getLabels("ship.jpg"); google.getLabels("greenball.jpg"); log.info("{} total ms", System.currentTimeMillis() - ts); } catch (Exception e) { Logging.logError(e); } } }