构建计算机视觉 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。

  1. 创建一个免费帐户 这里 , 点击 “免费试用” .
  2. 点击 数据库 > , 并选择免费套餐。
  3. 通过选择所需的云服务提供商、集群层和集群名称来创建 Starter Cluster。
  4. 创建用户,选择使用本地环境并单击 添加我当前的 IP 地址 > 保持简单。
  5. 点击 数据库 > 在您刚刚创建的集群上单击 ** .**
  6. 点击 ** ** ,添加数据库名称和集合名称并创建。
  7. 返回您的集群,单击 ** ** ,会弹出一个窗口:
  8. 选择 ** ** 并选择您的驱动程序和版本——对我来说它的 Python 和版本 3.6 或更高版本。
  9. 创建一个空的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 .请记住,在每条路线上,我们的应用程序都会执行与路线相关的代码。

  1. @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 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/10962/54150208

posted @ 2022-09-02 08:55  哈哈哈来了啊啊啊  阅读(153)  评论(0编辑  收藏  举报