居家工作後,因為筆電擺設的位置,每次會議想打開上蓋開視訊都會卡到螢幕,但又不想另外花錢買外接視訊,於是就這樣擱著不開鏡頭。

有天突發奇想,能不能用 Rasbperry pi 作一個呢?研究後發現還蠻簡單的,只需要Raspberry pi、鏡頭模組、一個簡單的 python script 以及 OBS 軟體就能實現!這篇分享我的實作經驗給大家。

以下教學假設讀者已經有基本的 Raspberry pi 使用經驗,且 Raspberry pi 的系統、Python 環境、Wifi 連線、相機模組都裝好或設定好,並使用 Bullseye 版本的 Raspberry pi OS,透過 picamera2 和 libcamera 來擷取相機影像

建立視訊串流 Server

原始碼下載:github

我用 Python flask 架設簡單的 Video Steam Server,首先建立虛擬環境,並且安裝對應套件。

特別注意的是,我們需要已經預設安裝在系統環境的 libcamera 和 picamera2 等套件,因此建立虛擬環境時,要在後面增加 --system-site-packages 參數, pip 才會幫我們自動導入,免去後續自行安裝的困擾。

$ virtualenv .env --system-site-packages
$ source .env/bin/activate
$ pip install flask

接著建立 stream.py 開始寫 code! 原始碼可參考 github,我們一步步解說程式內容

  • 第一步初始化 Picamear2
  • 緊接著準備 camera config,給定
    • size: 1920 x 1080 ,此部分可依個人情況調整
    • format:給定 XBGR8888 顏色才會正確(不然會出現綠巨人…)
    • transform:此設定可選,因鏡頭擺設角度上下顛倒,需要在影像輸出時作 vertical flip 轉回來
    • controls:此設定可選,因選用的鏡頭品質暗部雜訊多且畫質偏軟,透過 config 增加銳利度並降燥
    • 更多設定可參考 Picamera2 官方文件
  • 將 config 設定至 camera object 中
  • 呼叫 start_recording 啟動相機,並傳入 JpegEncoder()Quality.VERY_HIGH 將輸出編碼成高品質 JPEG,透過 FileOutput 輸出至 StreamingOutput
from picamera2 import Picamera2
from picamera2.encoders import JpegEncoder, Quality
from picamera2.outputs import FileOutput

cam = Picamera2()
config = cam.create_video_configuration(
    {'size': (1920, 1080), 'format': 'XBGR8888'},
    transform=Transform(vflip=1),
    controls={'NoiseReductionMode': controls.draft.NoiseReductionModeEnum.HighQuality, 'Sharpness': 1.5}
)
cam.configure(config)
cam.start_recording(JpegEncoder(), FileOutput(output), Quality.VERY_HIGH)

疑?不對啊?我們有寫 StreamingOutput 嗎?對,要來補了,參考 Picamera2 的 Sample Code,繼承 BufferedIOBase 寫一個 StreamingOutput ,作為將 JPEG bytes data 轉給 flask 的中介

class StreamingOutput(BufferedIOBase):
    def __init__(self):
        self.frame = None
        self.condition = Condition()

    def write(self, buf):
        with self.condition:
            self.frame = buf
            self.condition.notify_all()

output = StreamingOutput()

Camera 的部分準備完畢,開始準備 flask 的初始化

from flask import Flask
app = Flask(__name__)

寫一個 function 當進入網站時,render template

template = '''
<!DOCTYPE html>
<html lang="en">
    <body>
        <img src="{{ url_for('video_stream') }}" width="100%">
    </body>
</html>
'''

@app.route("/", methods=['GET'])
def get_stream_html():
    return render_template_string(template)

實作一個 api,從前面準備好的 StreamingOutput instance 讀取資料,不斷丟到 Response 裡,瀏覽器就能不斷刷新 img,實現直播的畫面

def gen_frames():
    while True:
        with output.condition:
            output.condition.wait()
            frame = output.frame
        
        yield (b'--frame\r\nContent-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

@app.route('/api/stream')
def video_stream():
    return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

最後啟動 flask dev server 即可

app.run(host='0.0.0.0')

若只有這樣寫,按下 ctrl+c 中止 server 會有錯誤拋出,因沒有正確關閉相機導致。需要在後面補上 cam.stop() ,當 server 中斷後程式會往下跑並關閉相機,讓整個 process 正常退出

app.run(host='0.0.0.0')

cam.stop()

到此 code 已全部寫完,在 console 跑看看

$ python stream.py
如何用 Raspberry pi 作 Webcam?

打開瀏覽器前往 server 位置,此例為 http://192.168.68.70:5000 ,就能看到即時轉播的畫面了!

如何用 Raspberry pi 作 Webcam?


延伸閱讀:如何用 OpenCV + Flask 快速搭建影像串流?

安裝 OBS 並建立虛擬相機

OBS 為 Open Broadcaster Software 的簡稱,在這裡免費下載,Windows、Mac、Linux 三平台皆支援!

如何用 Raspberry pi 作 Webcam?

安裝完開啟 OBS ,找到 來源 區塊中的 + 按鈕點下去建立新的視訊來源

如何用 Raspberry pi 作 Webcam?

跳出選單中選擇 瀏覽器

如何用 Raspberry pi 作 Webcam?

取個名稱,這邊以 pi camera 為例,按下確定

如何用 Raspberry pi 作 Webcam?

於下一個設定對話框中設定參數:

  • 網址:填入剛架設好的視訊串流 server 網址,這邊以 http://192.168.68.70:5000 為例
  • 寬度與高度:填入在 stream.py 中設定的值 19201080
如何用 Raspberry pi 作 Webcam?

按下確定回到主畫面,就能看到從 Raspberry pi 即時串流過來的影像。如果串流時 Raspberry pi 發生暫時離線或者畫面黑屏,可以點 OBS 中間的 重新整理 按紐恢復正常。

如何用 Raspberry pi 作 Webcam?

最後一步,點 OBS 右下角的 啟動虛擬相機 ,就可以去 Google Meet 試試看囉!

在 Google Meet 中使用 Raspberry pi 視訊鏡頭

於 Google Meet 的 Audio & Video 設定中,將 Camera 改成 OBS Virtual Camera 即可

如何用 Raspberry pi 作 Webcam?

That’s it! 只要 Raspberry pi 和電腦在同一個 wifi 下都可以串流此土砲的視訊鏡頭,換句話說,如果在公用 wifi 任何人也能串流,因此還是建議在自家 wifi 下使用!

如果想讓 Raspberry pi 一開機就啟動串流 server,可以將 script 放入系統 service 中,作法可以求助估狗大神(或是 chatGPT XD),這邊就不贅述了

希望大家都能土砲成功!

延伸閱讀

如何用 OpenCV + Flask 快速搭建影像串流?

參考資料

DIY a Webcam for MacBook with Raspberry Pi 

Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。 離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。 可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。