ESP32CAM人工智能教学15
ESP32CAM人工智能教学15
Flask服务器TCP连接
小智利用Flask在计算机中创建一个虚拟的网页服务器服务器,让ESP32Cam通过WiFi连接,把摄像头拍摄到的图片发送到电脑中,并在电脑中保存成图片文件。
Flask是用Python编写的网页服务程序WebServer。这个程序首先在电脑端用Python编写一个服务器端的程序,并创建一个指向5000端口的网页服务,用于接收ESP32CAM上传的图片数据,并保存成图片文件。
本来这个程序挺简单的,但是在测试程序时一直都过不了。测试程序耗了我三天时间,最后我采用“蚂蚁啃大象”的方法,采用由简及繁的方法,终于攻下难关。本文的测试主要参考博客内容https://blog.51cto.com/u_16213596/7788901
- 第一轮给在线网站发信息
首先我们在计算机中,用Python编写一个客户端的测试程序,然后利用requests驱动库,给网上的一个测试网站发送字符信息,http://httpbin.org/post是网上为我们提供的一个学习测试的网站。
我们在测试程序中,创建一个字典d={‘jpg’,’tupian’},然后把信息发送到测试网页。点击菜单上的Run运行,结果在IDLE Shell窗口中,可以看到(第六行)返回了用户发送给网站的信息”jpg”: ”tupian”。这样表面这个程序的requests的驱动库运行成功了。(当然,运行程序之前,需要在Python中先安装requests的驱动库,安装方法看前一课,可以到清华大学的镜像网站去下载)
- 第二轮给本地Flask服务器发文字、图片信息
我们在Python中安装Flask驱动库,然后编写服务器端的程序test.py。在程序中创建一个一个网页服务,开放计算机的5000端口,并提供一个上传网页,用于接收客户端发送过来的消息。如图所示:客户端访问http://192.168.1.162:5000/updata可以给服务器端发送消息了。
修改客户端程序test02.py,把上传的地址改成本地的Flask服务器的上传网页地址,然后还是给服务器发送消息”jpg”: “tupian”。
接下来是运行测试程序,先运行服务器端的程序test.py,可以看到Flask服务器开启了http://192.168.1.162:5000/。接着运行客户端程序test02.py,可以看到服务器端的IDLE Shell窗口显示一条消息,表示接收到了一条来自客户端的消息,并读取消息字典中名为“jpg”的内容,并组成字符串返回给客户端。在客户端的IDLE Shell窗口中看到了服务器返回的字符串”user”: “tupian”。
接下来这个测试就简单了,首先把客户端中发送的消息“jpg”的内容,更改为一张图片的内容。我们先准备一张图片,命名为333.jpg,和test.py、test02.py一起,都保存在同一个文件夹中(Python的安装目录,我这里是D:\Python312\)。接着,更改服务器端的程序,返回客户端的消息为接收到的数据长度值。
接下来,先运行服务器端的程序,在运行客户端的程序,可以看到在服务器端的Shell看到接收到了数据,在客户端的Shell看到返回的图片文件大小了。这样,这张图片就上传成功了,可以在D:\Python312\中看到两个图片文件:333.jpg是被上传的原图; 555.jpg是上传后保存下的图片, 这个上传过程,就像是左手换右手一样,这两张图的内容是一模一样的。
- 第三轮ESP32Cam读取内存图片发送给Flask
接下来,我们进行的是跨设备之间的传递,我们让ESP32Cam开发板读取内存中的一张图片的数据,然后通过WiFi连接,把图片数据发送到计算机中的Flask服务器中保存下来。
首先,我们在Thonny中连接ESP32Cam,并且下载一个urequests.py文件(如果没有可以复制后面的相关代码内容,然后在这里粘贴上传),上传到ESP32Cam中。
编写ESP32Cam客户端的程序,先连接WiFi,然后连接到服务器上传网页,读取图片内容,上传数据。需要注意的是,这个urequests.py驱动库文件只能传递二进制的数据,无法传递JSON的字符消息,所以在客户端和服务器端的程序,都有相应的小修改。
我们先在Thonny中上传一张图片到ESP32Cam中。打开服务器端的程序,再运行Thonny中的程序,这样就可以看到ESP32Cam内存中的那张图片,上传到了计算机D:\Python312\文件夹中了,在Thonny的Shell窗口中,看到了服务器程序返回来的图片文件大小的数字了。
- 第三轮ESP32Cam摄像头拍摄图片发送给Flask
在这个测试中,我们把发送的图片改为摄像头拍摄到了图片,经过运行程序测试,可以看到摄像头拍摄到的图片,发送到了计算机中的D:\Python312\的文件夹中了。
避坑笔迹:之前一直测试的程序也是这个程序,但是就是一直不成功,一直找不到失败的原因,不知道传送的过程中究竟是哪个环节出现了问题,这个问题一直困扰了我三天时间,经过反反复复的测试,就是不成功。
后来我就采用“蚂蚁啃大象”的办法,从最简单的测试开始,尽可能地砍掉了所有的环节,保留最简单的连接通道(第一轮测试:本地客户端程序发送数据到线上的测试网站,保留最简单、最短传输路径的测试,因为网上的测试网站,基本可以忽略存在问题的可能,绝大的概率是正确的)。等第一轮测试通过后,就慢慢增加测试的传输路径长度,一点一点的向着最终的目标慢慢前进,经过几轮的测试,最终完成了ESP32Cam拍摄照片,利用TCP连接,发送到Flask服务器中的程序。
最后的测试成果,与网上的程序(之前一直不通过的)相比,我在摄像头初始化完成的后面,增加了一个0.2秒的延时,等待摄像头拍摄图片,然后在获取图片的数据,这样程序测试就通过了。
这个就是三天摸索的结果,不过最终还是找到了一个解决问题的办法:当程序出现问题的时候,如何化繁为简地进行测试,从最简单开始,一直到实现全部的预定功能。
如果在测试的时候,我们点击Thonny中的运行按钮,可以成功发送一张照片。第二次运行的时候,出现了错误信息,可以拔下ESP32Cam,重新插如电脑中,重新运行程序右可以了。说明这个程序还是有缺陷的,还需要改进。
第一轮测试,Python编写客户端程序,给在线HTTP服务网站发送信息import requests
import binascii, jsondef send_image():url = 'http://httpbin.org/post'd = {'jpg': 'tupian'}r = requests.post(url, data=d)print(r.text)send_image()/
第二轮测试 在电脑中创建两个Python程序,一个做服务器,一个做客户端,
在Python安装目录中,客服端读取333.jpg发送, 服务器端接收保存成555.jpgtest.py 服务器端:from flask import Flask, request
import binasciiapp = Flask(__name__)@app.route("/updata", methods=["POST","GET"])
def updata():print("保存图片1")a = request.form.get('jpg')with open('555.jpg','wb') as f:val = binascii.a2b_base64(a)f.write(val)return ('user:%d' %len(a))if __name__ == "__main__":app.run('0.0.0.0', 5000)test02.py 客户端import requests
import binascii, jsondef send_image():url = 'http://192.168.1.162:5000/updata'with open('333.jpg','rb') as f:img = f.read()img = binascii.b2a_base64(img)d = {'jpg': img}r = requests.post(url, data=d)print(r.text)send_image()/
第三轮测试 ESP32CAM读取内存中的一张照片,发送到Python创建的Flask服务器端from flask import Flask, request
import binasciiapp = Flask(__name__)@app.route("/updata", methods=["POST","GET"])
def updata():print("保存图片1")a = request.get_data() #直接接收二进制with open('555.jpg','wb') as f:f.write(a)return ('user:%d' %len(a))if __name__ == "__main__":app.run('0.0.0.0', 5000) ESP32Cam 设备作为客户端import time, networkdef connectWiFi():wlan = network.WLAN(network.STA_IF)if wlan.isconnected():wlan.disconnect()wlan.active(True)wlan.connect('ChinaNet-xxVP', '123456789')while not wlan.isconnected():passprint('network config: ', wlan.ifconfig())connectWiFi()import urequests as requestsdef send_image():url = 'http://192.168.1.162:5000/updata'with open('333.jpg', 'rb') as f:img = f.read()r = requests.post(url, data = img)print(r.text)r.closesend_image()第四轮测试 ESP32CAM拍下一张照片,发送到Python创建的Flask服务器端Python服务器端from flask import Flask, request
import binasciiapp = Flask(__name__)@app.route("/updata", methods=["POST","GET"])
def updata():print("保存图片1")a = request.get_data() #直接接收二进制with open('555.jpg','wb') as f:f.write(a)return ('user:%d' %len(a))if __name__ == "__main__":app.run('0.0.0.0', 5000) ESP32Cam客户端 import time, networkdef connectWiFi():wlan = network.WLAN(network.STA_IF)if wlan.isconnected():wlan.disconnect()wlan.active(True)wlan.connect('ChinaNet-xxVP', '123456789')while not wlan.isconnected():passprint('network config: ', wlan.ifconfig())connectWiFi()import camera
import time
import urequests as requestsdef send_image():url = 'http://192.168.1.162:5000/updata'while not camera.init(0):time.sleep(0.2)camera.deinit()time.sleep(0.2)time.sleep(0.2) #稍作延时,等待拍照img = camera.capture() # 获取照片camera.deinit()r = requests.post(url, data = img)print(r.text)r.closesend_image()//
/
保存到ESP32Cam中的 urequests.py 驱动库源代码import usocketclass Response:def __init__(self, f):self.raw = fself.encoding = "utf-8"self._cached = Nonedef close(self):if self.raw:self.raw.close()self.raw = Noneself._cached = None@propertydef content(self):if self._cached is None:self._cached = self.raw.read()self.raw.close()self.raw = Nonereturn self._cached@propertydef text(self):return str(self.content, self.encoding)def json(self):import ujsonreturn ujson.loads(self.content)def request(method, url, data=None, json=None, headers={}, stream=None,params=None):try:proto, dummy, host, path = url.split("/", 3)except ValueError:proto, dummy, host = url.split("/", 2)path = ""if proto == "http:":port = 80elif proto == "https:":import usslport = 443else:raise ValueError("Unsupported protocol: " + proto)if ":" in host:host, port = host.split(":", 1)port = int(port)if params:path = path + "?"for k in params:path = path + '&'+k+'='+params[k]ai = usocket.getaddrinfo(host, port)addr = ai[0][4]s = usocket.socket()s.connect(addr)if proto == "https:":s = ussl.wrap_socket(s)s.write(b"%s /%s HTTP/1.0\r\n" % (method, path))if not "Host" in headers:s.write(b"Host: %s\r\n" % host)# Iterate over keys to avoid tuple allocfor k in headers:s.write(k)s.write(b": ")s.write(headers[k])s.write(b"\r\n")if json is not None:assert data is Noneimport ujsondata = ujson.dumps(json)if data:s.write(b"Content-Length: %d\r\n" % len(data))s.write(b"\r\n")if data:s.write(data)l = s.readline()protover, status, msg = l.split(None, 2)status = int(status)#print(protover, status, msg)while True:l = s.readline()if not l or l == b"\r\n":break#print(l)if l.startswith(b"Transfer-Encoding:"):if b"chunked" in l:raise ValueError("Unsupported " + l)elif l.startswith(b"Location:") and not 200 <= status <= 299:raise NotImplementedError("Redirects not yet supported")resp = Response(s)resp.status_code = statusresp.reason = msg.rstrip()return respdef head(url, **kw):return request("HEAD", url, **kw)def get(url, **kw):return request("GET", url, **kw)def post(url, **kw):return request("POST", url, **kw)def put(url, **kw):return request("PUT", url, **kw)def patch(url, **kw):return request("PATCH", url, **kw)def delete(url, **kw):return request("DELETE", url, **kw)
相关文章:

