2012/07/20

Webカメラの画像をpythonのsocketを使って転送する

BeagleBoneタンクに欠かせない装備はWebカメラです。Webカメラの映像をコマンドセンター(自分の部屋)にて確認し、状況に応じた適切な命令をタンクに送ることがでるようになります。

タンクとコマンドセンター間は無線LANで繋ぐので、ソケットを使って画像を転送する必要があります。Cでソケットプログラムを書くのは面倒ですが、pythonにはラッパークラスがあって比較的簡単にソケットプログラミングができます。

Webカメラで取得した画像の送信フローは以下のとおりです。
タンクはコマンドセンターから画像要求が来た場合に、Webカメラで取得した画像をJPEGに圧縮して送り返します。コマンドセンターでは受信した画像をデコードし、画面に表示します。受信しているデータはJPEGなので、そのままJPEGファイルとしてディスクに書き込むことも可能です。


SocketServerモジュールのサンプルコードを元に、BeagleBoneタンクで画像を取得し、コマンドセンターに転送するプログラムを作りました。例外処理等はしてませんが、一応動いています。タンク側はCtrl+cの強制終了でしか終わらないので行儀良いプログラムではありません。そのうち改良しようと思います。


はじめはOpenCV2.4から実装されているcv2.imencodeとcv2.imdecodeを使っていたのですが、BeagleBone側はOpenCV2.3だという事に気づき、エンコードにcv2.cv.EncodeImageを使用しています。OpenCV2.3のcv2.imencodeはSegmentation faultが出たので使うのをやめました。

まだ有線LANでしか実験していませんが、QVGAサイズの画像を1秒間に5枚程度は送受信できています。無線に変えても2〜3枚は送受信できるかな・・・?


BeagleBoneタンク側:
"""
 webcamera server
  for opencv 2.3
"""

import SocketServer
import cv2.cv as cv
import numpy
import socket
import sys

#for OpenCV2.3 python interface

class TCPHandler(SocketServer.BaseRequestHandler):
    capture=''

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print "%s connected:" % self.client_address[0]
        frame=cv.QueryFrame(capture)

        jpegstring=cv.EncodeImage('.jpeg',frame).tostring()
        print len(jpegstring)
        self.request.send(jpegstring)


if __name__ == "__main__":
    HOST, PORT = '192.168.111.40', 12345

    #init camera
    cameraid=0
    capture=cv.CreateCameraCapture(0)
    cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,320)
    cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,240)
    if not capture:
        print "Could not open camera"
        exit()
  
    server = SocketServer.TCPServer((HOST, PORT), TCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.capture=capture
    server.serve_forever()


コマンドセンター側
'''
  Image receiver
  for OpenCV 2.4 python interface
'''

import socket
import sys
import numpy
import cv2

# for opencv 2.4.2

HOST, PORT = "192.168.111.40", 12345

# Receive data from the server and shut down
quitflag=False
recvlen=1

def getImageFromServer():
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect((HOST,PORT)) 
    sock.send('HELLO\n')
    recvlen=100
    buffer='' 
    while recvlen>0:
        receivedstr=sock.recv(1024*8)
        recvlen=len(receivedstr)
        buffer +=receivedstr

    print '%d bytes received' %len(buffer)
    narray=numpy.fromstring(buffer,dtype='uint8')
    decimg=cv2.imdecode(narray,1)
    sock.close()
    return decimg

while 1:
    img=getImageFromServer()
    cv2.imshow('Capture',img)
    key=cv2.waitKey(100)
    if(int(key)>27): break
    img=''


※IPアドレスとポートは適当に読み替えてください。



次はソケットで操縦コマンドを送受信してGPIOを制御する部分を作ろうと思います。
ではまた。

0 件のコメント:

コメントを投稿