顯示具有 python 標籤的文章。 顯示所有文章
顯示具有 python 標籤的文章。 顯示所有文章

2025年9月24日 星期三

Raspberry Pi 3 + USB 網路攝影機:使用 Python Flask 建立 IP 串流視訊應用的

 

Raspberry Pi 3 + USB 網路攝影機:使用 Python Flask 建立 IP 串流視訊應用的優缺點分析

身為一個 AIOT 專家,我將為您深入分析使用 Raspberry Pi 3(樹莓派 3)搭配 USB 網路攝影機,並透過 Python Flask 建立 IP 串流視訊應用的優缺點。這個方案在 AIOT 領域非常常見,了解它的特性將幫助您更好地規劃您的專案。

優點 (Advantages)

  1. 高性價比 (Cost-Effective):

    • 硬體成本低: Raspberry Pi 3 和市面上的 USB 網路攝影機價格都相當親民。這使得它成為個人專案或小規模部署的理想選擇,能以極低的預算實現視訊監控功能。

  2. 開放且靈活 (Open and Flexible):

    • 軟體環境成熟: 樹莓派作業系統(Raspberry Pi OS)基於 Linux,您可以輕鬆安裝 Python、Flask 和 OpenCV 等豐富的開源函式庫。這讓您能完全掌控整個應用程式的開發和客製化。

    • 功能擴展性強: 除了視訊串流,您還可以利用樹莓派的 GPIO 腳位連接其他感測器(如溫濕度、移動感測器),並將這些數據與視訊流整合,建立一個多功能的監控系統。

  3. 學習與開發門檻低 (Low Barrier to Entry):

    • 程式碼簡單: 如前所述的 Flask 結合 OpenCV 程式碼,邏輯清晰、易於理解。對於有 Python 基礎的開發者來說,可以在短時間內快速建立原型。

  4. 去中心化部署 (Decentralized Deployment):

    • 邊緣運算能力: 樹莓派是一個邊緣運算設備,它可以直接在裝置端處理影像。這不僅可以減少對雲端伺服器的頻寬依賴,還能實現低延遲的即時處理,例如在本地端進行移動偵測後再決定是否發送告警訊息到雲端平台。


缺點 (Disadvantages)

  1. 效能瓶頸 (Performance Bottlenecks):

    • CPU 限制: Raspberry Pi 3 的 CPU 效能有限,在處理高解析度(如 1080p)或高幀率(高於 30 FPS)的視訊流時,可能會出現幀率下降、畫面卡頓的情況。

    • 無法勝任複雜運算: 如果您計畫在影像串流中加入複雜的 AI 運算,如即時人臉辨識或多目標物體追蹤,Raspberry Pi 3 的效能可能不足以應付,這會導致處理速度非常慢。

  2. 穩定性與可靠性 (Stability and Reliability):

    • 不適合 7x24 小時連續運作: 雖然樹莓派可以長時間運行,但在沒有適當散熱措施的情況下,長時間處理視訊可能會導致晶片過熱,影響系統穩定性。

    • USB 介面限制: 樹莓派的 USB 介面與乙太網路介面共用同一匯流排,大量數據傳輸可能會相互影響,導致網路速度下降或視訊卡頓。

  3. 軟體維護與部署 (Software Maintenance and Deployment):

    • 手動部署: 雖然 Docker 可以簡化部署,但對於單一裝置來說,您仍需手動或透過腳本來部署和維護作業系統與應用程式,這對於大規模部署來說較為麻煩。

  4. 安全性考量 (Security Concerns):

    • 預設設定: 許多預設的樹莓派作業系統設定可能不夠安全,您需要額外配置防火牆、使用者權限和加密傳輸等措施,以保護您的視訊串流不被未經授權的人存取。

結論

綜合來看,使用 Raspberry Pi 3 搭配 USB 網路攝影機來建立 IP 串流視訊應用,對於個人專案、實驗或小規模的室內監控來說是一個極佳且具成本效益的選擇

然而,如果您需要部署一個商業級、要求高穩定性和高效能的應用(例如,需要即時處理 4K 視訊或連續 24 小時不間斷運作),那麼您可能需要考慮效能更強大的硬體,例如 Raspberry Pi 4、NVIDIA Jetson 系列或專用的 IPC (工業電腦),並搭配更強大的伺服器架構來處理影像數據。

2017年7月20日 星期四

物件導向程式設計:為何說composition優於inheritance?

https://tw.twincl.com/programming/*662v


物件導向程式設計:為何說composition優於inheritance?

http://joostdevblog.blogspot.tw/2014/07/why-composition-is-often-better-than.html
學過物件導向程式設計的人,都知道繼承(inheritance)與複合(composition)這兩種觀念。前者是「is a」,後者則是「has a」的關係。近年來很多人提倡「favor composition over inheritance」,我也是支持者之一,但為何這樣,三言兩語又很難講清楚。我只能說,以前維護Java程式碼的時候,那一層又一層的繼承關係讓人腦袋發脹。