ESP32CAM人工智能教学15
ESP32CAM人工智能教学15 Flask服务器TCP连接 小智利用Flask在计算机中创建一个虚拟的网页服务器服务器,让ESP32Cam通过WiFi连接,把摄像头拍摄到的图片发送到电脑中,并在电脑中保存成图片文件。 Flask是用Python编写的网页服务程序WebServer。…...
Pandas 33个冷知识 0721
Pandas 33个冷知识 从Excel读取数据: 使用 pd.read_excel(file.xlsx) 来读取Excel文件。 写入Excel: 使用 df.to_excel(file.xlsx, indexFalse) 将DataFrame写入Excel文件。 创建日期索引: 使用 df.set_index(pd.to_datetime(df[date])) 创建日期索引。 向后填充缺失值: 使用…...

C++ map和set的使用
目录 0.前言 1.关联式容器 2.键值对 3.树形结构的关联式容器 3.1树形结构的特点 3.2树形结构在关联式容器中的应用 4.set 4.1概念与性质 4.2使用 5.multiset 5.1概念与性质 5.2使用 6.map 6.1概念与性质 6.2使用 7.multimap 7.1概念与性质 7.2使用 8.小结 &a…...
yarn的安装和配置以及更新总结,npm的对照使用差异
1. Yarn简介 Yarn 是一个由 Facebook 开发的现代 JavaScript 包管理器,旨在提供更快、更安全、更可靠的包管理体验。 1.1 什么是Yarn Yarn 是一个快速、可靠和安全的 JavaScript 包管理器,它通过并行化操作和智能缓存机制,显著提升了依赖安…...

