python
複製程式碼
import network
import socket
import camera
import time
import gc
# Wi-Fi 设置
SSID = "Bili-Net"
PASSWORD = "0932388283"
# 初始化摄像头
def init_camera():
try:
camera.init()
# 设置摄像头参数
camera.framesize(7) # VGA (640x480)
camera.pixformat(3) # JPEG 格式
camera.quality(10) # 图像质量,1-63,数值越小质量越高
print("摄像头初始化成功")
except Exception as e:
print("摄像头初始化失败:", e)
# 连接 Wi-Fi
def connect_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
print('正在连接到 Wi-Fi...')
while not wlan.isconnected():
time.sleep(1)
ip = wlan.ifconfig()[0]
print('连接成功,IP 地址为:', ip)
return ip
# 生成网页内容
def web_page():
html = """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ESP32-CAM 实时图像</title>
<style>
body {text-align: center; font-family: Arial;}
img {width: 100%; max-width: 640px;}
</style>
<script>
function refreshImage() {
var img = document.getElementById("camera");
img.src = "/image.jpg?t=" + new Date().getTime();
}
setInterval(refreshImage, 500); // 每 500 毫秒刷新一次图像
</script>
</head>
<body>
<h1>ESP32-CAM 实时图像</h1>
<img id="camera" src="/image.jpg" alt="Camera Image">
</body>
</html>
"""
return html
# 处理客户端请求
def handle_client(conn):
try:
request = conn.recv(1024)
request = request.decode('utf-8')
print('客户端请求:', request)
if 'GET /image.jpg' in request:
# 捕获图像并直接发送
img = camera.capture()
if img:
# 发送响应头
conn.send(b'HTTP/1.1 200 OK\r\n')
conn.send(b'Content-Type: image/jpeg\r\n')
conn.send(b'Connection: close\r\n\r\n')
# 发送图像数据
conn.sendall(img)
print("已发送图像数据,大小为:", len(img))
del img # 释放内存
gc.collect()
else:
# 如果捕获失败,发送 503 错误
conn.send(b'HTTP/1.1 503 Service Unavailable\r\n')
conn.send(b'Content-Type: text/plain\r\n')
conn.send(b'Connection: close\r\n\r\n')
conn.send(b'Unable to capture image')
else:
# 发送网页
response = web_page()
conn.send(b'HTTP/1.1 200 OK\r\n')
conn.send(b'Content-Type: text/html; charset=utf-8\r\n')
conn.send(b'Connection: close\r\n\r\n')
conn.sendall(response.encode('utf-8'))
except Exception as e:
print('处理客户端请求时发生错误:', e)
finally:
conn.close()
gc.collect()
# 启动服务器
def start_server():
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(5)
print('服务器正在运行,等待客户端连接...')
return s
# 主程序
def main():
ip = connect_wifi(SSID, PASSWORD)
init_camera()
s = start_server()
while True:
try:
conn, addr = s.accept()
print('连接来自:', addr)
handle_client(conn)
except Exception as e:
print('接受连接时发生错误:', e)
import sys
sys.print_exception(e)
if __name__ == '__main__':
main()
在 init_camera() 函数中,将 camera.framesize(5) 改为 camera.framesize(7),其中:
framesize(7) 对应 VGA 分辨率,即 640x480。
python
複製程式碼
def init_camera():
try:
camera.init()
# 设置摄像头参数
camera.framesize(7) # VGA (640x480)
camera.pixformat(3) # JPEG 格式
camera.quality(10) # 图像质量
print("摄像头初始化成功")
except Exception as e:
print("摄像头初始化失败:", e)
在 handle_client() 函数中,修改了处理 /image.jpg 请求的部分,直接捕获图像并发送,而不再保存为文件。
python
複製程式碼
if 'GET /image.jpg' in request:
# 捕获图像并直接发送
img = camera.capture()
if img:
# 发送响应头
conn.send(b'HTTP/1.1 200 OK\r\n')
conn.send(b'Content-Type: image/jpeg\r\n')
conn.send(b'Connection: close\r\n\r\n')
# 发送图像数据
conn.sendall(img)
print("已发送图像数据,大小为:", len(img))
del img # 释放内存
gc.collect()
else:
# 如果捕获失败,发送 503 错误
conn.send(b'HTTP/1.1 503 Service Unavailable\r\n')
conn.send(b'Content-Type: text/plain\r\n')
conn.send(b'Connection: close\r\n\r\n')
conn.send(b'Unable to capture image')
删除已使用的对象:在发送完图像数据后,使用 del img 删除图像对象,释放内存。
手动进行垃圾回收:调用 gc.collect(),进一步释放未使用的内存。
修改 JavaScript 中的刷新间隔:将刷新间隔设置为 500 毫秒(每秒 2 帧),以适应较大的图像尺寸和处理时间。
html
複製程式碼
setInterval(refreshImage, 500); // 每 500 毫秒刷新一次图像
说明:由于 VGA 分辨率的图像数据量更大,处理和传输时间更长,适当降低刷新频率可以提高稳定性。
在各个函数中添加了异常处理,捕获并打印可能发生的错误,提高程序的稳定性。
供电要求:使用 VGA 分辨率时,ESP32-CAM 的功耗会增加,建议使用稳定的 5V 2A 外部电源供电,避免因供电不足导致的问题。
内存限制:ESP32 的内存有限,使用较高的分辨率可能会占用更多的内存。如果出现内存不足的问题,可以尝试降低图像质量 camera.quality(15),或者使用更低的分辨率。
将代码中的 SSID 和 PASSWORD 替换为您的实际 Wi-Fi 名称和密码。
将完整的代码复制并粘贴到 Thonny 的编辑器中,保存为 main.py。
通过 Thonny 将代码上传到 ESP32-CAM。
重启 ESP32-CAM,或者在 Thonny 中点击 “运行” 按钮。
在 Thonny 的 Shell 窗口中,您将看到程序的输出,包括 Wi-Fi 连接状态、摄像头初始化状态、服务器运行状态等。
在浏览器中输入 ESP32-CAM 的 IP 地址,例如:http://192.168.0.135。
您将看到一个网页,每隔 500 毫秒刷新一次,显示摄像头的实时图像。
症状:程序崩溃、重启,或者出现内存分配错误。
解决方案:
降低图像质量:增大 camera.quality() 的数值,例如 camera.quality(15)。
降低分辨率:如果内存仍然不足,可以考虑使用较低的分辨率,例如 QVGA (camera.framesize(5))。
优化内存管理:确保在适当的位置调用 gc.collect() 进行垃圾回收。
原因:较高的分辨率和图像质量导致处理和传输时间增加。
解决方案:
调整刷新间隔:根据实际情况,适当调整 JavaScript 中的刷新间隔。
降低图像质量或分辨率:减小图像大小,提高传输速度。
原因:摄像头模块连接不良,或者参数设置不正确。
解决方案:
检查摄像头连接:确保摄像头模块与 ESP32-CAM 板连接牢固,没有松动。
调整摄像头参数:尝试不同的 framesize、pixformat 和 quality 参数。
希望这份更新的代码和说明能帮助您成功地将摄像头分辨率改为 VGA,并实现更好的功能。如果您在使用过程中遇到任何问题,或者有其他需求,请随时告诉我,我会尽力协助您。