ROS講座114 DataBaseで画像を扱いブラウザからアクセスする


環境

この記事は以下の環境で動いています。

項目
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に変換

目次ページへのリンク

ROS講座の目次へのリンク