ESP32-S3 CAM + OV3660 MicroPython 完整使用教程
·
本教程针对果云科技下的产品 ESP32-S3 CAM 开发板 + OV3660 同时想要使用micropython的,在这里注意了,如果各位还没有去买,请去买乐鑫旗下的产品,乐鑫已经公开了ESP32-S3 CAM 系列的例程库,很方便使用,至于博主为啥不买,呜呜呜~这里的痛苦不多做赘述,相信跟博主处于相同境遇下的小伙伴能够感同身受。为此,博主在实践过后总结了以下使用教程,主要还是借鉴了乐鑫官方的例程库进行参考试出来的,如果有小伙伴们有其他方案,欢迎在博主评论下留言给出更好的方案。
一、使用前必读
- OV3660 与 OV2640 不通用默认例程,直接刷网上例程 100% 失败
- 必须使用 支持 ESP32-S3 CAM 的 MicroPython 固件(果云给的固件,这里注意,必须要用烧录软件进行固件的烧录,不要使用Thonny内置的烧录,否则会出现异常)
- 必须开启 PSRAM(8MB/16MB),否则拍照会直接崩溃
- 本代码已自动处理:重复初始化、JPEG 验证、结束符截断、大小限制
- 关于后续,如果后续大家有其他需要,可以在评论中留言,我看到会总结一下再次把相关问题进行解决并发布的~
二、硬件信息
- 主控:ESP32-S3
- 摄像头:OV3660
- 接口:DVP 并行接口
- 最大分辨率:UXGA (2048×1536)
- 本工程推荐使用:QVGA(320×240) 或 VGA(640×480) 最稳定,其余的像SVGA,XGA均无法使用,各位也可以尝试一下其他分辨率看能否使用。
- 针脚图

