Tensorflow functions and applications

* initial step
 * Tensorflow models functional model redesign

      -- Based on https://tzolov.github.io/mind-model-services
      -- Resolves #5

 * Add object detection processor README
 * Add image recognition processor README
 * Initial Tensorflow commonn README
 * Initial Tensorflow commonn README
 * Tensorflow common diagram
 * Tensorflow docs code
 * Tensorflow docs code snippets improve
 * Tensorflow docs code snippets improve
 * Tensorflow docs code snippets improve
 * Tensorflow docs code snippets improve
 * Add semantic segmentation function. add object detecteion function readme
 * oo images
 * Furether oo readme improvments
 * Final obj detection readme fixes
 * Add image recognition readme
 * Add image recognition readme 2
 * Semantic segmentation readme
 * Segmentation readme
 * Semantic segmentation readme 3
 * Fix image recognition and object detcion app starter dependecies

 * Add metadata for Tensorflow apps
This commit is contained in:
Christian Tzolov
2020-06-11 17:07:44 +02:00
committed by Soby Chacko
parent 3bb9e066b9
commit dffb467da4
66 changed files with 10300 additions and 1 deletions

View File

@@ -0,0 +1,272 @@
/*
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.fn.image.recognition;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.tensorflow.Operand;
import org.tensorflow.Tensor;
import org.tensorflow.op.core.Placeholder;
import org.tensorflow.op.image.DecodeJpeg;
import org.tensorflow.op.nn.TopK;
import org.springframework.cloud.fn.common.tensorflow.GraphRunner;
import org.springframework.cloud.fn.common.tensorflow.GraphRunnerMemory;
import org.springframework.cloud.fn.common.tensorflow.ProtoBufGraphDefinition;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;
/**
* @author Christian Tzolov
*/
public class ImageRecognition implements AutoCloseable {
private final List<String> labels;
private final GraphRunner imageNormalization;
private final GraphRunner imageRecognition;
private final GraphRunner maxProbability;
private final GraphRunner topKProbabilities;
/**
* Instead of creating the {@link ImageRecognition} service explicitly via the constructor,
* you should consider the convenience factory methods below. E.g.
*
* {@link #inception(String, int, int, boolean)}
* {@link #mobileNetV1(String, int, int, boolean)}
* {@link #mobileNetV2(String, int, int, boolean)}
*
* @param modelUri location of the pre-trained model to use.
* @param labelsUri location of the list fromMemory pre-trained categories used by the model.
* @param imageRecognitionGraphInputName name of the Model's input node to send the input image to.
* @param imageRecognitionGraphOutputName name of the Model's output node to retrieve the predictions from.
* @param imageHeight normalized image height.
* @param imageWidth normalized image width.
* @param mean mean value to normalize the input image.
* @param scale scale to normalize the input image.
* @param responseSize Max number of predictions per recognize.
* @param cacheModel if true the pre-trained model is cached on the local file system.
*/
public ImageRecognition(String modelUri, String labelsUri, int imageHeight, int imageWidth, float mean, float scale,
String imageRecognitionGraphInputName, String imageRecognitionGraphOutputName, int responseSize, boolean cacheModel) {
this.labels = labels(labelsUri);
/**
* Normalizes the raw input image into format expected by the pre-trained Inception/MobileNetV1/MobileNetV2 models.
* Typically the model is trained fromMemory images scaled to certain size. Usually it is 224x224 pixels, but can be
* also 192x192, 160x160, 128128, 92x92. Use the (imageHeight, imageWidth) to set the desired size.
* The colors, represented as R, G, B in 1-byte each were converted to float using (Value - Mean)/Scale.
*
* imageHeight normalized image height.
* imageWidth normalized image width.
* mean mean value to normalize the input image.
* scale scale to normalize the input image.
*/
this.imageNormalization = new GraphRunner("raw_image", "normalized_image")
.withGraphDefinition(tf -> {
Placeholder<String> input = tf.withName("raw_image").placeholder(String.class);
final Operand<Float> decodedImage =
tf.dtypes.cast(tf.image.decodeJpeg(input, DecodeJpeg.channels(3L)), Float.class);
final Operand<Float> resizedImage = tf.image.resizeBilinear(
tf.expandDims(decodedImage, tf.constant(0)),
tf.constant(new int[] { imageHeight, imageWidth }));
tf.withName("normalized_image").math.div(tf.math.sub(resizedImage, tf.constant(mean)), tf.constant(scale));
});
this.imageRecognition = new GraphRunner(imageRecognitionGraphInputName, imageRecognitionGraphOutputName)
.withGraphDefinition(new ProtoBufGraphDefinition(toResource(modelUri), cacheModel));
this.maxProbability = new GraphRunner(Arrays.asList("recognition_result"), Arrays.asList("category", "probability"))
.withGraphDefinition(tf -> {
Placeholder<Float> input = tf.withName("recognition_result").placeholder(Float.class);
tf.withName("category").math.argMax(input, tf.constant(1));
tf.withName("probability").max(input, tf.constant(1));
});
this.topKProbabilities = new GraphRunner("recognition_result", "topK")
.withGraphDefinition(tf -> {
Placeholder<Float> input = tf.withName("recognition_result").placeholder(Float.class);
tf.withName("topK").nn.topK(input, tf.constant(responseSize), TopK.sorted(true));
});
}
/**
* Takes an byte encoded image and returns the most probable category recognized in the image along fromMemory its probability.
* @param inputImage Byte array encoded image to recognize.
* @return Returns a single map entry containing the names of the recognized categories as key and the confidence as value.
*/
public Map<String, Double> recognizeMax(byte[] inputImage) {
try (Tensor inputTensor = Tensor.create(inputImage); GraphRunnerMemory memorize = new GraphRunnerMemory()) {
Map<String, Tensor<?>> max = this.imageNormalization.andThen(memorize)
.andThen(this.imageRecognition).andThen(memorize)
.andThen(this.maxProbability).andThen(memorize)
.apply(Collections.singletonMap("raw_image", inputTensor));
long[] category = new long[1];
max.get("category").copyTo(category);
float[] probability = new float[1];
max.get("probability").copyTo(probability);
return Collections.singletonMap(labels.get((int) category[0]), Double.valueOf(probability[0]));
}
}
/**
* Takes an byte encoded input image and returns the top K most probable categories recognized in the image
* along fromMemory their probabilities.
*
* @param inputImage Byte array encoded image to recognize.
* @return Returns a list of key-value pairs. Every key-value pair represents a single category recognized.
* The key stands for the name(s) of the category while the value states the confidence that there is an
* object of this category. The entries in the Map are ordered from the higher to the lower confidences.
*/
public Map<String, Double> recognizeTopK(byte[] inputImage) {
try (Tensor inputTensor = Tensor.create(inputImage); GraphRunnerMemory memorize = new GraphRunnerMemory()) {
Map<String, Tensor<?>> topKResults =
this.imageNormalization.andThen(memorize)
.andThen(this.imageRecognition).andThen(memorize)
.andThen(this.topKProbabilities).andThen(memorize)
.apply(Collections.singletonMap("raw_image", inputTensor));
Tensor recognizedImagesTensor = memorize.getTensorMap().get(this.imageRecognition.getSingleFetchName());
float[][] results = new float[(int) recognizedImagesTensor.shape()[0]][(int) recognizedImagesTensor.shape()[1]];
recognizedImagesTensor.copyTo(results);
Tensor<Float> topKTensor = topKResults.get("topK").expect(Float.class);
float[][] topK = new float[(int) topKTensor.shape()[0]][(int) topKTensor.shape()[1]];
topKTensor.copyTo(topK);
float min = topK[0][topK[0].length - 1];
Map<Float, Integer> valueToIndex = new HashMap<>();
for (int i = 0; i < results[0].length; i++) {
if (results[0][i] >= min) {
valueToIndex.put(results[0][i], i);
}
}
Map<String, Double> map = new LinkedHashMap<>();
for (float tk : topK[0]) {
map.put(labels.get(valueToIndex.get(tk)), (double) tk);
}
return map;
}
}
private Resource toResource(String uri) {
return new DefaultResourceLoader().getResource(uri);
}
/**
* Converts a labels resources into string list.
* @return Returns string lists. One line per different category.
*/
private List<String> labels(String labelsUri) {
try (InputStream is = toResource(labelsUri).getInputStream()) {
return Arrays.asList(StreamUtils.copyToString(is, Charset.forName("UTF-8")).split("\n"));
}
catch (IOException e) {
throw new RuntimeException("Failed to initialize the Vocabulary", e);
}
}
/**
*
* The Inception graph uses "input" as input and "output" as output.
*
*/
public static ImageRecognition inception(String inceptionModelUri,
int normalizedImageSize, int responseSize, boolean cacheModel) {
return new ImageRecognition(inceptionModelUri, "classpath:/labels/inception_labels.txt",
normalizedImageSize, normalizedImageSize, 117f, 1f,
"input", "output",
responseSize, cacheModel);
}
/**
* Convenience for MobileNetV2 pre-trained models:
* https://github.com/tensorflow/models/tree/master/research/slim/nets/mobilenet#pretrained-models
*
* The normalized image size is always square (e.g. H=W)
*
* The MobileNetV2 graph uses "input" as input and "MobilenetV2/Predictions/Reshape_1" as output.
*
* @param mobileNetV2ModelUri model uri
* @param normalizedImageSize Depends on the pre-trained model used. Usually 224px is used.
* @param responseSize Number of responses fot topK requests.
* @param cacheModel cache model
* @return ImageRecognition instance configured fromMemory a MobileNetV2 pre-trained model.
*/
public static ImageRecognition mobileNetV2(String mobileNetV2ModelUri,
int normalizedImageSize, int responseSize, boolean cacheModel) {
return new ImageRecognition(mobileNetV2ModelUri, "classpath:/labels/mobilenet_labels.txt",
normalizedImageSize, normalizedImageSize, 0f, 127f,
"input", "MobilenetV2/Predictions/Reshape_1",
responseSize, cacheModel);
}
/**
* Convenience for MobileNetV1 pre-trained models:
* https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.md#pre-trained-models
*
* The MobileNetV1 graph uses "input" as input and "MobilenetV1/Predictions/Reshape_1" as output.
*
*/
public static ImageRecognition mobileNetV1(String mobileNetV1ModelUri,
int normalizedImageSize, int responseSize, boolean cacheModel) {
return new ImageRecognition(mobileNetV1ModelUri, "classpath:/labels/mobilenet_labels.txt",
normalizedImageSize, normalizedImageSize,
0f, 127f,
"input", "MobilenetV1/Predictions/Reshape_1",
responseSize, cacheModel);
}
/**
* Convert image recognition results into {@link RecognitionResponse} domain list.
* @param recognitionMap map containing the category mames and its probability. Returned by the
* {@link ImageRecognition#recognizeMax(byte[])} and the ImageRecognition{@link #recognizeTopK(byte[])} methods
* @return List of {@link RecognitionResponse} objects representing the name-to-probability pairs in the input map.
*/
public static List<RecognitionResponse> toRecognitionResponse(Map<String, Double> recognitionMap) {
return recognitionMap.entrySet().stream()
.map(nameProbabilityPair -> new RecognitionResponse(nameProbabilityPair.getKey(), nameProbabilityPair.getValue()))
.collect(Collectors.toList());
}
@Override
public void close() {
this.imageNormalization.close();
this.imageRecognition.close();
this.maxProbability.close();
this.topKProbabilities.close();
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.fn.image.recognition;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.function.BiFunction;
import javax.imageio.ImageIO;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Ability to to augment the input image fromMemory the recognized labels.
*
* @author Christian Tzolov
*/
public class ImageRecognitionAugmenter implements BiFunction<byte[], List<RecognitionResponse>, byte[]> {
private static final Log logger = LogFactory.getLog(ImageRecognitionAugmenter.class);
/** IMAGE_FORMAT. */
public static final String IMAGE_FORMAT = "jpg";
private final Color textColor = Color.BLACK;
private final Color bgColor = new Color(167, 252, 0);
public ImageRecognitionAugmenter() {
}
/**
* Augment the input image by adding the recognized classes.
*
* @param imageBytes input image as byte array
* @param result computed recognition labels
* @return the image augmented fromMemory recognized labels.
*/
@Override
public byte[] apply(byte[] imageBytes, List<RecognitionResponse> result) {
try {
if (result != null) {
BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
Graphics2D g = originalImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
FontMetrics fm = g.getFontMetrics();
int x = 1;
int y = 1;
for (RecognitionResponse r : result) {
String labelName = r.getLabel();
int probability = (int) (100 * r.getProbability());
String title = labelName + ": " + probability + "%";
Rectangle2D rect = fm.getStringBounds(title, g);
g.setColor(bgColor);
g.fillRect(x, y, (int) rect.getWidth() + 6, (int) rect.getHeight());
g.setColor(textColor);
g.drawString(title, x + 3, (int) (y + rect.getHeight() - 3));
y = (int) (y + rect.getHeight() + 1);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage, IMAGE_FORMAT, baos);
baos.flush();
imageBytes = baos.toByteArray();
baos.close();
}
}
catch (IOException e) {
logger.error("Failed to draw labels in the input image", e);
}
return imageBytes;
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.fn.image.recognition;
/**
* @author Christian Tzolov
*/
public class RecognitionResponse {
private String label;
private Double probability;
public RecognitionResponse() {
}
public RecognitionResponse(String label, Double probability) {
this.label = label;
this.probability = probability;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public Double getProbability() {
return probability;
}
public void setProbability(Double probability) {
this.probability = probability;
}
@Override
public String toString() {
return "{label='" + label + ", probability=" + probability + '}';
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.fn.image.recognition.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
/**
* Create a text file mapping label id to human readable string.
*
* Produces a text file where every line represents single category. The line number represents the category id, while
* the line text is human-readable names for the categories fromMemory this imagenet id.
*
* Based on https://github.com/tensorflow/models/blob/master/research/slim/datasets/imagenet.py#L66
*
* We retrieve a synset file, which contains a list of valid synset labels used
* by ILSVRC competition. There is one synset one per line, eg.
* # n01440764
* # n01443537
* We also retrieve a synset_to_human_file, which contains a mapping from synsets
* to human-readable names for every synset in Imagenet. These are stored in a
* tsv format, as follows:
* # n02119247 black fox
* # n02119359 silver fox
* We assign each synset (in alphabetical order) an integer, starting from 1
* (since 0 is reserved for the background class)
*
* @author Christian Tzolov
*/
public final class ImageNetReadableNamesWriter {
private ImageNetReadableNamesWriter() {
}
/** BASE_URL. */
public final static String BASE_URL = "https://raw.githubusercontent.com/tensorflow/models/master/research/inception/inception/data/";
/** SYNSET_URI. */
public final static String SYNSET_URI = BASE_URL + "imagenet_lsvrc_2015_synsets.txt";
/** SYNSET_TO_HUMAN_URI. */
public final static String SYNSET_TO_HUMAN_URI = BASE_URL + "imagenet_metadata.txt";
public static void main(String[] args) {
Charset utf8 = Charset.forName("UTF-8");
try (InputStream synsetIs = toResource(SYNSET_URI).getInputStream();
InputStream synsetToHumanIs = toResource(SYNSET_TO_HUMAN_URI).getInputStream()) {
List<String> synsetList = Arrays.asList(StreamUtils.copyToString(synsetIs, utf8)
.split("\n")).stream().map(l -> l.trim()).collect(Collectors.toList());
Assert.notNull(synsetList, "Failed to initialize the labels list");
Assert.isTrue(synsetList.size() == 1000, "Labels list is expected to be of " +
"size 1000 but was:" + synsetList.size());
Map<String, String> synsetToHuman = Arrays.asList(StreamUtils.copyToString(synsetToHumanIs, utf8)
.split("\n")).stream().map(s2h -> s2h.split("\t")).collect(Collectors.toMap(s -> s[0], s -> s[1]));
Assert.notNull(synsetToHuman, "Failed to initialize the synsetToHuman");
Assert.isTrue(synsetToHuman.size() == 21842, "synsetToHuman is expected to be of " +
"size 21842 but was:" + synsetToHuman.size());
List<String> l = synsetList.stream().map(id -> synsetToHuman.get(id)).collect(Collectors.toList());
List<String> ll = new ArrayList<>();
ll.add("dummy");
ll.addAll(l);
System.out.println(ll.get(389));
FileUtils.writeLines(new File("labels.txt"), ll);
}
catch (IOException e) {
throw new RuntimeException("Failed to initialize the Vocabulary", e);
}
}
public static Resource toResource(String uri) {
return new DefaultResourceLoader().getResource(uri);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.fn.image.recognition;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.springframework.cloud.fn.common.tensorflow.deprecated.GraphicsUtils;
import org.springframework.cloud.fn.common.tensorflow.deprecated.JsonMapperFunction;
/**
* @author Christian Tzolov
*/
public final class ImageRecognitionExample {
private ImageRecognitionExample() {
}
public static void main(String[] args) throws IOException {
// You can use file:, http: or classpath: to provide the path to the input image.
byte[] inputImage = GraphicsUtils.loadAsByteArray("classpath:/images/giant_panda_in_beijing_zoo_1.jpg");
// MmobileNetV2 models
// https://github.com/tensorflow/models/tree/master/research/slim/nets/mobilenet#pretrained-models
String mobilenet_v2_modelUri = "https://storage.googleapis.com/mobilenet_v2/checkpoints/mobilenet_v2_1.4_224.tgz#mobilenet_v2_1.4_224_frozen.pb";
//String mobilenet_v2_modelUri = "https://storage.googleapis.com/mobilenet_v2/checkpoints/mobilenet_v2_0.35_96.tgz#mobilenet_v2_0.35_96_frozen.pb";
try (ImageRecognition imageRecognition = ImageRecognition.mobileNetV2(
mobilenet_v2_modelUri,
224,
5,
true)) {
List<RecognitionResponse> recognizedObjects =
ImageRecognition.toRecognitionResponse(imageRecognition.recognizeTopK(inputImage));
// Draw the predicted labels on top of the input image.
byte[] augmentedImage = new ImageRecognitionAugmenter().apply(inputImage, recognizedObjects);
IOUtils.write(augmentedImage, new FileOutputStream("./image-recognition/target/image-augmented-mobilnetV2.jpg"));
String jsonRecognizedObjects = new JsonMapperFunction().apply(recognizedObjects);
System.out.println("mobilnetV2 result:" + jsonRecognizedObjects);
}
String mobilenet_v1_modelUri = "https://download.tensorflow.org/models/mobilenet_v1_2018_08_02/mobilenet_v1_1.0_224.tgz#mobilenet_v1_1.0_224_frozen.pb";
try (ImageRecognition recognitionService = ImageRecognition.mobileNetV1(
mobilenet_v1_modelUri,
224,
5,
true)) {
List<RecognitionResponse> recognizedObjects =
ImageRecognition.toRecognitionResponse(recognitionService.recognizeTopK(inputImage));
// Draw the predicted labels on top of the input image.
byte[] augmentedImage = new ImageRecognitionAugmenter().apply(inputImage, recognizedObjects);
IOUtils.write(augmentedImage, new FileOutputStream("./image-recognition/target/image-augmented-mobilnetV1.jpg"));
String jsonRecognizedObjects = new JsonMapperFunction().apply(recognizedObjects);
System.out.println("mobilnetV1 result:" + jsonRecognizedObjects);
}
String inception_modelUri = "https://storage.googleapis.com/scdf-tensorflow-models/image-recognition/tensorflow_inception_graph.pb";
try (ImageRecognition recognitionService = ImageRecognition.inception(
inception_modelUri,
224,
5,
true)) {
List<RecognitionResponse> recognizedObjects =
ImageRecognition.toRecognitionResponse(recognitionService.recognizeTopK(inputImage));
// Draw the predicted labels on top of the input image.
byte[] augmentedImage = new ImageRecognitionAugmenter().apply(inputImage, recognizedObjects);
IOUtils.write(augmentedImage, new FileOutputStream("./image-recognition/target/image-augmented-inception.jpg"));
String jsonRecognizedObjects = new JsonMapperFunction().apply(recognizedObjects);
System.out.println("inception result:" + jsonRecognizedObjects);
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.fn.image.recognition;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import org.springframework.cloud.fn.common.tensorflow.deprecated.GraphicsUtils;
/**
* @author Christian Tzolov
*/
public final class ImageRecognitionExample2 {
private ImageRecognitionExample2() {
}
public static void main(String[] args) throws IOException {
ImageRecognitionAugmenter augmenter = new ImageRecognitionAugmenter();
byte[] inputImage = GraphicsUtils.loadAsByteArray("classpath:/images/giant_panda_in_beijing_zoo_1.jpg");
ImageRecognition inceptions = ImageRecognition.inception(
"https://storage.googleapis.com/scdf-tensorflow-models/image-recognition/tensorflow_inception_graph.pb",
224, 10, true);
System.out.println(inceptions.recognizeMax(inputImage));
System.out.println(inceptions.recognizeTopK(inputImage));
System.out.println(ImageRecognition.toRecognitionResponse(inceptions.recognizeTopK(inputImage)));
IOUtils.write(augmenter.apply(inputImage, ImageRecognition.toRecognitionResponse(inceptions.recognizeTopK(inputImage))),
new FileOutputStream("./functions/function/image-recognition-function/target/image-augmented-inceptions.jpg"));
inceptions.close();
ImageRecognition mobileNetV2 = ImageRecognition.mobileNetV2(
"https://storage.googleapis.com/mobilenet_v2/checkpoints/mobilenet_v2_1.4_224.tgz#mobilenet_v2_1.4_224_frozen.pb",
224, 10, true);
System.out.println(mobileNetV2.recognizeMax(inputImage));
System.out.println(mobileNetV2.recognizeTopK(inputImage));
IOUtils.write(augmenter.apply(inputImage, ImageRecognition.toRecognitionResponse(mobileNetV2.recognizeTopK(inputImage))),
new FileOutputStream("./functions/function/image-recognition-function/target/image-augmented-mobilnetV2.jpg"));
mobileNetV2.close();
ImageRecognition mobileNetV1 = ImageRecognition.mobileNetV1(
"https://download.tensorflow.org/models/mobilenet_v1_2018_08_02/mobilenet_v1_1.0_224.tgz#mobilenet_v1_1.0_224_frozen.pb",
224, 10, true);
System.out.println(mobileNetV1.recognizeMax(inputImage));
System.out.println(mobileNetV1.recognizeTopK(inputImage));
IOUtils.write(augmenter.apply(inputImage, ImageRecognition.toRecognitionResponse(mobileNetV1.recognizeTopK(inputImage))),
new FileOutputStream("./functions/function/image-recognition-function/target/image-augmented-mobilnetV1.jpg"));
mobileNetV1.close();
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.fn.image.recognition;
import java.util.Map;
import com.google.protobuf.InvalidProtocolBufferException;
import org.tensorflow.SavedModelBundle;
import org.tensorflow.framework.MetaGraphDef;
import org.tensorflow.framework.SignatureDef;
/**
* @author Christian Tzolov
*/
public final class SavedModelTest {
private SavedModelTest() {
}
/**
* https://medium.com/@jsflo.dev/saving-and-loading-a-tensorflow-model-using-the-savedmodel-api-17645576527
*
* https://www.tensorflow.org/alpha/guide/saved_model
*
*/
public static void main(String[] args) throws InvalidProtocolBufferException {
SavedModelBundle savedModelBundle =
SavedModelBundle.load("/Users/ctzolov/Downloads/ssd_mobilenet_v1_coco_2017_11_17/saved_model", "serve");
//SavedModelBundle.load("/Users/ctzolov/Downloads/aiy_vision_classifier_plants_V1_1/", "serve");
//SavedModelBundle savedModelBundle =
// SavedModelBundle.load("/Users/ctzolov/Downloads/mnasnet-a1/saved_model", "serve");
MetaGraphDef meta = MetaGraphDef.parseFrom(savedModelBundle.metaGraphDef());
Map<String, SignatureDef> signatures = meta.getSignatureDefMap();
System.out.println(signatures);
savedModelBundle.session();
//Iterator<Operation> itr = savedModelBundle.graph().operations();
//
//while (itr.hasNext()) {
// System.out.println("Operation: " + itr.next());
//}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB