Coding Your Own Image Recognition Program (Python)

零、先看看程式碼

Argument

在外面程式定義的變數,我們稱之為引數 Argument。而在 python 裡面要完成引數有兩種方式,一種是利用 sys.argv ,很簡單但變化性很低;另一種 argparse,則是相對彈性化

為了理解程式碼,可以參考一下相關的網頁,找了一些資料其實都寫得很清楚

參考資料 

https://matters.news/@CHWang/coding%E8%B5%B7%E4%BE%86-python-argparse-%E7%B0%A1%E6%98%93%E6%95%99%E5%AD%B8-bafyreif4hhlzgzmgxqm6lk7ojn7pna5uaacmlnji4sbqzs5gxb6hwuvwqe

摘錄網站的一段話,很清楚

很簡單當你想要把程式裡的變數改成外部控制時,你就parser.add_argument(名稱, 種類, 幫忙(當輸入錯的變數時就會跳出提醒,像是明明就應個是一個整數,然後使用的硬要放一個字串,這樣就不對了))

(ex.parser.add_argument(‘runtimes’, type=int, help=’display an integer’))

https://sean22492249.medium.com/python-argpase-%E7%9A%84%E4%BB%8B%E7%B4%B9-python-%E7%9A%84%E5%BC%95%E6%95%B8-26d54db52b1f

先來看看完整的程式碼吧!

#!/usr/bin/python3

import jetson.inference

import jetson.utils

import argparse


# parse the command line 剖析器的指令碼

parser = argparse.ArgumentParser()

   #物件的class是argparse.ArgumentParser(),定義parser為argparse.ArgumentParser物件

parser.add_argument("filename", type=str, help="filename of the image to process") 

    #名稱:filename種類:str說明文字:"filename of the image to process"

    #如果在python 加上這行 parser.print_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.")

    #名稱:--network 種類:str 預設載入:googlenet 說明文字:"model to use, can be:  googlenet, resnet-18, ect."

    #--加上這兩個叫做可選參數喔!可選參數顧名思義就是你在run python檔的時候,可選擇添加或不添加的參數 

args = parser.parse_args()

    # 回傳變數的剖析 

# load an image (into shared CPU/GPU memory),這個其實寫得很清楚,先載入image的檔案名稱

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,其中confidence指的是信賴度

print("image is recognized as '{:s}' (class #{:d}) with {:f}% confidence".format(class_desc, class_idx, confidence * 100))

一、開始吧-情建立資料夾跟空檔案開始

建立程式碼放置的資料夾,並在執行Docker時載入

建立要被載入的資料夾,當執行Docker container時,我們可以下指令將上面我們完成的python程式碼放置的資料夾載入

# run these commands outside of container

$ cd ~/    #切換到跟目錄

$ sudo mkdir my-recognition-python  #建立名稱為 my-recognition-python 的資料夾,其實要建立什麼名稱都好,輸入密碼

$ cd my-recognition-python     #切換到my-recognition-python資料夾

$ sudo touch my-recognition.py      #利用touch指令來建立新的空檔案(這裡是建立空檔案)、或修改檔案的時間紀錄,前面應該存檔了

二、要把程式碼寫進去了與掛載目錄

切換到my-recognition-python這個資料夾,然後用自己習慣的編輯器來編輯,我個人是習慣用Vi或Vim做編輯,不過Nvidia的ubuntu有沒有我不知道,所以官方也建議可以用gedit

$  sudo vi my-recognition.py   #必須以超級使用者權限做編輯與存檔

那就開始吧 

進入編輯器後,先按a,然後把程式貼上

自動載入python3解譯器

先寫入第一行shebang sequence ,放在至頂處

#!/usr/bin/python3

也就是開始執行時,自動載入python3的解譯器

shebang其實就是在很多腳本的第一行出現的以」#!」開頭的注釋,他指明了當我們沒有指定解釋器的時候默認的解釋器,一般可能是下面這樣:

匯入python模組

匯入 jetson.inference and jetson.utils ,分別做影像辨識及影像載入

