再谈ESP32_CAM视频传输至公网服务器

本文介绍了作者将ESP32Cam的视频流处理从C语言、Node.js和Python分别编写统一到Python的过程,展示了从ESP32连接WiFi、摄像头初始化到建立TCP连接、发送视频流的完整代码,以及服务器端的接收和处理策略。
部署运行你感兴趣的模型镜像

        很久没写文章了,最近闲来无事,又研究了下关于esp32_cam,之前也写过一篇文章,讲述了如何把视频流推送至公网服务器,但是用到的代码很不统一,esp32_cam端用的是c语言,服务器用的是nodejs,拉流客户端用的是python,看上去很别扭,更重要的是,虽然能推流至服务器,但传输效果也不是很理想,于是把三端的代码统一成了python,话不多说,直接上代码。

这里重点说明一下,使用的esp32_cam固件是国外一个老哥开发的,里面带有camera库,使用其他的固件是没有camera库的,需要的小伙伴可以留言或者私信我留下邮箱,我会发给你们。

首先是esp32_cam端代码(使用thonny开发并烧录):

import socket
import network
import camera
import time


# 连接wifi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
    print('connecting to network...')
    wlan.connect('xxxx', 'xxxx')  # 此处替换成自己的wifi和密码
    
    while not wlan.isconnected():
        pass
print('网络配置:', wlan.ifconfig())
 
 
# 摄像头初始化
try:
    camera.init(0, format=camera.JPEG)
    time.sleep(0.5)
except Exception as e:
    camera.deinit()
    # camera.init(0, format=camera.JPEG)


# 其他设置:
# 上翻下翻
camera.flip(1)
#左/右
camera.mirror(1)

# 分辨率
camera.framesize(camera.FRAME_CIF)
# 选项如下:
# FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240
# FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA
# FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA FRAME_FHD
# FRAME_P_HD FRAME_P_3MP FRAME_QXGA FRAME_QHD FRAME_WQXGA
# FRAME_P_FHD FRAME_QSXGA
# 有关详细信息,请查看此链接:https://bit.ly/2YOzizz

# 特效
camera.speffect(camera.EFFECT_NONE)
#选项如下:
# 效果\无(默认)效果\负效果\ BW效果\红色效果\绿色效果\蓝色效果\复古效果
# EFFECT_NONE (default) EFFECT_NEG \EFFECT_BW\ EFFECT_RED\ EFFECT_GREEN\ EFFECT_BLUE\ EFFECT_RETRO

# 白平衡
# camera.whitebalance(camera.WB_HOME)
#选项如下:
# WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME

# 饱和
camera.saturation(0)
#-2,2(默认为0). -2灰度
# -2,2 (default 0). -2 grayscale 

# 亮度
camera.brightness(0)
#-2,2(默认为0). 2亮度
# -2,2 (default 0). 2 brightness

# 对比度
camera.contrast(0)
#-2,2(默认为0).2高对比度
#-2,2 (default 0). 2 highcontrast

# 质量
camera.quality(30)
#10-63数字越小质量越高

# socket TCP 的创建
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('xxx.xxx.xxx.xxx', xxxx))  # 此处替换成自己的公网ip和端口号(端口号是自定义)
time.sleep(0.5)

try:
    while True:
        buf = camera.capture()  # 获取图像数据
        len_buf = len(buf)  # 发送数据长度
        s.sendall(str.encode('%-10s' % len_buf))
        s.sendall(buf)  # 向服务器发送图像数据
        # time.sleep_ms(50)
except Exception as e:
    print(e)
    camera.deinit()
finally:
    camera.deinit()



需要替换的有两处,wifi名称和密码以及公网ip和端口号。

然后上服务器端代码:

import socket
import time

import cv2
import io
from PIL import Image
import numpy as np
import threading

cc = []  # 用来保存已经连接到服务器的摄像头socket
cp = []  # 用来保存已经连接到服务器的电脑socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("0.0.0.0", xxxx))  # 此处填写自定义的端口号,注意,要跟esp32_cam中定义的端口号一致
s.listen(10)


def receive_all(sock, count):
    buf = b''
    while count:
        recv_data_temp = sock.recv(count)
        if not recv_data_temp:
            return None
        buf += recv_data_temp
        count -= len(recv_data_temp)
    return buf