最近在整理一門JavaScript進階課程教材的過程中,剛好寫到JavaScript物件導向程式設計這個單元。我想起一年多前讀過的一篇好文:Why composition is often better than inheritance,作者Joost van Dongen是一位C++遊戲開發者,文章內容及舉的例子都很精彩,是那種有多年實戰經驗的人才寫得出來的東西。

我認為「composition over inheritance」這個觀念值得弄清楚,所以花了一些時間翻譯這篇文章,並與大家分享。


Photo credit: geraldford@flickr

以下是這篇文章的摘要翻譯。

在物件導向程式設計裡,要採用複合或繼承,是一個常見的問題。有時答案很明顯,例如「椅子有坐墊」屬於複合關係(has a),而「椅子是一種家具」則是繼承關係(is a)。但很多時候,該採用那種關係,答案並非顯而易見。例如遊戲中的某個角色,應該要「有碰撞外框」(has a collision box),或者應該「是一種可碰撞物件」(is a collidable object)?這兩種不同的做法,都可以用來處理碰撞問題,到底該用哪種好呢?根據我的經驗,若順著直覺,我們傾向採用繼承,但它可能造成許多問題;在很多情況下,複合其實是更好的選擇。

讓我們來看一個實際例子。在遊戲中,我們建立了一個類別,用來處理遊戲角色的物理行為,包括重力、反彈、滑行、跳躍等等。我們可以讓Character(角色)繼承PhysicsObject(物理物件),也可以讓Character有一個PhysicsObject物件。

簡化過的程式碼大概長這樣:(CharacterInheritance及CharacterComposition分別採用繼承及複合兩種做法)

class PhysicsObject
{
  Vector2D position;

  void updatePhysics();
  void applyKnockback(Vector2D force);
  Vector2D getPosition() const;
};

// Using PhysicsObject through inheritance
class CharacterInheritance: PhysicsObject
{
  void update()
  {
    updatePhysics();
  }
};

// Using PhysicsObject through composition
class CharacterComposition
{
  PhysicsObject physicsObject;

  void update()
  {
    physicsObject.updatePhysics();
  }

  void applyKnockback(Vector2D force)
  {
    physicsObject.applyKnockback(force);
  }

  void getPosition() const
  {
    return physicsObject.getPosition();
  }
};
如同你看到的,CharacterInheritance的程式碼要短得多,而且看起來更自然,不需要再另外寫applyKnockback、getPosition這類輔助方法。然而,在同時採用這兩種寫法多年之後,我學到的教訓是:複合的架構在這類情況下比起繼承更有彈性、不容易有bug,也更容易了解。

1. 彈性

讓我們從彈性(flexibility)開始講起。

假設我們想在遊戲中創造一種新的敵人角色,這種敵人由兩個物體組成,中間連著一條能量鏈,任何碰到能量鏈的人都會受到傷害。這兩個物體可以各自移動,增加打敗這種敵人的挑戰,因此使遊戲變得更吸引人。兩個物體都有各自的物理行為,碰撞其中一個物體並不影響另外一個物體,但它們實際上是同一個角色:同一組生命值,同一個AI(人工智慧),同時出現在一個小地圖(minimap)上。


Picture from Joost's Dev Blog

若我們採用複合架構,創造這種新敵人角色就變得很容易,因為我們只需讓新角色擁有幾個PhysicsObjects物件即可。若採用繼承架構,我們就沒辦法用單一角色做到,因為單一角色不能繼承PhysicsObjects兩次。我們可能會採取其它變通方式,但這很快就會使程式碼變得更複雜、更不直覺。

如果你認為這種情況不常發生,不值得擔心,那你可能還沒在一個有相當規模、「遊戲可玩性就是一切(gameplay is king)」的遊戲專案裡待過。遊戲設計者三不五時就會想出一些新的遊戲機制(game mechanics),是你目前程式架構無法處理的例外狀況。如果你說「不」,就會嚴重影響遊戲品質;畢竟最終,遊戲樂趣才是唯一的考量點(好吧,也許加上是否能在專案期限內達成)。

遊戲程式開發的一個重要目標,就是彈性:使你的程式碼具備彈性,不管遊戲設計者今天提出甚麼古怪想法,都能相對容易的加進遊戲裡。在絕大多數情況下,複合要比繼承有彈性得多。

2. 可讀性

我下一個反對繼承的論點,是可讀性(readibility)。可讀性總是伴隨著bug出現的頻率:可讀性越高的代碼,bug出現機會越低,因為如果程式員讀不懂程式,他就容易在修改代碼時把程式弄壞。

