Jetson Nano で物体検知時にセマンティックセグメンテーションを試してみた | そう備忘録

Jetson Nano で物体検知時にセマンティックセグメンテーションを試してみた

セマンティックセグメンテーションとは

以前の記事の「NVIDIAのJetson Nanoで物体の検知をやってみた」の続き。

上記の記事では検知した物体をバウンディングボックスという四角い枠で囲んでいたがセマンティックセグメンテーションとは下記のようにピクセル単位で物体の輪郭を識別する技術。

overlayのみ指定

セマンティックセグメンテーションは「環境の認識で役に立ち、シーンの前景・背景など物体のピクセル毎の分類を生成する」とNVIDIAのページにはあった。

このセマンティックセグメンテーションをNVIDIAのJetson Nano 2GB 開発キットにて試してみた。

環境

今回の実行環境は以下の通り。

本体

NVIDIA Jetson Nano 2GB 開発者キット

OS

Ubuntu18.04.5 LTS

JetPack SDK

JetPack 4.4.1

事前準備

事前準備については「NVIDIAのJetson Nanoで物体の検知をやってみた」の事前準備の章を参照して欲しい。

  • セットアップ
  • プロジェクトの準備

に従って必要な設定を行う。

セグメンテーション

使用可能なモデル

使用可能なモデルは以下の通り。

いずれも 21-class FCN-ResNet18 ネットワークをベースにしている。

Cityscapes

  • CLI時の引数:fcn-resnet18-cityscapes-512×256
  • 解像度:512×256
  • 正確性:83.3%
  • Jetson Nanoでの性能:48 FPS

Cityscapes

  • CLI時の引数:fcn-resnet18-cityscapes-1024×512
  • 解像度:1024×512
  • 正確性:87.3%
  • Jetson Nanoでの性能:12 FPS

Cityscapes

  • CLI時の引数:fcn-resnet18-cityscapes-2048×1024
  • 解像度:2048×1024
  • 正確性:89.6%
  • Jetson Nanoでの性能:3 FPS

DeepScene

  • CLI時の引数:fcn-resnet18-deepscene-576×320
  • 解像度:576×320
  • 正確性:96.4%
  • Jetson Nanoでの性能:26 FPS

DeepScene

  • CLI時の引数:fcn-resnet18-deepscene-864×480
  • 解像度:864×480
  • 正確性:96.9%
  • Jetson Nanoでの性能:14 FPS

Multi-Human

  • CLI時の引数:fcn-resnet18-mhp-512×320
  • 解像度:512×320
  • 正確性:86.5%
  • Jetson Nanoでの性能:34 FPS

Multi-Human

  • CLI時の引数:fcn-resnet18-mhp-512×320
  • 解像度:640×360
  • 正確性:87.1%
  • Jeton Nanoでの性能:23 FPS

Pascal VOC

  • CLI時の引数:fcn-resnet18-voc-320×320
  • 解像度:320×320
  • 正確性:85.9%
  • Jeton Nanoでの性能:45 FPS

Pascal VOC

  • CLI時の引数:fcn-resnet18-voc-512×320
  • 解像度:512×320
  • 正確性:88.5%
  • Jeton Nanoでの性能:34 FPS

SUN RGB-D

  • CLI時の引数:fcn-resnet18-sun-512×400
  • 解像度:512×400
  • 正確性:64.3%
  • Jetn Nanoでの性能:28 FPS

SUN RGB-D

  • CLI時の引数:fcn-resnet18-sun-640×512
  • 解像度:640×512
  • 正確性:65.1%
  • Jetn Nanoでの性能:17 FPS

モデルの追加

今回試したモデルは Cityscapes の解像度が 512×256、1024×512、2048×1024 の3種類と Multi-Human の解像度が 512×320 と 640×360 の合計5種類。

Cityscapes の 2048×1024 と Multi-Human の 640×360 の高解像度のモデルがデフォルトではインストールされていなかったので以下のコマンドで追加した。

