Raspberry Pi 웹 동영상 스트리밍

라즈베리파이에서 라이브러리를 설치해주자.

 

sudo apt-get install python-picamera 설치해주고

pycamera_test.py 파일에서 작업을 해주자.

 

from picamera import PiCamera
from time import sleep

# 사진찍기
camera = PiCamera() # PiCamera 객체 생성
camera.start_preview() # 미리보기 화면 시작
# 카메라의 센서가 빛의 수준을 감지 할 시간이 있어야 하므로
# 이미지를 갭쳐하기 전에 최소 2초는 sleep

sleep(10) # 초
camera.capture("/home/pi/mywork/picamera/image.jpg")
camera.stop_preview() #미리보기 화면 중지

문제)

5초에 한 번씩 사진 5장 촬영하기

- 파일명은 image1. jpg ~ image5.jpg

더보기
from picamera import PiCamera
from time import sleep

camera = PiCamera()

camera.start_preview()
sleep(10)
for i in range(1,6):
    sleep(5)
    camera.capture("/home/pi/mywork/picamera/image"+str(i)+".jpg")
camera.stop_preview()

 

 

from picamera import PiCamera, Color
from time import sleep

camera = PiCamera()
#해상도 적용
camera.resolution = (2592,1944)
camera.framerate = 15

camera.start_preview()
camera.rotation = 180 #카메라 회전

camera.annotate_text = "raspberry PI"
camera.annotate_text_size = 50
camera.annotate_background = Color("blue")
camera.annotate_foreground = Color("yellow")
# 사진에 글자 넣기



sleep(10)
camera.capture("/home/pi/mywork/picamera/image.jpg")
camera.stop_preview()

 

from picamera import PiCamera
from time import sleep

camera = PiCamera()
camera.start_preview()
#동영상 저장 시작
camera.start_recording("/home/pi/mywork/picamera/video.h264")
sleep(10)
camera.stop_recording()
camera.stop_preview()

 

문제)

카메라로 촬영한 이미지 파일을 mqtt통신을 통해서 전송

1) pc (subscriber)

- broker가 보내주는 바이너리 데이터(이미지 파일)를 받아서 파일로 저장

2) 라즈베리파이(publisher)

- 라즈베리파이 카메라로 영상을 촬영

   2초에 한 번 씩 촬영해서 5개의 파일 전송

- 생성된 이미지 파일을 읽어서 바이트배열로 publish

 

더보기

라즈베리파이

from picamera import PiCamera
import paho.mqtt.publish as publish
from time import sleep

class camera:
    def __init__(self):
        self.camera = PiCamera()
        self.camera.start_preview()
        sleep(10)
        
    def capture(self):
        for i in range(1,6):
            sleep(5)
            self.camera.capture("/home/pi/mywork/exam/image"+str(i)+".jpg")
        self.camera.stop_preview()
            

camera_capture = camera()
camera_capture.capture()

for i in range(1,6):
    f = open("/home/pi/mywork/exam/image"+str(i)+".jpg","rb")
    mq = f.read()
    mq = bytearray(mq)
    publish.single("iot/img",mq,hostname="192.168.50.201")
    sleep(5)

PC

import paho.mqtt.client as client

num = 0
def on_connect(client, useradata, flags, rc):
    print("connect..."+str(rc))
    if rc==0:
        client.subscribe("iot/img")
    else:
        print("연결실패")

def on_message(client, userdata, message):
    global num
    num += 1
    f = open("test"+str(num)+".jpg", "wb")
    f.write(message.payload)
    f.close()
    
try:
    mqttClient = client.Client()
    mqttClient.on_connect = on_connect
    mqttClient.on_message = on_message
    mqttClient.connect("192.168.50.201",1883)
    mqttClient.loop_forever()
except KeyboardInterrupt:
    pass

어느정도 활용할줄 아니 웹이랑 연동해보자

 

라즈베리파이 mymqtt.py

import paho.mqtt.client as mqtt
import paho.mqtt.publish as publisher
from threading import Thread
import mycamera

class MqttWorker:
    def __init__(self):
        self.client = mqtt.Client()
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.camera = mycamera.MyCamera()
        
    def mymqtt_connect(self):
        try:
            print("브로커 연결 시작하기")
            self.client.connect("192.168.50.201",1883)
            self.client.loop_forever()
        except KeyboardInterrupt:
            pass
        finally:
            print("종료")
    
    def on_connect(self, client, userdata, flags, rc):
        print("connect..."+str(rc))
        if rc==0:
            client.subscribe("web")
        else:
            print("연결실패...")
    
    def on_message(self, client, userdata, message):
        try:
            myval = message.payload.decode("utf-8")
            print(message.topic+"-----"+myval)
            if myval == "start":
                while True:
                    frame = self.camera.getStreaming()
                    publisher.single("mycamera",frame,hostname="192.168.50.201")
        except:
            pass
        finally:
            pass
        
