Back | Next | Contents
Image Classification
# Coding Your Own Image Recognition Program (Python)
In the previous step, we ran a sample application that came with the `jetson-inference` repo.
Now, we're going to walk through creating a new program from scratch in Python for image recognition called [`my-recognition.py`](../python/examples/my-recognition.py). This script will load an arbitrary image from disk and classify it using the [`imageNet`](https://rawgit.com/dusty-nv/jetson-inference/master/docs/html/python/jetson.inference.html#imageNet) object. The completed source at [`python/examples/my-recognition.py`](../python/examples/my-recognition.py)
``` python
#!/usr/bin/python3
import jetson.inference
import jetson.utils
import argparse
# parse the command line
parser = argparse.ArgumentParser()
parser.add_argument("filename", type=str, help="filename of the image to process")
parser.add_argument("--network", type=str, default="googlenet", help="model to use, can be: googlenet, resnet-18, ect.")
args = parser.parse_args()
# load an image (into shared CPU/GPU memory)
img = jetson.utils.loadImage(args.filename)
# load the recognition network
net = jetson.inference.imageNet(args.network)
# classify the image
class_idx, confidence = net.Classify(img)
# find the object description
class_desc = net.GetClassDesc(class_idx)
# print out the result
print("image is recognized as '{:s}' (class #{:d}) with {:f}% confidence".format(class_desc, class_idx, confidence * 100))
```
## Setting up the Project
If you're using the Docker container, you'll want to store your code in a [Mounted Directory](aux-docker.md#mounted-data-volumes). This way your code won't be lost when you shutdown the container. For simplicity, this guide will create it in a directory on your host device under the user's home directory located at `~/my-recognition-python`, and then mount that path into the container.
Run these commands from a terminal (outside of container) to create the directory, source file, and download some test images:
``` bash
# run these commands outside of container
$ cd ~/
$ mkdir my-recognition-python
$ cd my-recognition-python
$ touch my-recognition.py
$ chmod +x my-recognition.py
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/black_bear.jpg
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/brown_bear.jpg
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/polar_bear.jpg
```
Then when you start the container, [mount the directory](aux-docker.md#mounted-data-volumes) that you just created:
```bash
$ docker/run.sh --volume ~/my-recognition-python:/my-recognition-python # mounted inside the container to /my-recognition-python
```
Next, we'll add the Python code for the program to the empty source file we created here.
## Source Code
Open up `my-recognition.py` in your editor of choice (or run `gedit my-recognition.py`). You can edit from outside the container.
First, let's add a shebang sequence to the very top of the file to automatically use the Python interpreter:
``` python
#!/usr/bin/python3
```
Next, we'll import the Python modules that we're going to use in the script.
#### Importing Modules
Add `import` statements to load the [`jetson.inference`](https://rawgit.com/dusty-nv/jetson-inference/master/docs/html/python/jetson.inference.html) and [`jetson.utils`](https://rawgit.com/dusty-nv/jetson-inference/master/docs/html/python/jetson.utils.html) modules used for recognizing images and image loading. We'll also load the standard `argparse` package for parsing the command line.
``` python
import jetson.inference
import jetson.utils
import argparse
```
> **note**: these Jetson modules are installed during the `sudo make install` step of [building the repo](building-repo-2.md#compiling-the-project).
> if you did not run `sudo make install`, then these packages won't be found when we go to run the example.
#### Parsing the Command Line
Next, add some boilerplate code to parse the image filename and an optional `--network` parameter:
``` python
# parse the command line
parser = argparse.ArgumentParser()
parser.add_argument("filename", type=str, help="filename of the image to process")
parser.add_argument("--network", type=str, default="googlenet", help="model to use, can be: googlenet, resnet-18, ect. (see --help for others)")
args = parser.parse_args()
```
This example loads and classifies an image that the user specifies. It will be expected to be run like this:
``` bash
$ ./my-recognition.py my_image.jpg
```
The desired image filename to be loaded should be substituted for `my_image.jpg`. You can also optionally specify the `--network` parameter to change the classification network that's used (the default is GoogleNet):
``` bash
$ ./my-recognition.py --network=resnet-18 my_image.jpg
```
See the [Downloading Other Classification Models](imagenet-console-2.md#downloading-other-classification-models) section from the previous page for more information about downloading other networks.
#### Loading the Image from Disk
You can load images from disk into shared CPU/GPU memory using the `loadImage()` function. Supported formats are JPG, PNG, TGA, and BMP.
Add this line to load the image with the filename that was specified from the command line:
``` python
img = jetson.utils.loadImage(args.filename)
```
The returned image will be a [`jetson.utils.cudaImage`](aux-image.md#image-capsules-in-python) object that contains attributes like width, height, and pixel format:
```python
.ptr # memory address (not typically used)
.size # size in bytes
.shape # (height,width,channels) tuple
.width # width in pixels
.height # height in pixels
.channels # number of color channels
.format # format string
.mapped # true if ZeroCopy
```
For more information about accessing images from Python, see the [Image Manipulation with CUDA](aux-image.md) page. For simplicity, we just load a single image here. To load a video or sequence of images, you would want to use the [`videoSource`](aux-streaming.md#source-code) API like the previous [`imagenet.py`](../python/examples/imagenet.py) sample does.
#### Loading the Image Recognition Network
Using the [`imageNet`](https://rawgit.com/dusty-nv/jetson-inference/master/docs/html/python/jetson.inference.html#imageNet) object, the following code will load the desired classification model with TensorRT. Unless you specified a different network using the `--network` flag, by default it will load GoogleNet, which was already downloaded when you initially [built the `jetson-inference` repo](building-repo-2.md#downloading-models) (the `ResNet-18` model was also selected by default to be downloaded).
All of the available classification models are pre-trained on the ImageNet ILSVRC dataset, which can recognize up to [1000 different classes](../data/networks/ilsvrc12_synset_words.txt) of objects, like different kinds of fruits and vegetables, many different species of animals, along with everyday man-made objects like vehicles, office furniture, sporting equipment, ect.
``` python
# load the recognition network
net = jetson.inference.imageNet(args.network)
```
#### Classifying the Image
Next, we are going to classify the image with the recognition network using the `imageNet.Classify()` function:
``` python
# classify the image
class_idx, confidence = net.Classify(img)
```
`imageNet.Classify()` accepts the image and it's dimensions, and performs the inferencing with TensorRT.
It returns a tuple containing the integer index of the object class that the image was recognized as, along with the floating-point confidence value of the result.
#### Interpreting the Results
As the final step, let's retrieve the class description and print out the results of the classification:
``` python
# find the object description
class_desc = net.GetClassDesc(class_idx)
# print out the result
print("image is recognized as '{:s}' (class #{:d}) with {:f}% confidence".format(class_desc, class_idx, confidence * 100))
```
`imageNet.Classify()` returns the index of the recognized object class (between `0` and `999` for these models that were trained on ILSVRC). Given the class index, the `imageNet.GetClassDesc()` function will then return the string containing the text description of that class. These descriptions are automatically loaded from [`ilsvrc12_synset_words.txt`](../data/networks/ilsvrc12_synset_words.txt).
That's it! That is all the Python code we need for image classification. See the [completed source](#coding-your-own-image-recognition-program-python) above.
## Running the Example
Now that our Python program is complete, let's classify the test images that we [downloaded](#setting-up-the-project) at the beginning of this page:
``` bash
$ ./my-recognition.py polar_bear.jpg
image is recognized as 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus' (class #296) with 99.999878% confidence
```
``` bash
$ ./my-recognition.py brown_bear.jpg
image is recognized as 'brown bear, bruin, Ursus arctos' (class #294) with 99.928925% confidence
```
``` bash
$ ./my-recognition.py black_bear.jpg
image is recognized as 'American black bear, black bear, Ursus americanus, Euarctos americanus' (class #295) with 98.898628% confidence
```
You can also choose to use a [different network](imagenet-console-2.md#downloading-other-classification-models) by specifying the `--network` flag, like so:
``` bash
$ ./my-recognition.py --network=resnet-18 polar_bear.jpg
image is recognized as 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus' (class #296) with 99.743396% confidence
```
Next, we'll walk through the creation of the C++ version of this program.
##
Next | Coding Your Own Image Recognition Program (C++)
Back | Classifying Images with ImageNet
© 2016-2019 NVIDIA | Table of Contents