【Git命令】git rebase之合并提交记录
使用场景 在本地提交了两个commit,但是发现根本没有没必要分为两次,需要想办法把两次提交合并成一个提交;这个时候可以使用如下命令启动交互式变基会话: git rebase -i HEAD~N这里 N 是你想要重新调整的最近的提交数。 如下在本地…...

为什么品牌需要做 IP 形象?
品牌做IP形象的原因有多方面,这些原因共同构成了IP形象在品牌建设中的重要性和价值,主要原因有以下几个方面: 增强品牌识别度与记忆点: IP形象作为品牌的视觉符号,具有独特性和辨识性,能够在消费者心中留…...

Kubernetes 1.24 版弃用 Dockershim 后如何迁移到 containerd 和 CRI-O
在本系列的上一篇文章中,我们讨论了什么是 CRI 和 OCI,Docker、containerd、CRI-O 之间的区别以及它们的架构等。最近,我们得知 Docker 即将从 kubernetes 中弃用!(查看 kubernetes 官方的这篇文章)那么让我…...
70. 爬楼梯【 力扣(LeetCode) 】
一、题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 二、测试用例 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶…...

R语言优雅的把数据基线表(表一)导出到word
基线表(Baseline Table)是医学研究中常用的一种数据表格,用于在研究开始时呈现参与者的初始特征和状态。这些特征通常包括人口统计学数据、健康状况和疾病史、临床指标、实验室检测、生活方式、社会经济等。 本人在既往文章《scitb包1.6版本发…...

