본문 바로가기

프로젝트형 IoT 서비스 개발 4회차/3. 게이트웨이 디바이스 제어

[Day61] 2022-04-25(월) 라즈베리파이10 - 카메라(스트리밍) - 김서연 강사님

728x90

[1] 카메라 스트리밍

  1. 기본 구조 예제

    1) 라즈베리파이

      ① 카메라 모듈 생성

mycamera.py

# 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로 실행흐름을 분리 - picamera로 찍은 영상을 frame 단위로 보내는 메소드
    # 인스턴스메소드, 클래스메소드(@classmethod 표시)
    # io 모듈은 다양한 i/o처리를 위해 제공되는 모듈
    # 텍스트, 바이너리, raw 데이터
    # 텍스트
    # - string -> f = open("myfile.txt", "rt")
    # - io.StringIO(메모리 스트림) 
    # 바이너리
    # - f = open("myimg.jpg", "rb")
    # - 인메모리 바이너리스트림 -> io.BytesIO()
    
    @classmethod
    def streaming(c):
        with picamera.PiCamera() as camera:
            camera.resolution = (320, 240)
            camera.hflip = True
            camera.vflip = True
            
            camera.start_preview()
            time.sleep(2)
            
            stream = io.BytesIO()
            for f in camera.capture_continuous(stream, "jpeg", use_video_port=True):
                stream.seek(0)
                c.frame = stream.read()
                # 다음 캡쳐를 위한 준비 - 파일의 내용을 비우기
                stream.seek(0)
                stream.truncate()

      ② MQTT 모듈 생성 및 모듈 내 테스트 코드

mymqtt.py

# mymqtt.py
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
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("XXX.XXX.XXX.XXX", 1883, 60)
            self.client.loop_forever()

        except KeyboardInterrupt:
            pass
        finally:
            print("종료")
            
    def on_connect(self, client, userdata, flags, rc):
        print("connect..."+str(rc))
        if rc == 0:
            self.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()
                    publish.single("mycamera", frame, hostname="172.30.1.57")
        except:
            pass
        finally:
            pass
        

if __name__ == "__main__":
    mymqtt = MqttWorker()
    mymqtt.mymqtt_connect()

    2) Web

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 = "XXX.XXX.XXX.XXX"
        var port = 9001

        function onConnect(){
            console.log("접속완료")
            // 영상데이터가 전송될 때까지 대기
            mqtt.subscribe("mycamera")

            // 웹페이지 접속하자마자 메시지 보내기
            message = new Paho.MQTT.Message("start");
            // topic 설정
            message.destinationName = "web";
            // MQTT 메시지 보내기 - publish
            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, "Video Client")
            var options = {
                timeout: 3,
                onSuccess: onConnect,
                onFailure: onFailure,
            }
            mqtt.onMessageArrived = onMessageArrived
            mqtt.connect(options)
        }
    </script>
</head>
<body>
    <script>MQTTConnect()</script>
    <h1>MQTT와 웹소켓 테스트</h1>
    <img id="myimg" src="#" width="800" height="600">
</body>
</html>

 

- 끝 -

 

728x90