cd jetson-inference/tools
./download-models.sh

利用したいモデルにチェックを入れて追加する。

モデルの追加

モデルが追加される。

モデルが追加される

実行コマンド

以下のコマンドで segnet.py によるセマンティックセグメンテーションを実行する。

./segnet.py --network=fcn-resnet18-cityscapes-2048x1024 images/city_1.jpg images/test/cityoutput2048x1024.jpg

segnet.py

実行プログラム(後述

–network

都市の景観のセグメンテーションが得意な fcn-resnet18-cityscapes-2048×1024 を指定した。

尚、解像度を省略した時は最低解像度のモデルが読み込まれる。

images/city_1.jpg

元の入力画像

都市画像その1

images/test/cityoutput2048x1024.jpg

出力Pathとファイル名(解像度を2048×1024で出力)

Dockerコンテナ終了後もファイルが残るディレクトリを指定している。

2048×1024の出力結果

車、歩行者、道路、地面からのポール、街路樹などがピクセル単位でセグメンテーションされている事が分かる。

また左側に元の画像にマスクをオーバーレイした画像、右側にマスク画像が表示される。

–filter-mode

省略時は linear(線形)が選択される(上記の出力結果)

point を指定した時は下記のように出力される。

filter-modeにpoint指定

–visualize

省略時は overlay,maskの両方が指定される。

–visualize=’overlay,mask’

overlayだけを指定すると元の画像にオーバレイ表示した画像のみが出力される

overlayのみ指定

maskだけを指定すると元画像は表示されずにマスク表現の画像のみが出力される。

maskのみを指定

その他の結果

同じ写真を解像度1024×512でセグメンテーションしたのが以下の結果。

解像度1024×512

同じく512×256でのセグメンテーションの結果。

解像度が落ちると境界も曖昧になってくる。

512×256の実行結果

Multi-Human

モデル=Multi-Human で違う写真を試してみた。

Multi-Human Parsing は群衆の画像から身体(頭、胴体、腕、足、etc)や衣服などのアイテムに分割してラベル付けしてグループ行動分析、人物の再識別、画像編集、ビデオ監視、自動運転、バーチャルリアリティなどのアプリケーションを構築する為のシンガポール国立大学のプロジェクト。

入力画像

サッカーをしている子供たちの写真を入力にしている。

入力画像

出力結果(640×360)

出力結果(解像度640x360)

出力結果(512×320)

出力結果(解像度512×320)

ソースコード

segnet.py のソースコードは以下の通り。

上部にNVIDIAの著作権(制限無しで使用可能、コピー、変更、マージ、公開、配布、サブライセンス・・・)が記述されている。

またコード中に日本語でコメントを追記した。

#!/usr/bin/python3
#
# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#

import jetson.inference
import jetson.utils

import argparse
import sys

from segnet_utils import *

# parse the command line
parser = argparse.ArgumentParser(description="Segment a live camera stream using an semantic segmentation DNN.", 
                                 formatter_class=argparse.RawTextHelpFormatter, epilog=jetson.inference.segNet.Usage() +
                                 jetson.utils.videoSource.Usage() + jetson.utils.videoOutput.Usage() + jetson.utils.logUsage())

parser.add_argument("input_URI", type=str, default="", nargs='?', help="URI of the input stream") # 入力
parser.add_argument("output_URI", type=str, default="", nargs='?', help="URI of the output stream") # 出力
parser.add_argument("--network", type=str, default="fcn-resnet18-voc", help="pre-trained model to load, see below for options") # 使用ネットワーク(デフォルトはfcn-resnet18-voc)
parser.add_argument("--filter-mode", type=str, default="linear", choices=["point", "linear"], help="filtering mode used during visualization, options are:\n  'point' or 'linear' (default: 'linear')") # 出力結果表現方法linearとPoint
parser.add_argument("--visualize", type=str, default="overlay,mask", help="Visualization options (can be 'overlay' 'mask' 'overlay,mask'")
parser.add_argument("--ignore-class", type=str, default="void", help="optional name of class to ignore in the visualization results (default: 'void')") # ヴィジュアライズ時に無視するクラスのオプション名
parser.add_argument("--alpha", type=float, default=150.0, help="alpha blending value to use during overlay, between 0.0 and 255.0 (default: 150.0)")
parser.add_argument("--stats", action="store_true", help="compute statistics about segmentation mask class output")

is_headless = ["--headless"] if sys.argv[0].find('console.py') != -1 else [""]

try:
	opt = parser.parse_known_args()[0]
except:
	print("")
	parser.print_help()
	sys.exit(0)

# load the segmentation network
net = jetson.inference.segNet(opt.network, sys.argv)# segNetの起動

# set the alpha blending value
net.SetOverlayAlpha(opt.alpha)

# create buffer manager
buffers = segmentationBuffers(net, opt)

# create video sources & outputs
input = jetson.utils.videoSource(opt.input_URI, argv=sys.argv) # 入力 videoSourceは画像、映像両方に対応
output = jetson.utils.videoOutput(opt.output_URI, argv=sys.argv+is_headless) # 出力

# process frames until user exits
while True:
	# capture the next image
	img_input = input.Capture() # キャプチャーして画像をimgに保存

	# allocate buffers for this size image
	buffers.Alloc(img_input.shape, img_input.format)

	# process the segmentation network
	net.Process(img_input, ignore_class=opt.ignore_class)

	# generate the overlay --visualizeでoverlayを指定したとき
	if buffers.overlay:
		net.Overlay(buffers.overlay, filter_mode=opt.filter_mode)

	# generate the mask --visualizeでmaskを指定したとき
	if buffers.mask:
		net.Mask(buffers.mask, filter_mode=opt.filter_mode)

	# composite the images
	if buffers.composite:
		jetson.utils.cudaOverlay(buffers.overlay, buffers.composite, 0, 0)
		jetson.utils.cudaOverlay(buffers.mask, buffers.composite, buffers.overlay.width, 0)

	# render the output image
	output.Render(buffers.output)

	# update the title bar
	output.SetStatus("{:s} | Network {:.0f} FPS".format(opt.network, net.GetNetworkFPS()))

	# print out performance info
	jetson.utils.cudaDeviceSynchronize()
	net.PrintProfilerTimes()

    # compute segmentation class stats
	if opt.stats:
		buffers.ComputeStats()
    
	# exit on input/output EOS
	if not input.IsStreaming() or not output.IsStreaming():
		break

補足説明

入力、出力で使用している jetson のユーティリティの videoSource(入力) と videoOutput(出力) は画像、映像の両方に対応している。

詳細については以前の「NVIDIAのJetson Nanoで物体の検知をやってみた」を参照して欲しい。

終わりに

以上でセマンティックセグメンテーションに関する今回の記事は終了とする。

最後に

この記事が何処かで誰かの役に立つことを願っている。

尚、当記事中の商品へのリンクはAmazonアソシエイトへのリンクが含まれています。Amazonのアソシエイトとして、当メディアは適格販売により収入を得ていますのでご了承ください。

souichirou

やった事を忘れない為の備忘録 同じような事をやりたい人の参考になればと思ってブログにしてます。 主にレゴ、AWS(Amazon Web Services)、WordPress、Deep Learning、RaspberryPiに関するブログを書いています。 仕事では工場に協働ロボットの導入や中小企業へのAI/IoT導入のアドバイザーをやっています。 2019年7月にJDLA(一般社団法人 日本デイープラーニング協会)Deep Learning for GENERALに合格しました。 質問は記事一番下にあるコメントかメニュー上部の問い合わせからお願いします。

おすすめ

質問やコメントや励ましの言葉などを残す

名前、メール、サイト欄は任意です。
またメールアドレスは公開されません。