XMl基本操作
引言 使⽤Mybatis的注解⽅式,主要是来完成⼀些简单的增删改查功能. 如果需要实现复杂的SQL功能,建议使⽤XML来配置映射语句,也就是将SQL语句写在XML配置⽂件中. 之前,我们学习了,用注解的方式来实现MyBatis 接下来我们…...

Linux——Shell脚本和Nginx反向代理服务器
1. Linux中的shell脚本【了解】 1.1 什么是shell Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁 Shell 既是一种命令语言,有是一种程序设计语言 Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问…...

pyspark使用 graphframes创建和查询图的方法
1、安装graphframes的步骤 1.1 查看 spark 和 scala版本 在终端输入: spark-shell --version 查看spark 和scala版本 1.2 在maven库中下载对应版本的graphframes https://mvnrepository.com/artifact/graphframes/graphframes 我这里需要的是spark 2.4 scala 2.…...

【web】-flask-简单的计算题(不简单)
打开页面是这样的 初步思路,打开F12,查看头,都发现了这个表达式的base64加密字符串。编写脚本提交答案,发现不对; 无奈点开source发现源代码,是flask,初始化表达式,获取提交的表达式࿰…...
Apache Sqoop
Apache Sqoop是一个开源工具,用于在Apache Hadoop和关系型数据库(如MySQL、Oracle、PostgreSQL等)之间进行数据的批量传输。其主要功能包括: 1. 数据导入:从关系型数据库(如MySQL、Oracle等)中将…...
【Python】TensorFlow介绍与实战
TensorFlow介绍与使用 1. 前言 在人工智能领域的快速发展中,深度学习框架的选择至关重要。TensorFlow 以其灵活性和强大的社区支持,成为了许多研究者和开发者的首选。本文将进一步扩展对 TensorFlow 的介绍,包括其优势、应用场景以及在最新…...

第100+16步 ChatGPT学习:R实现Xgboost分类
基于R 4.2.2版本演示 一、写在前面 有不少大佬问做机器学习分类能不能用R语言,不想学Python咯。 答曰:可!用GPT或者Kimi转一下就得了呗。 加上最近也没啥内容写了,就帮各位搬运一下吧。 二、R代码实现Xgboost分类 (…...

【操作系统】定时器(Timer)的实现
这里写目录标题 定时器一、定时器是什么二、标准库中的定时器三、实现定时器 定时器 一、定时器是什么 定时器也是软件开发中的⼀个重要组件.类似于⼀个"闹钟".达到⼀个设定的时间之后,就执行某个指定 好的代码. 定时器是⼀种实际开发中⾮常常用的组件. ⽐如⽹络通…...

鸿蒙Navigation路由能力汇总
基本使用步骤: 1、新增配置文件router_map: 2、在moudle.json5中添加刚才新增的router_map配置: 3、使用方法: 属性汇总: https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-compone…...

1:1公有云能力整体输出,腾讯云“七剑”下云端
【全球云观察 | 科技热点关注】 曾几何时,云计算技术的兴起,为千行万业的数字化创新带来了诸多新机遇,同时也催生了新产业新业态新模式,激发出高质量发展的科技新动能。很显然,如今的云创新已成为高质量发…...

【iOS】APP仿写——网易云音乐
网易云音乐 启动页发现定时器控制轮播图UIButtonConfiguration 发现换头像 我的总结 启动页 这里我的启动页是使用Xcode自带的启动功能,将图片放置在LaunchScreen中即可。这里也可以通过定时器控制,来实现启动的效果 效果图: 这里放一篇大…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...