def client_camera(clientsocket):
    global cp
    global cc
    print('摄像头已连接')
    while True:
        # 注释调两个if语句后,视频流会相对流畅一些
        if clientsocket.recv(1024) == b'':
            print('摄像头已退出')
            cc = []
            break
        if len(cp) == 0:
            time.sleep(1)
            continue
        try:
            length = receive_all(clientsocket, 10)
            data = receive_all(clientsocket, int(length))  # 目前只设计为一个摄像头和一台pc
            len_buf = len(data)  # 发送数据长度
            cp[0].sendall(str.encode('%-10s' % len_buf))
            cp[0].sendall(data)
        except Exception as e:
            pass
            # print(f'摄像头以退出:{e}')


def client_pc(clientsocket):
    global cp
    while True:
        time.sleep(1)
        if clientsocket.recv(1024) == b'':
            print('客户端已退出')
            cp = []
            break


while True:
    # 接收所有连接,每受到一个客户端,就启动一个新线程
    clientsocket, addr = s.accept()
    try:
        if clientsocket.recv(1024).decode('utf-8') == 'client':  # 说明该消息是客户端pc发送的拉流请求
            cp.append(clientsocket)
            print(cp)
            threading.Thread(target=client_pc, args=(clientsocket,)).start()
        else:  # 说明是摄像头推流的请求
            cc.append(clientsocket)
            threading.Thread(target=client_camera, args=(clientsocket,)).start()
            print(cc)
    except Exception as e:
        clientsocket.close()

此处要修改的是端口号,要跟esp32_cam中自定义的端口号一致,其它的看注释即可

最后上拉流的客户端代码:

import socket
import cv2
import io
from PIL import Image
import numpy as np
import time


def receive_all(sock, count):
    buf = b''
    while count:
        recv_data_temp = sock.recv(count)
        if not recv_data_temp:
            return None
        buf += recv_data_temp
        count -= len(recv_data_temp)
    return buf


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.connect(('xxx.xxx.xxx.xxx', xxx))  # 此处设置公网的ip地址以及自定义的端口号
s.send('client'.encode('utf-8'))
time.sleep(0.5)
while True:
    try:
        length = receive_all(s, 10)
        data = receive_all(s, int(length))
        bytes_stream = io.BytesIO(data)
        image = Image.open(bytes_stream)
        img = np.asarray(image)
        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)  # ESP32采集的是RGB格式,要转换为BGR(opencv的格式)
        cv2.imshow("ESP32 Capture Image", img)
        if cv2.waitKey(1) == ord("q"):
            break
    except Exception as e:
        print(e)

此处要修改的是公网ip和自定义的端口号

        目前代码如果都跑在局网内,效果还是很不错的,我使用的公网带宽是3m,效果嘛你们自己部署后自己看吧,有时间我还会再优化这一套流程,如果有好想法的小伙伴也可以给我留言一起讨论。

您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

esp32-cam视频传输可以通过将视频数据流发送到公网服务器来实现。首先,esp32-cam将数据流发送到公网服务器,然后服务器会将数据原样透传给用户的电脑端。在这个过程中,esp32-cam使用的是C语言,公网服务器端使用的是Node.js,而电脑客户端则使用了Python。这样的传输路径是:esp32-cam -> 公网服务器 -> 电脑客户端。 你需要先启动服务器端代码,然后在电脑端运行Python端代码,最后烧录esp32-cam的代码。第一次运行时,电脑客户端可能会报错并退出,但不用担心,只需重新运行一下电脑客户端的Python代码,就能看到视频图像了。在服务器端的逻辑中,当接收到'monitor'字符串时,会将对应的socket保存下来。当接收到下一个socket连接时,默认认为是esp32-cam,会将之前保存的socket取出来,并将视频流数据转发出去。需要注意的是,这种方式只能支持一个esp32-cam和一个客户端监视器,如果有其他需求,可以自行修改代码。 所有的传输都是在TCP协议下进行的,因此在公网服务器上开端口时,请选择TCP协议。 以上代码和思路参考了博主dsxcode的代码,你可以参考该博主的博客文章进行更详细的了解。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ESP32-CAM视频传输公网服务器并转发视频数据流](https://blog.youkuaiyun.com/phoenix3k/article/details/128446232)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

phoenix3k

如果觉得满意,就请作者喝杯茶吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值