Raspberry Pi 웹 동영상 스트리밍
- IoT
- 2022. 4. 22.
라즈베리파이에서 라이브러리를 설치해주자.
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작동 시키고 라즈베리파이 작동 시키고
웹을 실행하면 데이터가 넘어오면서 웹에 카메라가 찍는 내용이 나타날거다