# 下載範例程式 ~$ wget http://max543.com/debugger/class/python02/人臉辨識與物體辨識/code/ch5.zip ~$ unzip ch5.zip ### Lab5-1 ### # 啟動 RTSP Server ~$ raspivid -o - -t 0 -hf --rotation 180 -w 320 -h 240 -fps 15 | cvlc -vvv stream:///dev/stdin --sout '#rtp{sdp=rtsp://:8554}' :demux=h264 # 找出佔用的 Port Number 的 PID  ~$ sudo netstat -lpn |grep 8554 # 刪除佔用的 PID ~$ sudo kill -9 PID ### Lab5-2 ### # VLC media player https://get.videolan.org/vlc/3.0.14/win64/vlc-3.0.14-win64.exe ### Lab5-3 ### # 安裝輕量級的 RTSP Server ~$ cd ~ ~$ git clone https://github.com/mpromonet/h264_v4l2_rtspserver.git ~$ sudo apt-get install liblivemedia-dev libv4l-dev cmake ~$ cd h264_v4l2_rtspserver ~/h264_v4l2_rtspserver$ cmake . ~/h264_v4l2_rtspserver$ make -j4 ~/h264_v4l2_rtspserver$ sudo ./v4l2rtspserver -F 15 -W 800 -H 600 -P 8554 /dev/video0 # 沒有支援旋轉鏡頭參數的指令,也可以用以下的指令: ~$ v4l2-ctl --set-ctrl vertical_flip=1 ### Lab5-4 ### ~$ pip install Flask ### Lab5-5 (app.py) ### from flask import Flask app = Flask(__name__) # Flask 類別初始化時傳入的 __name__ 參數,代表當前模組的名稱。是固定用法,以便讓 Flask 知道在哪裡尋找資源 (template__folder 或 static_folder 資料夾位置) @app.route('/') # 定義路由路徑,告訴 Flask,哪個 URL 應該觸發我們的函式。/ 指的是 web root (URL) (又稱為 Controller) def hello_world(): # 定義一個接著要觸發的函式 return 'Hello, World!' # 函式回傳的文字字串 (又稱為 View) ### Lab5-6 (5-1-app-hello.py) ### from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello Flask' if __name__ == '__main__': # 是直接運行的才會執行 app.run() 這個方法 app.run(host = '0.0.0.0', port = 80, debug = True) ### Lab5-7 ### # 查找哪一個 python 程序正在執行中 $ ps -fA | grep python # 刪除 root 占用的程序 $ sudo kill -9 PID ### Lab5-8 ### # 新增一個資料夾 templates,與一個網頁檔 link.html ~$ mkdir templates && cd templates ~/templates$ nano link.html # link.html 的內容

Hello Template

foo # 再新增一個 bar.html ~/templates$ nano bar.html # bar.html 的內容 ### Lab5-9 (5-2-app-route.py) ### from flask import Flask, render_template, Response # render_template 用來使用 html app = Flask(__name__) @app.route('/') def index(): return render_template('link.html') # View 可由自訂的樣板產生 @app.route('/foo') def foo(): extns = ['Flask', 'Jinja2', 'Awesome'] # 樣板內可塞變數 return render_template('bar.html', extns = extns) # View 的超連結,並顯示變數 if __name__ == '__main__': app.run(host = '0.0.0.0', port = 80, debug = True) ### Lab5-10 (stream_pi.py) ### from time import time class Camera(object): def __init__(self): self.frames = [open('static/' + f + '.jpg', 'rb').read() for f in ['1', '2', '3']] def get_frame(self): # get_frame 每三秒讀取一張圖片,並回傳該張 frame return self.frames[int(time()) % 3] ### Lab5-11 (5-3-app-stream.py) ### from flask import Flask, render_template, Response from stream_pi import Camera app = Flask(__name__) @app.route('/') def index(): return render_template('stream.html') def gen(camera): while True: frame = camera.get_frame() # Camera 類別 yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n') @app.route('/video_feed') def video_feed(): return Response(gen(Camera()), # 回傳內容 mimetype = 'multipart/x-mixed-replace; boundary = frame') if __name__ == '__main__': app.run(host = '0.0.0.0', port = 80, debug = True) ### Lab5-12 ### # 新增一個 stream.html $ nano templates/stream.html # stream.html 的內容

Hello Stream

### Lab5-13 ### import cv2 class Camera(object): def __init__(self): self.video = cv2.VideoCapture(0) # 開啟 /dev/videoX,預設的 camera 是 0 def __del__(self): self.video.release() def get_frame(self): success, image = self.video.read() # V4L2 的 API ret, jpeg = cv2.imencode('.jpg', image) return jpeg.tostring() ### Lab5-14 (5-4-app-camera.py) ### from flask import Flask, render_template, Response from camera_pi import Camera app = Flask(__name__) @app.route('/') def index(): return render_template('stream.html') def gen(camera): while True: frame = camera.get_frame() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n') @app.route('/video_feed') def video_feed(): return Response(gen(Camera()), mimetype = 'multipart/x-mixed-replace; boundary = frame') if __name__ == '__main__': app.run(host = '0.0.0.0', port = 80, debug = True) ### Lab5-15 ### ~$ sudo pip install numpy==1.21.4 ~$ sudo pip install opencv-python==4.5.4.60 ~$ sudo pip install opencv-contrib-python==4.5.4.60 ### Lab5-16 (camera_pi_v2.py) ### import cv2 class Camera(object): def __init__(self): if cv2.__version__.startswith('2'): # 若是 OpenCV 是 2.X 的版本 PROP_FRAME_WIDTH = cv2.cv.CV_CAP_PROP_FRAME_WIDTH PROP_FRAME_HEIGHT = cv2.cv.CV_CAP_PROP_FRAME_HEIGHT elif cv2.__version__.startswith('3'): # 若是 OpenCV 是 3.X 的版本 PROP_FRAME_WIDTH = cv2.CAP_PROP_FRAME_WIDTH PROP_FRAME_HEIGHT = cv2.CAP_PROP_FRAME_HEIGHT else: # 若是 OpenCV 是其他的版本 PROP_FRAME_WIDTH = cv2.CAP_PROP_FRAME_WIDTH PROP_FRAME_HEIGHT = cv2.CAP_PROP_FRAME_HEIGHT self.video = cv2.VideoCapture(0) #self.video = cv2.VideoCapture(1) #self.video.set(PROP_FRAME_WIDTH, 640) #self.video.set(PROP_FRAME_HEIGHT, 480) self.video.set(PROP_FRAME_WIDTH, 320) # 改變視窗的寬 self.video.set(PROP_FRAME_HEIGHT, 240) # 改變視窗的高 def __del__(self): self.video.release() def get_frame(self): success, image = self.video.read() ret, jpeg = cv2.imencode('.jpg', image) # 調整 JPG 壓縮品質 return jpeg.tostring() ### Lab5-17 ### ~$ cd ~/ch05/project_opencv ~/project_opencv$ sudo python3 app-opencv.py ### Lab5-18 ### ~$ cd ~/ch05/project_opencv+line ~/project_opencv+line$ sudo python3 app-opencv+line.py