2024年11月16日 星期六

MicroPython 學習筆記 : ESP32-WROVER-DEV 開發板測試 (三)

本篇主要是紀錄 camera 模組的初始化函式的改寫, 本系列之前的文章參考 :


在前兩篇的測試中所使用的初始化函式寫法其實有 bug, 原寫法如下 :

import time, camera
from machine import reset

def init_camera(**config): # 初始化鏡頭
    camera.init(
        0, d0=4, d1=5, d2=18, d3=19, d4=36, d5=39, d6=34, d7=35,
        href=23, vsync=25, reset=-1, sioc=27, siod=26, xclk=21,
        pclk=22, fb_location=camera.PSRAM, format=camera.JPEG, 
        xclk_freq=camera.XCLK_10MHz, framesize=camera.FRAME_QVGA,
        **config)
    
def capture_image(file_name='capture.jpg'): # 拍攝照片並存檔 
    time.sleep(2)    # 等待攝像頭穩定
    buf=camera.capture()
    if buf:
        with open(f'/{file_name}', 'wb') as f:
            f.write(buf)
        print(f'Image has been saved as {file_name}')
    else:
        print('Failed to capture image')
    camera.deinit()
    del buf

其中 init_camera() 函式的傳入參數使用可變長度參數 **config,  原意是想如果要更改這些參數的預設值 (例如解析度預設是 QVGA 想改為 VGA), 就在呼叫 init_camera() 時傳給 **config, 例如 :

init_camera(framesize=camera.FRAME_VGA) 

但這樣會出現參數重複的錯誤 (extra keyword arguments given) : 

>>> init_camera(framesize=camera.FRAME_VGA)      
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in init_camera
TypeError: extra keyword arguments given   

實踐原意的正確做法應該是要用字典的 setefault() 函式來設定傳入之關鍵字參數 :

import time, camera
from machine import reset
    
def init_camera(**config): # 初始化鏡頭
    config.setdefault('fb_location', camera.PSRAM) 
    config.setdefault('format', camera.JPEG)  
    config.setdefault('xclk_freq', camera.XCLK_10MHz)  
    config.setdefault('framesize', camera.FRAME_QVGA)   
    camera.init(
        0, d0=4, d1=5, d2=18, d3=19, d4=36, d5=39, d6=34, d7=35,
        href=23, vsync=25, reset=-1, sioc=27, siod=26, xclk=21,
        pclk=22, **config)

def capture_image(file_name='capture.jpg'): # 拍攝照片並存檔 
    time.sleep(2)    # 等待攝像頭穩定
    buf=camera.capture()
    if buf:
        with open(f'/{file_name}', 'wb') as f:
            f.write(buf)
        print(f'Image has been saved as {file_name}')
    else:
        print('Failed to capture image')
    camera.deinit()
    del buf

其實這四個用 setdefault() 設定初始值的參數通常只有 xclk_freq 與 framesize 會需要設定.

測試結果如下 :

不傳入參數的話預設解析度是 320*240 : 

>>> init_camera()      
0
4
10000000
5
True
>>> capture_image()      
8872
Image has been saved as capture.jpg
True

可見呼叫 dict 的 setdefault() 時會傳回設定值. 




如果傳入 framesize 參數指定 VGA, 則解析度變成 640*480 :

>>> init_camera(framesize=camera.FRAME_VGA)   
0
4
10000000
8
True
>>> capture_image()    
cam_hal: EV-EOF-OVF
cam_hal: EV-EOF-OVF
cam_hal: EV-EOF-OVF
cam_hal: EV-VSYNC-OVF
cam_hal: EV-EOF-OVF
cam_hal: EV-VSYNC-OVF
cam_hal: EV-EOF-OVF
21140
Image has been saved as capture.jpg
True



下面範例是同時設定 framesize=VGA 與 xclk_freq=20mM 參數 :

>>> init_camera(framesize=camera.FRAME_VGA, xclk_freq=camera.XCLK_20MHz)   
0
4
20000000
8
True
>>> capture_image()    
cam_hal: EV-EOF-OVF
16460   
Image has been saved as capture.jpg
True




結果頻率高檔案大小比較小, 這可能是因為時脈越高, 影像數據擷取速率快, 引入較多信號噪音, 提高了演算法的壓縮比所致. 

沒有留言 :