環境
この記事は以下の環境で動いています。
項目 | 値 |
---|---|
CPU | Core i5-8250U |
Ubuntu | 16.04 |
ROS | Kinetic |
python | 2.7.12 |
mongodb | 2.6.10 |
インストールについてはROS講座02 インストールを参照してください。
またこの記事のプログラムはgithubにアップロードされています。ROS講座11 gitリポジトリを参照してください。
概要
これまでいろいろなデータをブラウザで表示しましたが、ROSで取得した画像をブラウザで表示するのは面倒です。
ROSのimage形で保存してもブラウザでは表示できません。一度ROSで画像をファイルに書き出してブラウザで見ることもできますが、あまりROSでファイルシステムを使いたくありません。
ここでは画像のデータをBase64でエンコードすることでブラウザで表示を行います。またmongodbでこのデータを保存することで、電源を切っても情報を保存しておけます。
base64形式はバイナリーデータをテキストで表すものです。3バイトのバイナリーを4つのASCII文字に変換します。
ソースコード
rosserviceを受けてImageをmongodbに保存する。データベースの削除をする。browserに対してデータを送信します。
mongodbにアクセスするROSノード
web_lecture/scripts/mongo_image.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_srvs.srv import Empty, EmptyResponse
from sensor_msgs.msg import Image
from web_lecture.msg import StringStamp
from web_lecture.srv import StringStampList, StringStampListResponse
from mongodb_store.message_store import MessageStoreProxy
from cv_bridge import CvBridge, CvBridgeError
import base64
import cv2
class MongoImage:
def __init__(self):
rospy.Service('shot', Empty, self.shotCallback)
rospy.Service('delete', Empty, self.deleteCallback)
rospy.Service('request', StringStampList, self.requestCallback)
rospy.Subscriber("/image_raw", Image, self.imageCallback)
self.last_image = Image()
self.scale = 0.5
self.bridge = CvBridge()
self.last_base64 = None
self.msg_store = MessageStoreProxy(database="srs", collection="image_stamp")
def imageCallback(self, msg):
self.last_image = msg
def shotCallback(self, msg):
frame = self.bridge.imgmsg_to_cv2(self.last_image, "bgr8")
height = frame.shape[0]
width = frame.shape[1]
frame2 = cv2.resize(frame , (int(width*self.scale), int(height*self.scale)))
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 50]
result, frame3 = cv2.imencode(".jpg", frame2, encode_param)
mongo_data = StringStamp()
mongo_data.stamp = rospy.get_rostime()
mongo_data.data = base64.b64encode(frame3)
try:
p_id = self.msg_store.insert(mongo_data)
except rospy.ServiceException, e:
print "Service call failed: %s"%e
return EmptyResponse()
def deleteCallback(self, msg):
list = self.msg_store.query(StringStamp._type)
for item in list:
self.msg_store.delete(str(item[1]["_id"]))
return EmptyResponse()
def requestCallback(self, msg):
mongo_list = self.msg_store.query(StringStamp._type)
output = []
try:
for item in mongo_list:
output.append(item[0])
except rospy.ServiceException, e:
print "Service call failed: %s"%e
return StringStampListResponse(output)
if __name__ == '__main__':
rospy.init_node('mongo_image')
mongo_image = MongoImage()
rospy.spin()
-
base64.b64encode(cv2.imencode(".jpg", frame, encode_param))
でopencv形式からjpg形式のデータを作り、それをbase64形式に変換します。 - mongodbでは一括で削除をするというapiはありません。一度queryで一覧を取得してからdeleteを行います。
blowserで表示するhtml
web_lecture/www/image_view.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
web_lecture index.html
</head>
<body>
<p>
<a href="pub.html">pub.html</a> <br/>
<a href="sub.html">sub.html</a> <br/>
<a href="camera.html">camera.html</a> <br/>
<a href="camera_full.html">camera_full.html</a> <br/>
<a href="twist.html">twist.html</a> <br/>
<a href="gamepad_api_test.html">gamepad_api_test.html</a> <br/>
<a href="gamepad.html">gamepad.html</a> <br/>
<a href="image_view.html">image_view.html</a> <br/>
</p>
</body>
</html>
実行
実行
mkdir ~/.ros/mongo
roslaunch web_lecture mongo_image.launch
- 「shot」を押すとカメラに写っている画像を保存します。
- 「request」を押すと保存されている画像をblowserに表示します。
- 「delete」を押すと保存されている画像をすべて消去します。
参考
base64で画像をhtmlに埋め込む
pythonでbase64に変換