构建计算机视觉 WebApp — Flask、OpenCV 和 MongoDB
构建计算机视觉 WebApp — Flask、OpenCV 和 MongoDB
作为一名数据科学家,具备一些软件工程技能已成为就业市场中一项非常重要的技能。如果您可以构建模型,我建议您提高简单的应用程序开发和模型部署技能。
https://www.oreilly.com/library/view/python-advanced-guide
该项目
我最近收到了一个使用 Flask 创建对象检测应用程序的带回家的任务, 开放式CV 以及 1 周内的任何 NoSQL 数据库平台。我最后一次使用 Flask 是在 2 年前,当时我还是一名数据科学家,所以这是一个很好的更新项目。
该应用程序允许用户上传图像或视频,对上传的文件执行对象检测并将结果输出到 MongoDB 或者 AWS DynamoDB。
要查看完整的工作代码,请访问我的 ** GitHub 仓库** ** .**
*这里先睹为快
烧瓶
Flask 是一个允许使用 Python 无缝开发 Web 应用程序的框架。
与其他框架不同,Flask 非常 Pythonic。所以它没有很大的学习曲线,而且非常明确,增加了可读性。
要使用 Flask,我建议你过去 HTTPs 请求方法 这很容易理解。它们为您的应用程序(使用烧瓶)提供了一种与您创建的网页进行通信的方式。他们指定是否将数据发布到您的网站,从您的网站获取数据等等。
开放式CV
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。 OpenCV 旨在为计算机视觉应用程序提供通用基础架构。
通过我们将通过的代码,我们将看到 OpenCV 的实现,并带有注释以帮助理解。如果您已经熟悉深度学习和计算机视觉,您将能够更快地理解代码。
MongoDB
MongoDB 是一个面向文档的 NoSQL 数据库,用于大容量数据存储。 MongoDB 不像在传统关系数据库中那样使用表和行,而是使用类似 JSON 的文档。
常见的关系数据库具有具有固定模式(指定数据类型)的表,并使用 SQL(结构化查询语言)来管理数据。
使用 NoSQL,您可以将非结构化或半结构化数据存储在一起,而不是连接规范化数据的表;通常在键值对或 JSON 文档中。 NoSQL 在易用性、可扩展性、弹性和高效可用性方面表现出色。
连接到 MongoDB Atlas :
这允许我们在云中使用 MongoDB。
- 创建一个免费帐户 这里 , 点击 “免费试用” .
- 点击 数据库 > ,
并选择免费套餐。 - 通过选择所需的云服务提供商、集群层和集群名称来创建 Starter Cluster。
- 创建用户,选择使用本地环境并单击 添加我当前的 IP 地址 > 保持简单。
- 点击 数据库 > 在您刚刚创建的集群上单击 **
.** - 点击 **
** ,添加数据库名称和集合名称并创建。 - 返回您的集群,单击 **
** ,会弹出一个窗口: - 选择 **
** 并选择您的驱动程序和版本——对我来说它的 Python 和版本 3.6 或更高版本。 - 创建一个空的python文件并命名
数据库.py
粘贴此代码,然后替换<username>
,<password>
,<your_db_name>
和<your_collection_name>
使用您创建的值/名称。
看看我们如何使用它 数据库.py
文件,转到标题下的文章末尾> utils.py 中的辅助函数
项目结构
├── app.py
├── utils.py
├── db.py
└── 设置/
│ ├── requirements.txt
│ ├── setup.sh
└── 静态文件/
│ ├── 图片
│ ├── 影片
│ ├── 输出
│ ├── 上传
└── 模板文件/
│ ├── index.html
│ ├── show_image.html
│ ├── show_video.htl
│ ├── 成功.html
└── README.md
上面我们已经提到了HTTPS请求方法,现在让我们简单介绍一下html网站模板。
模板
烧瓶用途 神社2 ,这让我们可以使用 Python 来生成 html
网页(即模板)。
模板包含变量,这些变量是模板时传入的替换值 渲染 __ 通过我们在下面创建的函数
@app.routes()
(我们在下一节中进一步解释路线) .
以下是如何创建模板的指南 → 点击这里 .
我们为我们的应用程序创建的模板是:
索引.html:
我们将用于用户上传的登陆/主页。show_image.html:
我们将用来显示用户上传的图片的页面。show_video.html:
我们将用于显示用户上传的视频和成功.html:
与索引页面相同,但当用户成功上传文件时,它将加载“成功”消息。
要查看模板的完整代码,请访问我的 GitHub 仓库 在下面 模板文件/
目录 → 这里 .在本教程中,我将只强调 html 页面的重要部分。要以交互方式了解有关 html 的更多信息,我建议使用 W3学校 .
应用程序代码
让我们从实际的 Flask 应用程序创建开始,之后我们将介绍对象检测代码。我们首先创建一个空的python文件并命名 应用程序.py
,导入 flask 及其库,然后创建一个 App 对象。
从烧瓶导入烧瓶,渲染模板,请求,会话 app = Flask(__name__)
app = Flask(__name__)
创建一个 Flask 应用程序对象 在我们正在创建的当前 Python 文件中。这 应用程序
变量是一个 实例 我们在文件顶部导入了一个名为 Flask 的 Python 类。 应用程序
现在拥有 Flask 的所有函数、方法和属性。
我们还指定环境变量以显示我们的上传和输出数据应存储的路径。
UPLOAD_FOLDER = os.path.join('staticFiles', 'uploads')
OUTPUT_FOLDER = os.path.join('staticFiles', 'output')
然后我们创建路线。
路线
路由将网站 URL 附加或映射到 Python 代码或函数,这些代码或函数决定在该特定路由 (URL) 上会发生什么。我们将创建这些功能。
对于每一个 @app.route('')
我们将创建,我们将加载特定路由将使用的 html 模板/页面。我们指定的任何路由名称都附加到我们网站 URL 的末尾。
我们将创建的示例路线最终将作为 https://ourwebapp.com/
, https://ourwebapp.com/show_image
或者 https://ourwebapp.com/detect-obect
.请记住,在每条路线上,我们的应用程序都会执行与路线相关的代码。
@app.route('/')
是我们将创建的第一条路线,它将把我们带到我们的主页。
我们可以看到这个主页路由只是一个空的 '/'
因为它的 URL 只是停留在着陆页上。
这里附加到这条路线的功能是 定义主():
,它被命名为main,因为它是我们网站的主页,它真的可以命名任何你喜欢的名字。我们告诉函数返回 渲染模板(“index.html”)
这将加载 索引.html
模板/页面并使其显示在我们的网站上。
**索引.html**
模板
这是所有网站中主页的页面。在我们的网站上,我们将使用它从用户那里获取输入文件,因此我们需要使用 html 表单。
动作=”/”
它调用了我们刚刚创建的@app.route('/')。方法="发布"
我们指定 POST 请求方法,因为用户会将数据发布到我们的网站上。name = "文件上传"
指定上传文件的名称。这将在我们创建 Flask 应用程序时派上用场,因为我们将使用上传的文件来执行对象检测。动作="/show_image"
调用@app.route('/show_image')
我们稍后会创建。它将用户带到show_image.html
.当用户单击“显示图像”提交按钮时会发生这种情况。
当。。。的时候 索引.html
渲染后,这将是我们的结果(使它看起来漂亮的代码在我的 GitHub 存储库中):
Our index.html page
2. 然后我们创建 @app.route('/', methods=[“POST”])
允许用户上传文件的路由。
我们看到的一样 '/'
我们在主页路由中看到的意思是我们留在主页但这次我们指定 方法="发布"
因为我们将创建用户所在的部分 邮政 将他们的文件下载到我们的网站。
_img = request.files['文件上传']
允许我们获取用户上传的图片或视频,请求文件
是一个包含所有上传文件的字典对象。回想一下,在我们的 index.html 模板中,我们将用户上传的文件命名为name = "文件上传"
因此,我们在这里称其为相同的名称。- 我们从
请求文件
上面的对象,然后将其传递给一个简短的帮助函数,该函数决定我们的应用程序中是否允许该文件类型。 - 然后我们将图像保存到我们之前指定的上传文件夹路径中,然后
会话['uploaded_img_file_path'] = …
一个 会议 (从上面的烧瓶中导入)用于在用户与 Web 应用程序交互时跨不同请求存储与用户相关的信息。在其中我们存储上传文件的路径。稍后我们将再次使用它。- 就像其他路线一样,我们返回
渲染模板()
——这次是成功.html
显示文件是否上传成功的页面。
**成功.html**
模板:
它与 索引.html
template ,除了这次我们添加这个 html 行:
<p style="color:green;">文件上传成功</p>
这是渲染成功模板的部分:
3. 然后我们创建 @app.route('/show_image')
路线。
session.get('uploaded_img_file_path', 无)
允许我们获取/获取我们从上传文件
我们在上面创建的路线。根据文件类型,无论是图像还是视频,我们返回渲染模板()
为了show_image.html
或者show_video.html
.用户图像
是我们创建的一个变量,允许我们将图像插入到渲染的网页中。
**show_image/video.html**
模板
<video src=”{{ user_image }}” controls=”controls” ></video>:
使用<video> </video>
我们周围的html标签{{用户图像}}
变量让 html 知道期待来自我们上传文件路径的视频。如果它是一个图像,我们把<img> </img>
标签。
在 Jinja 双卷曲 {{ }}
大括号允许我们评估 Python 表达式、变量或函数调用并将结果打印到模板中
- 这
动作="/detect_object"
调用@app.route('/detect_object')
这将是我们将创建的最终路线。
上传视频并渲染后 show_video.html
或者 show_image.html
模板,这是我们得到的结果:
4. 最后我们创建 @app.route('/detect_object')
路线。这条路线运行对象检测并将结果呈现给我们的 show_image/video.html
模板。
我们再次得到 上传图片路径
从会话中,然后我们运行我们的对象检测功能 def detect_and_draw_box()
: 我们很快就会过去。
从中,我们得到 输出图像路径
保存图像结果的位置和 文件类型
这让我们的路由函数知道文件输出是“图像”还是“视频”,以便可以渲染相应的模板。
我们将从之前的上传中获得此输出。迷人的!!
现在让我们编码吧!
物体检测代码
我们创建一个名为 实用程序.py
.这是代码的核心,我们编写的实际对象检测和辅助函数将在其中。
导入我们需要的所有库:
进口我们
导入简历2
将 cvlib 导入为 cv
从 cvlib.object_detection 导入 draw_bbox
图像检测功能:
它需要 img_filepath
从保存的 应用程序.py
路线。我们使用“yolov3”模型并设置 信心
值,通常为 0.5(使用 50%)。
置信度是模型对检测到的对象分配正确标签的“信心”程度。编码器设置其阈值或截止点,以决定何时应为预测对象提供正标签。
img = cv2.imread(img_filepath)
:OpenCv 将图像读入一个 numpy 数组以供我们的模型理解。bbox,标签,conf = cv.detect_common_objects(img,信心,模型)
:检测通用对象
使用预训练来检测 80 个常见对象。- 它返回图像中检测到的对象的边界框坐标(检测到的对象周围的框)、相应的标签和置信度分数。
output_image = draw_bbox(img, bbox, 标签, conf)
:然后我们将框和标签绘制到图像上以获得输出图像。output_image_path = os.path.join(OUTPUT_FOLDER, 'output_image.jpg')
:我们指定图像输出名称和应保存的路径。cv2.imwrite(输出图像路径,输出图像)
用于将图像保存到任何存储设备或路径。
其余代码使用我们创建的辅助函数将模型输出保存为本地 JSON(我们将其称为“响应”),并以这种格式将其推送到 MongoDB:
视频检测 功能:
cap = cv2.VideoCapture(video_filepath):
创建一个视频捕获对象,这将允许我们读取上传或流式传输的视频。
fourcc = cv2.VideoWriter_fourcc(*'MJPG'):
以 MJPG 格式保存输出视频。
四CC (“四字符代码”)是一个由四个组成的序列 字节 (通常 ASCII ) 用于唯一标识 数据格式 .
而 cap.isOpened()
: 拍完视频后,可以用这个方法来检查你的视频是否打开成功。否则,您将收到一条错误消息。
ret, frame = cap.read():
用于通过创建循环并一次读取一帧来捕获视频的每一帧。它返回一个元组 bool 和 frame,如果 ret 是 真的
然后有一个视频帧要读取。
如果 ret
返回 错误的
然后 print(“无法接收帧(流结束?)。正在退出……”)
并打破循环。
然后我们翻转图像,因为它可能会颠倒过来。
类似于 图片
检测代码,我们使用 检测通用对象
模型和 draw_bbox
函数显示每个检测到的对象的边界框和预测标签。
out = cv2.VideoWriter(out_path,fourcc, fps=10, (width, height)):
声明如何保存视频。指定输出文件夹,以指定的fourcc格式保存,将帧率(每秒帧数)设置为10.0,我们设置所需的大小。
out.write(输出帧):
将帧写入输出文件。
我们可以使用 显示()
在窗口中显示框架的方法。我们保存图像检测函数中指定的响应 JSON。
这 等待键()
指定在视频之间暂停多长时间并监视用户输入的键盘。当用户按下 q
键(当窗口在屏幕上打开时)我们退出循环并结束流式传输。
我们使用我们的辅助函数 添加数据()
将数据推送到 MongoDB Atlas 。 帽释放()
一旦视频流被完全处理或用户过早退出循环,就会释放视频捕获,在 out.release()
我们释放视频写入对象和 cv2.destroyAllWindows()
关闭窗口。最后我们保存模型输出 回复
本地。
utils.py 中的辅助函数:
其余的可以在 GitHub 仓库 *
import db # 导入我们之前创建的 MongoDB db.py 文件
谢谢阅读!!
参考书目:
https://pythonbasics.org/what-is-flask-python/
https://python-adv-web-apps.readthedocs.io/en/latest/flask.html
https://tedboy.github.io/flask/
https://www.python-engineer.com/posts/opencv-videos/
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明