也匯入標準的argparse package做解析(parser)的指令列

import jetson.inference

import jetson.utils


import argparse

官網寫了注意事項,不過我是在執行Docker狀態下,所以我就無須理會


note: these Jetson modules are installed during the sudo make install step of building the repo.

          if you did not run sudo make install, then these packages won't be found when we go to run the example. 

把以下的固定樣板代碼與可選代碼完成吧

# 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)")

opt = parser.parse_args()  #本教學頁面在上面命名是args,這裡用opt喔

這幾行的功能是讓使用者載入指定的照片的檔案名稱來做影像分類,執行的指令長得像以下這樣

$ ./my-recognition.py my_image.jpg

# ./我們寫的python程式碼 指定要做分類的影像檔案名稱(要絕對路徑喔)


所以我們也可以選用其他的神經網路模型來做影像分類,例如

$ ./my-recognition.py --network=resnet-18 my_image.jpg

 #  ./我們寫的python程式碼 --指定的神經網路模型 指定要做分類的影像檔案名稱(要絕對路徑喔)


如果大家想要下載其他模型,請參閱我其他篇的說明喔

從硬碟載入影像

使用loadimage()將照片載入CPU或GPU內

支援的檔案類型為 JPG, PNG, TGA, and BMP. 

新增下面那行來載入我們指定的檔案吧

img = jetson.utils.loadImage(opt.filename)

這回傳的影像將是一個jetson.utils.cudaImage 物件,包含了像寬度、高度、畫素格式等屬性

<jetson.utils.cudaImage>

  .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 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 API like the previous imagenet.py sample does. 

看看這一段,這個範例只是載入單一的影像,如果要載入影片或多個影像,就要使用videoSource這個API,也可以參考imagenet.py這個範例

以下的程式碼是使用ImageNet物件,將載入所需要的分類模型,而這些模型是使用TensorRT。如果需要特定的其他影像分類網路,就可以使用選用的--networks,已經預先載入了googlenet的ResNet-18

# load the recognition network

net = jetson.inference.imageNet(opt.network)

要開始辨識了喔

我們使用imageNet.Classify() 來做影像的辨識,

# 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))

imageNet.Classify() 回傳辨識出來的分類索引值(0-999,這些模型是預先在 ILSVRC 上訓練完成的)

把回傳的分類索引給imageNet.GetClassDesc(),會回傳這些分類的描述。這些描述說明會自動從ilsvrc12_synset_words.txt 載入。(例如n01910747索引是jellyfish這個描述 )

您可以逐步完成或者直接拷貝最上方那個完整的程式碼,我們總算完成了自己寫的第一隻python程式了

按一下Esc鍵,輸入:

再輸入wq,完成存檔

設定為執行檔這時候才做

$ sudo chmod +x my-recognition.py   #my-recognition.py設定為可執行

以下指令碼是在執行啟用Docker時把my-recognition-python這個資料夾掛載近來

注意目錄的切換喔,要先切換到jetson-inference

    $ cd jetson-inference

$ docker/run.sh --volume ~/my-recognition-python:/my-recognition-python   

# mounted inside the container to /my-recognition-python

三、影像測試

$ cd data/images

$  wget https://i0.zi.org.tw/ddm/2019/07/09170135/1562662894-f37fc1513f186ad28ad7eb1e21bed216.jpg

$  mv 1562662894-f37fc1513f186ad28ad7eb1e21bed216.jpg liu.jpg

#我下載劉德華的照片啦...哈哈哈

$ wget https://autos.yahoo.com.tw/p/r/w1200/car-trim/August2018/77c01740298fa22e0f88b325b9bae3e7.jpeg

$ mv 77c01740298fa22e0f88b325b9bae3e7.jpeg forester.jpg

開始辨識了...

$ cd / 

$ cd my-recognition-python

$ ./my-recognition.py /jetson-inference/data/images/liu.jpg

我以為是人

結果是suit of clothes

再來一次

$ ./my-recognition.py /jetson-inference/data/images/forester.jpg


哪裡像貨車了