やみとものプログラミング日記 やみとものプログラミング日記
TOP 【ラズベリーパイ】カメラモジュールの映像をネットワーク経由で別PCに表示する方法
【ラズベリーパイ】カメラモジュールの映像をネットワーク経由で別PCに表示する方法

【ラズベリーパイ】カメラモジュールの映像をネットワーク経由で別PCに表示する方法

Python プログラミング ラズベリーパイ Tkinter
作成日時: 2019年11月6日
更新日時: 2020年4月22日
ラズベリーパイのカメラモジュールで撮影した映像を同一ネットワーク内の別PCで表示する方法を解説します。

完成形は下の動画のようになります。
コードのポイントは、ラグを減らすためラズパイ側でJPEG圧縮をしてからTCPで送信し、受信側で復元することです。
そうしないとラグがひどくなります。

それと、ラズパイ側でプログラムを実行する前に以下のコマンドを実行する必要があります。
sudo modprobe bcm2835-v4l2
このコマンドについては良くわからないのですが、また調べて記事にしてみます。

以下コード全文です。

ラズパイ側
import socket
import cv2
import time


SERVER_PORT = 58372
FRAME_WIDTH = 300
FRAME_HEIGHT = 300


server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("", SERVER_PORT))
server.listen()
soc, addr = server.accept()

vcap = cv2.VideoCapture(0)

while True:
    _, frame = vcap.read()
    resized_frame = cv2.resize(frame, (FRAME_WIDTH, FRAME_HEIGHT))
    print(type(resized_frame))
    
    status, encoded_img = cv2.imencode(".jpg", resized_frame, [int(cv2.IMWRITE_JPEG_QUALITY), 30])
    print(len(encoded_img), "bytes (encoded)")
    
    data = encoded_img.tostring()

    header_size = 4
    header = len(data).to_bytes(header_size, "big")
    
    soc.sendall(header + data)

    print(len(data), "bytes sended")

    time.sleep(0.015)
別PC側
import socket
import tkinter
import numpy as np
import PIL.Image, PIL.ImageTk
import cv2
import threading

def update_image(data):
    global photo

    img = np.frombuffer(data, dtype=np.uint8)
    img = cv2.imdecode(img, 1)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(img))
    canvas.create_image(0, 0, image = photo, anchor = tkinter.NW)

def update_loop():
    data = b""
    while True:
        data += client.recv(BUFSIZE)
        if len(data) < 4:
            continue
        data_size = int.from_bytes(data[:4], "big")
        
        buf = data[4:]
        while True:
            if len(buf) > data_size:
                img_data = buf[0 : data_size]
                update_image(img_data)
                data = buf[data_size : ]
                break
            else:
                buf += client.recv(BUFSIZE)

SERVER_IP = "192.168.0.2"   # ★★★ラズパイのIPアドレスを指定してください!!!
SERVER_PORT = 58372
BUFSIZE = 270000


window = tkinter.Tk()
canvas = tkinter.Canvas(window, width=300, height=300)
canvas.pack()

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((SERVER_IP, SERVER_PORT))

thread = threading.Thread(target=update_loop)
thread.start()

window.mainloop()
実行する場合は、まずラズパイの方のプログラムを実行し、そのあと別PC側のプログラムを実行してください。

参考にしたサイト

Pythonでネットワーク越しにカメラの映像をストリーミング
PiCamera streaming on Tkinter label -Help