三、软件环境
- 编程工具:Thonny(https://thonny.org/)

- 固件:ESP32-S3 MicroPython(带 camera 驱动 + PSRAM 使能)
- 库依赖:
camera、ubinascii、time(均为内置库,无需安装)
四、函数 API 文档
1. camera.init(channel, format=..., framesize=...)
功能:初始化摄像头硬件(DVP、时钟、传感器、DMA、PSRAM)。
camera.init(channel, format=camera.JPEG, framesize=camera.FRAME_QVGA)
参数:
-
channel:int 固定填
0(ESP32‑S3 CAM 只有 1 路摄像头) -
format:int 图像输出格式
camera.JPEG(OV3660 唯一稳定可用)camera.GRAYSCALEcamera.RGB565camera.YUV422
-
framesize:int 输出分辨率(OV3660 全部支持)
返回值: 无,失败直接抛出异常
异常: 初始化失败、传感器无响应、PSRAM 错误
2.camera.capture()
功能:捕获一帧图像,返回原始字节流(JPEG / RGB / GRAY)
frame = camera.capture()
返回值:
- 成功:
bytes图像数据 - 失败:
None
说明:
- OV3660 输出为标准 JPEG 数据
- 包含
0xFFD8开头、0xFFD9结尾
3.camera.deinit()
功能:关闭摄像头、释放时钟、关闭 DVP、释放 DMA 内存
camera.deinit()
说明:
- 重新初始化前必须调用
- 防止重复初始化导致死机
4. 常量(分辨率 framesize)
全部 OV3660 实测可用:
| camera.FRAME_QQVGA | 160x120 |
| camera.FRAME_QVGA | 320x240 |
| camera.FRAME_VGA | 640x480 |
| camera.FRAME_QXGA | 2048x1536 |
五. OV3660 重要注意事项
- 必须启用 PSRAM,否则无法捕获图像
- 只支持 JPEG 输出稳定
- 初始化前必须先
deinit() - 分辨率越高,速度越慢、内存占用越大
- 图像数据必须检查
FF D8开头和FF D9结尾 - MicroPython 固件必须是 ESP32‑S3 CAM 专用版
六. 使用教程
1.工具函数
这里为了方便大家使用,我将核心使用封装为一个utils工具函数文件,使用这个文件足够大家在很多情况下进行摄像头的使用了。
# camera_utils.py
# ESP32-S3 CAM + OV3660 MicroPython 稳定驱动
# 功能:摄像头初始化、拍照、JPEG验证、自动裁剪结束符、大小限制、Base64编码
import camera
import ubinascii
import time
def init_camera(camera_format, frame_size):
"""
摄像头初始化(自动防卡死、重复初始化)
:param camera_format: 图像格式 → camera.JPEG 最稳定
:param frame_size: 分辨率 → 推荐 QVGA(320x240) / VGA(640x480)
:return: True 成功 / False 失败
"""
# 尝试关闭之前的摄像头(防止占用)
try:
camera.deinit()
except:
pass
time.sleep(1)
try:
# OV3660 核心初始化
camera.init(0, format=camera_format, framesize=frame_size)
print("摄像头初始化成功")
return True
except Exception as e:
print(f"摄像头初始化失败: {e}")
return False
def capture_and_encode_image():
"""
拍照 → 验证JPEG → 自动截尾 → 大小限制 → Base64编码
:return: base64 图像字符串 / None
"""
try:
# 1. 捕获一帧图像
frame = camera.capture()
if not frame:
print("摄像头捕获失败")
return None
print(f"捕获图像: {len(frame)} 字节")
# 2. 验证 JPEG 数据是否有效
is_valid, msg = validate_jpeg_data(frame)
if not is_valid:
print(f"JPEG验证失败: {msg}")
return None
# 3. 寻找 JPEG 结束符 0xFFD9 并截断(解决数据尾脏数据)
jpeg_end_pos = -1
for i in range(len(frame) - 1):
if frame[i] == 0xFF and frame[i+1] == 0xD9:
jpeg_end_pos = i + 2
break
if jpeg_end_pos == -1:
print("找不到JPEG结束标记")
return None
# 截取有效图像
valid_frame = frame[:jpeg_end_pos]
# 4. 图像大小限制(可根据需求修改)
max_size = 3000 # 3KB 限制
if len(valid_frame) > max_size:
print(f"图像太大 ({len(valid_frame)} > {max_size} 字节),丢弃")
return None
# 5. 转 Base64
img_b64 = ubinascii.b2a_base64(valid_frame).decode().strip()
img_b64 = img_b64.replace('\n', '').replace('\r', '')
print(f"编码完成: {len(img_b64)} 字符")
return img_b64
except Exception as e:
print(f"捕获/编码错误: {e}")
return None
def validate_jpeg_data(jpeg_data):
"""
JPEG 完整性验证
检查:开头 0xFFD8 + 结尾 0xFFD9
"""
try:
if len(jpeg_data) < 4:
return False, "数据太短"
# JPEG 必须以 0xFFD8 开头
if jpeg_data[0] != 0xFF or jpeg_data[1] != 0xD8:
return False, "不是有效的JPEG文件头"
# 必须包含结束符 0xFFD9
has_end_marker = False
for i in range(len(jpeg_data) - 1):
if jpeg_data[i] == 0xFF and jpeg_data[i+1] == 0xD9:
has_end_marker = True
break
if not has_end_marker:
return False, "JPEG缺少结束标记"
return True, "JPEG数据有效"
except Exception as e:
return False, f"验证异常: {e}"
2.使用示例
# main.py
import camera
from camera_utils import init_camera, capture_and_encode_image
# ==================== 配置区 ====================
# 图像格式:JPEG 最稳定(OV3660 推荐)
CAMERA_FORMAT = camera.JPEG
# 分辨率(选一个)
# frame_size = camera.QVGA # 320x240 最稳定
frame_size = camera.VGA # 640x480 稳定
# frame_size = camera.SVGA # 800x600
# ================================================
print("=== ESP32-S3 CAM OV3660 启动 ===")
# 初始化摄像头
if init_camera(CAMERA_FORMAT, frame_size):
# 拍照并获取 Base64
img_base64 = capture_and_encode_image()
if img_base64:
print("\n 拍照成功!Base64 前50字符:")
print(img_base64[:50], "...")
else:
print("\n 拍照失败")
else:
print("\n 摄像头无法启动")
更多推荐


所有评论(0)