読者です 読者をやめる 読者になる 読者になる

ami_GS's diary

情報系大学院生の備忘録。ネットワークの勉強にハマっています。

UDPで画像通信(その1)

Python UDP 画像処理

こんばんは、卒論提出を二日後に控えていますが記事を書きます。



今回は前回の挫折編からのリベンジ編という事で、
一方のPCで撮った映像をリアルタイムで他方のPCにUDPで送り、表示します。
そこそこ簡単にスカイプのテレビ電話(音声無し)みたいな物が作れるのでテンションがあがると思います。(あがりました)


(3ヶ月以上前に書いたコードだから忘れかけてるやばいやばい)





さて、今回使う物は、筆者の都合上openCVです。
(※これはカメラから画像をキャプチャし、表示させる為だけに使っているのでpygame等を使った方が簡単かもしれません)



インストールの仕方は

sudo port install opencv +python27

インストールされたかの確認はpythonインタラクティブシェルにて

import cv2 # または import cv

として、エラーが出なければおkです。



今回は、クライアント側で画像をキャプチャし、サーバ側で画像の表示をさせたいと思います。


Client側

import cv2.cv as cv
import cv2
import socket

if __name__ == "__main__":
        udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        
#        cv.NamedWindow("ClientCAM", 1)
        capture = cv.CaptureFromCAM(0)#キャプチャに使うカメラの選択
        cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,320)#キャプチャする画像のサイズ
        cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,240)  
        while True:
                img = cv.QueryFrame(capture)#画像のキャプチャ
                jpgstring = cv.EncodeImage(".jpeg", img).tostring()#UDPで送る為に画像をstringに変換
 #               cv.ShowImage("ClientCAM", img)
                
                udp.sendto(jpgstring, ("127.0.0.1", 12345))#画像の送信
                if cv.WaitKey(10) == 27:
                        break #エスケープキー(だったけ・・・・?)にて終了
        
        cv.DestroyAllWindows()#事後処理
        udp.close()

Server側

import cv2.cv as cv
import cv2
import numpy
import socket

if __name__ == "__main__":
        cv.NamedWindow("serverCAM", 1)#表示するウィンドウ作成
        
        udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        udp.bind(("127.0.0.1", 12345))
        
        buff = 1024
        while True:
                jpgstring, addr = udp.recvfrom(buff*64)#送られてくるデータが大きいので一度に受け取るデータ量を大きく設定
                narray = numpy.fromstring(jpgstring, dtype = "uint8")#string型からnumpyを用いuint8に戻す
                decimg = cv2.imdecode(narray,1)#uint8のデータを画像データに戻す
                
                cv2.imshow("serverCAM", decimg)画像の表示
                if cv.WaitKey(10) == 27:
                        break
        
        cv.DestroyAllWindows()
        udp.close()


簡単のため、今回はシングルスレッドです。
動画も割とスムーズでパケットロスもあまり気にならないしね!
画像データをstring型にエンコードし、受け取った側でデコードする所で詰まった記憶があります。
当時は送れるデータがstringに限られてる(のかな?)ことは知らなかった・・・


ちなみに、キャプチャした画像を分割せずに一度に一枚送っています。
client側からudpで送る際に、socketの仕様上データの上限が決まっているので、キャプチャする画像サイズをデカくするとエラーが出ます。
大きい画像を送りたい時は画像を分割してマルチスレッドでやればいいのかな、(その?)あたりで試してみますか。


もしクライアント側で、キャプチャした画像を見たいという方は2つのコメントアウトを取り除いてください!
2つのPCを並べて動画のディレイを見て楽しむ事ができます。
僕の動作環境ではほぼディレイ無かった気がする。



お後がよろしいようで。