我們團隊的其中一條重要原則,是讓每個類別的代碼保持在500行內。雖然有時做不到,但它的目標很清楚:讓類別代碼相對短一些,更容易了解,以便程式員能把整個類別的運作機制裝進腦袋裡。

舉個例子,隨著很多新功能加進來,我們的代碼越長越大,Character和PhysicsObject都長到500行了。我們還加進了Pickup(撿拾)和Projectile(投射),兩者都用到PhysicsObject,也都長到500行。

                        +-----------------+
                        |  PhysicsObject  |
                        +-----------------+
                                 ^
           +---------------------|---------------------+
           |                     |                     |
  +-----------------+   +-----------------+   +-----------------+
  |    Character    |   |     Pickup      |   |   Projectile    |
  +-----------------+   +-----------------+   +-----------------+
在這種情況下,採用繼承架構的代碼,常常令人很困惑。即使我們已盡可能將更多成員保持在私有(private)狀態,最終還是會出現越來越多的保護(protected)及虛擬(virtual)成員。在以上例子,PhysicsObject已經和它的3個子類別Character、Pickup和Projectile糾纏在一起,難以分開。在我的經驗裡面,這件事情幾乎總是會發生:隨著時間過去,繼承的類別一起產生更複雜的行為,彼此糾纏得越來越緊密。

這本身還不是最大問題。現在當我們要了解其中一個類別,就必須了解它們全部:例如,當我們為了給Projectile加進一個新功能而改寫PhysicsObject,此時Character和Pickup也必須同時納入考量。要了解這整件事,程式員現在必須將4個類別、2000行程式碼都裝進他腦袋。以我個人經驗,這很快就變得不可能:程式碼已經多到沒辦法一次同時了解。結果就是代碼可讀性降低,程式員則更容易因為疏忽而造成bug出現。

當然採用複合的架構,並不會使所有問題自動神奇消失,但它確實有助於讓程式碼保持在簡單與可讀的狀態。採用複合架構,就沒有保護(protected)及虛擬(virtual)成員,所以PhysicsObject在一邊,Character、Pickup和Projectile在另一邊,它們之間的界線很清楚。這避免了類別之間隨著時間纏繞在一起,使它們更容易真正保持分開。理論上,採用繼承也能保持類別分開,但根據我的經驗,這在現實上很難維持,而複合則強制你做到這一點。在我們的代碼裡有數不清的例子,採用繼承架構的類別程式碼長得太大,大到再也無法輕易理解。

菱形問題

任何有關繼承與複合的討論,如果不提菱形問題(diamond problem)就談不上完整。例如,類別A繼承B和C,而這二者同時又繼承D,會發生甚麼事?A會繼承D兩次,問題也因此產生。

           +-------+
           |   D   |
           +-------+
               ^
       +-------|-------+
       |               |
   +-------+       +-------+
   |   B   |       |   C   |
   +-------+       +-------+
       ^               ^
       +-------|-------+
               |
           +-------+
           |   A   |
           +-------+
在C++裡,菱形問題的解法有幾種。例如你可以直接接受A有兩個D,或者你也可以用虛擬繼承(virtual inheritance)。但這兩種解法都會造成一堆問題與潛在bug,所以最好是一開始就避免菱形問題。

在遊戲程式的初始架構裡,這種問題通常並不存在,但隨著新功能加入,它可能會偶爾開始出現。問題在於,當它一旦出現,通常很難有好的解法,除非做大量的程式碼重構(refactor)。

不過在我12年的物件導向程式設計經驗裡,菱形問題只出現過幾次,所以它也許不是反對繼承的強有力論點。

(順便一提,即使沒有出現菱形問題,多重繼承的架構也容易變得很骯髒,這在我之前寫的「Hardcore C++: why "this" sometimes doesn't equal "this"」文章中有探討。)

繼承可以用,但少用

這些論點,代表我整體上反對使用繼承嗎?不,絕對不是!繼承對一些事情很有用,例如多型(polymorphism),或者設計模式裡的偵聽者(listner)、工廠(factory)模式等。我的重點是,繼承不像它表面上看起來那麼好用。在多數情況下,繼承也許看似最乾淨的解法,但實務上,複合很可能才是更好的選擇。

2017年6月22日 星期四

pi3 UART by python

#!/usr/bin/env python
import serial

ser = serial.Serial(
  port='/dev/ttyAMA0',
  baudrate = 9600,
  parity=serial.PARITY_NONE,
  stopbits=serial.STOPBITS_ONE,
  bytesize=serial.EIGHTBITS,
  timeout=1
)

print "Serial is open: " + str(ser.isOpen())

print "Now Writing"
ser.write("This is a test")

print "Did write, now read"
x = ser.readline()
print "got '" + x + "'"

ser.close()

port='/dev/ttyAMA0'
 console=/dev/ttyS0,115200