Jetson + ROS

#JetsonTX2 + ROS + Segnet
2017/7/19のROS勉強会にて[「Jetson + ROS」]というタイトルでLTを行いました．
スライドは以下で公開してあります．
https://docs.google.com/presentation/d/1edOO_PCEk5WQyNRetSBnmB5Bjew2wPAttXtYuYsHLhQ/edit#slide=id.p
<img width="640" alt="slide.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/76888/468f72d9-98a4-a57d-f0d1-0b624bfe9f09.jpeg">

内容は，TX2で[Segnet](http://mi.eng.cam.ac.uk/projects/segnet/tutorial.html)をROSに繋げて動かしてみました，というお話です．



###ハードウェア
動画は車にwebcameraを貼り付けまして，
<img src=https://qiita-image-store.s3.amazonaws.com/0/76888/7808ac33-1f58-7c13-fdc3-118b9796ba55.jpeg width=400px>
助手席にPCを置いてrosbagをとりました．
<img src=https://qiita-image-store.s3.amazonaws.com/0/76888/7f2ad724-2ef2-1e02-d872-5d0b37a24a14.jpeg width=400px>
動画ではこんな感じです．
https://drive.google.com/open?id=0B5oEuTcLOvlDaEIyemQyWEJ5bDg

jetsonを車に乗せた事もありましたが，PCの方が手軽です．
<img src=https://qiita-image-store.s3.amazonaws.com/0/76888/c03807fd-00e0-b49f-c7f7-05ef4d5c0146.jpeg width=400px>




###ソースコード
[Segnet](http://mi.eng.cam.ac.uk/projects/segnet/tutorial.html)のROS対応コードを作ったので参考に公開しておきます．

Sensor_msgsのimageトピックを受け取り，セグメンテーション後のimageを出力します．

インストールの注意点として，Segnetをビルドする際にcaffeが必要なのですが，Alexさんの公開しているcaffe-segnetでないとエラーが出たのでこちらを入れる必要があります．

[OTLさんの本](https://www.amazon.co.jp/ROSではじめるロボットプログラミング_フリーのロボット用「フレームワーク」-I・O-BOOKS-小倉-崇/dp/4777519015/ref=sr_1_1?ie=UTF8&qid=1500728508&sr=8-1&keywords=ros)にある「ROS」を使って「分散画像処理」の章を参考にしながら，Segnet_Tutorialのwebcam_demo.pyを書き換えました．

```ros_segnet.py
#!/usr/bin/env python

#$ python Scripts/ros_segnet.py --model Example_Models/segnet_model_driving_webdemo.prototxt --weights Example_Models/segnet_weights_driving_webdemo.caffemodel --colours Scripts/camvid12.png

import numpy as np
import matplotlib.pyplot as plt
import os.path
import scipy
import argparse
import math
import cv2
import sys
import time

#ros
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge,CvBridgeError

class segnet:
	def __init__(self):
		self.image_in_pub = rospy.Publisher("segnet_input", Image)
		self.image_out_pub = rospy.Publisher("segnet_output", Image)
		self.bridge = CvBridge()
		self.image_sub = rospy.Subscriber("/image_topic",Image,self.callback)



	def callback(self,message):

		start = time.time()	
		try:
			cv2_imag = self.bridge.imgmsg_to_cv2(message,"bgr8")
		except CvBridgeError,e:
			rospy.loginfo(e)
		end = time.time()
		print '%30s' % 'image_input ', str((end - start)*1000), 'ms'

		start = time.time()
		cv2_imag = cv2_imag[0:380,0:640]	
		cv2_imag = cv2.resize(cv2_imag, (input_shape[3],input_shape[2]))
		input_image = cv2_imag.transpose((2,0,1))

		input_image = np.asarray([input_image])
		end = time.time()
		print '%30s' % 'Resized image in ', str((end - start)*1000), 'ms'

		start = time.time()
		out = net.forward_all(data=input_image)
		end = time.time()
		print '%30s' % 'Executed SegNet in ', str((end - start)*1000), 'ms'

		start = time.time()
		segmentation_ind = np.squeeze(net.blobs['argmax'].data)
		segmentation_ind_3ch = np.resize(segmentation_ind,(3,input_shape[2],input_shape[3]))
		segmentation_ind_3ch = segmentation_ind_3ch.transpose(1,2,0).astype(np.uint8)
		segmentation_rgb = np.zeros(segmentation_ind_3ch.shape, dtype=np.uint8)

		cv2.LUT(segmentation_ind_3ch,label_colours,segmentation_rgb)
		segmentation_rgb = segmentation_rgb.astype(float)/255

		end = time.time()
		print '%30s' % 'Processed results in ', str((end - start)*1000), 'ms\n'


		#cv2.imshow("Input", cv2_imag)	
		#cv2.imshow("SegNet", segmentation_rgb)
		#cv2.waitKey(3)

		segmentation_rgb = (segmentation_rgb*256).astype(np.uint8)

		try:
			self.image_in_pub.publish(self.bridge.cv2_to_imgmsg(cv2_imag, "bgr8"))
			self.image_out_pub.publish(self.bridge.cv2_to_imgmsg(segmentation_rgb, "bgr8"))
		except CvBridgeError as e:
			print(e)

def main(args):
  ic = image_converter()
  rospy.init_node('image_converter', anonymous=True)
  try:
    rospy.spin()
  except KeyboardInterrupt:
    print("Shutting down")
  cv2.destroyAllWindows()

def main():
	sys.path.append('/usr/local/lib/python2.7/site-packages')

	# Make sure that caffe is on the python path:
	caffe_root = '${HOME}/caffe-segnet/'
	sys.path.insert(0, caffe_root + 'python')
	import caffe

	# Import arguments
	parser = argparse.ArgumentParser()
	parser.add_argument('--model', type=str, required=True)
	parser.add_argument('--weights', type=str, required=True)
	parser.add_argument('--colours', type=str, required=True)
	args = parser.parse_args()

	global net
	net = caffe.Net(args.model,
                args.weights,
                caffe.TEST)

	caffe.set_mode_gpu()

	global  input_shape
	global output_label_coloursshape
	input_shape = net.blobs['data'].data.shape
	output_shape = net.blobs['argmax'].data.shape

	global label_colours
	label_colours = cv2.imread(args.colours).astype(np.uint8)

	sn = segnet()

	rospy.init_node('segnet_node',anonymous=True)
	rospy.loginfo("start")
	try:
		rospy.spin()
	except KeyboardInterrupt:
		pass
	cv2.destroyAllWindows()

if __name__ == '__main__':
	main()




```