if __name__ == "__main__":
    mymqtt = MqttWorker()
    mymqtt.mymqtt_connect()

라즈베리파이 mycamera.py

import io
import threading
import picamera
import time

class MyCamera:
    frame = None
    thread = None
    
    # streaming메소드를 쓰레드로 동작시키며 스트리밍되는 frame을 외부로 보내는 메소드
    def getStreaming(self):
        if MyCamera.thread is None:
            MyCamera.thread = threading.Thread(target=self.streaming)
            MyCamera.thread.start()
            while self.frame is None:
                time.sleep(0) #프레임이 없으면 넘어가지 못하게
        return self.frame
        
    # Thread로 실행흐름을 분리 - 파이카메라로 찍은 영상을 프레임 단위로 보내는 메소드
    # 클래스메소드(@classmethod표시) - 클래스를 받을 매개변수 필요
    # 클래스안에 변수를 공유하는 함수
    
    # io모듈은 다양한 i/o처리를 위해 제공되는 모듈
    # 텍스트, 바이너리, raw
    # 텍스트 - string, f = open("myfile.txt","r")
    #       - io.StringIO(메모리 스트림)
    # 바이너리 - f = open("myimg.jpg","rb")
    # 인메모리 바이너리스트림 - io.bytesIO(b'XXXXX')
    
    @classmethod
    def streaming(c):
        print("dddd")
        with picamera.PiCamera() as camera:
            camera.resolution = (320,240)
            camera.hflip = True
            camera.vflip = True
            
            camera.start_preview()
            time.sleep(2)
            
            stream = io.BytesIO() #녹화한거를 메모리상에서 stream으로 넘겨줌
            for f in camera.capture_continuous(stream, "jpeg", use_video_port=True):
                #비디오포트로 stream 영상을 jpeg형식으로 만들어준다.
                #비디오포트를 사용하면 속도는 올라가되 질이 떨어진다.
                #stream으로 들어온 영상을 프레임으로 다 쪼개서 jpeg으로 만들어진 이미지가 f로 들어간다.
                stream.seek(0) #되감기
                c.frame = stream.read() #프레임 하나 저장
                #다음 캡쳐를 위한 준비작업 - 파일의 내용을 비우기
                stream.seek(0)
                stream.truncate()

웹 mqttvideo.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src = "https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js"
            type = "text/javascript"> </script>
    <script type="text/javascript">

    var host = "192.168.50.201";
    var port = 9001;
    var mqtt;

    function onConnect() {
        console.log("접속됫다");
        //영상 데이터가 전송될때까지 대기
        mqtt.subscribe("mycamera");
        message = new Paho.MQTT.Message("start");
        message.destinationName = "web";
        mqtt.send(message);
    };
    function onFailure() {
        console.log("접속안됨");
    };

    function onMessageArrived(msg) {
        console.log("======"+msg.payloadBytes+"===<br/>");
        //전송되는 payloadBytes를 이미지로 만들어서 이미지태그에 연결
        //바이너리데이터를 인코딩해야 할 경우 Base64
        //자바스크립트에서 문자열을 base64로 인코드하려면 btoa메소드를 이용해서 변환
        //broker에게 전송받은 payloadBytes를 btoa메소드에서 변경할 수 있도록 문자열로 변환해서 전달
        document.getElementById("myimg").src = "data:image/jpeg;base64,"+btoa(String.fromCharCode.apply(null,msg.payloadBytes))
        //
    };

    function MQTTConnect() {
        console.log("mqtt접속"+host+"port");
        mqtt = new Paho.MQTT.Client(host,port,"javascript_client");
        var options = {
            timeout:3,
            onSuccess:onConnect,
            onFailure:onFailure,
        };
        mqtt.onMessageArrived = onMessageArrived;
        mqtt.connect(options);
    };
</script>
</head>
<body>
    <h1>MQTT와 웹소켓 테스트</h1>
    <script type="text/javascript">
        MQTTConnect();
    </script>
    <img src="#" id="myimg" width="800" height="600"/>
</body>
</html>

mosquitto broker작동 시키고 라즈베리파이 작동 시키고

웹을 실행하면 데이터가 넘어오면서 웹에 카메라가 찍는 내용이 나타날거다

 

댓글

Designed by JB FACTORY