flask数字图像处理系统开发全流程记录(基于OpenCV)

2023-05-16

目录

  • 一、环境安装
    • 1.1 安装虚拟环境
    • 1.2 安装Flask
  • 二、搭建flask项目框架
    • 2.1 创建一个简单项目
    • 2.2 渲染html页面
    • 2.3 使用Bootstrap美化页面
    • 2.4 前后端逻辑交互
      • 2.4.1 前端实现
      • 2.4.2 后端实现
    • 三、部署
      • 3.1 Waitress工业级部署
      • 3.2 项目打包

一、环境安装

1.1 安装虚拟环境

虚拟环境是Python解释器的一个副本环境,在这个环境中可以安装其它第三方Python包,在虚拟环境中安装的Python包不会影响全局环境中的包。通过虚拟环境可以有效的做到python环境隔离,适合需要不同依赖库的python项目开发。

为了能够正常的使用虚拟环境,我们首先安装虚拟环境工具virtualenv,输入下面的命令即可完成安装:

sudo apt-get install python3-virtualenv

接下来我们可以专门建立一个文件夹phdl用于创建虚拟环境,创建虚拟环境命令如下:

virtualenv envi

创建成功结果如下所示:
请添加图片描述接下来我们需要进入到我们的虚拟环境,可以使用下面的命令:

source envi/bin/activate

此时在命令行前面会出现当前虚拟环境名称,如下图所示:
请添加图片描述表明我们已经进入到名为envi的python虚拟环境中。我们可以使用命令pip list来查看当前虚拟环境中的python库,如下所示:
请添加图片描述可以看到当前虚拟环境中很简单,只有pip、pkg-resources、setuptools和wheel几个工具库。目前这个虚拟环境是一个相当“干净”的库环境。

1.2 安装Flask

Flask是一个轻量级
进入刚才创建的虚拟环境envi,然后安装flask:

pip install flask -i https://mirror.baidu.com/pypi/simple

安装完后验证下flask是否能够正常使用,先输入python进入python环境,然后输入:

import flask查看是否报错,如果没有报错命令,说明flask成功安装并可以使用了。

二、搭建flask项目框架

2.1 创建一个简单项目

相比于另一个Python Web框架Django,Flask更“Python”化一些,因为我们可以在一个.py脚本文件中写完运行整个项目的所有代码。

我们在phdl项目下新建一个app.py文件,然后在该文件中填入主运行函数如下:

from flask import Flask
 
app = Flask(__name__)
 
@app.route('/', methods=['GET'])
def index():
    return "<h1>我的第一个网站</h1>"
    
 
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, threaded=True,debug=True)

上面的代码开发了一个最简单的网站。我们可以先不分析具体的代码,直接执行来看一下效果。我们在终端中输入命令来启动这个项目(注意要在虚拟环境中启动):

python app.py

正常情况下输出如下所示:
请添加图片描述如果没有准确输出上面的内容,那么就要检查代码,其中注意__name__和__main__两个地方,这里前后都是两个下划线。

正常启动后我们就可以在浏览器中访问我们的这个网站,网址就在上述输出的最后一行http://127.0.0.1:5000/。效果如下图所示:
请添加图片描述

2.2 渲染html页面

在项目根目录下创建一个名为templates的文件夹,在该文件夹下创建一个home.html文件,该文件内容如下:

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>欢迎</title>
</head>

<body>
    <h1>我的第一个网站</h1>
</body>

然后重新编辑app.py文件:

from flask import Flask,request,render_template
 
app = Flask(__name__)
 
@app.route('/', methods=['GET'])
def home():
    if request.method == 'GET':
        return render_template('/home.html')

 
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, threaded=True,debug=True)

保存后重新运行,效果跟前面一样。到这里我们可以实现html页面的准确渲染。

2.3 使用Bootstrap美化页面

首先在当前项目根目录下新建static文件夹,该文件夹将作为我们的静态资源文件夹使用,专门用于存放css、js、fonts等网页需要的静态资源。接下来我们找一个免费的Bootstrap模板来作为我们的起始页面。

这里给出一个免费的Bootstrap模板下载网址:https://startbootstrap.com/template/scrolling-nav
下载后将其解压,然后将assets、css、js文件夹拷贝到static文件下下面,然后将index.html中的所有代码拷贝到我们自己的home.html文件中,然后修改home.html中相关静态资源的导入,修改方法很简单,只需要在类似css/styles.css这种引用的地方统一添加一个static目录前缀,如下所示:

/static/css/styles.css

然后我们重新启动系统,重新刷新页面后效果如下:
请添加图片描述
最后我们对这个页面做一些修改,最后样式如下所示:
请添加图片描述
其中关于样式.py-5我们在styles.css文件中对其做了一些修改,使得底部footer能够固定在底部:

.py-5 {
  /* padding-top: 1rem !important;
  padding-bottom: 1rem !important; */
  position:absolute;
  color:#fff;
  bottom:0;
  width:100%;
  height:100px;
  line-height:100px;
  text-align:center;
  background-color: #000;
}

最后还有一个问题需要解决。由于Bootstrap 的所有 JavaScript 插件都依赖 jQuery,而我们下载的这个模板中并没有提供jQuery,因此我们要下载jQuery并且放到js文件夹中并引用进来。

下载地址:https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js。将这个地址打开,然后右键页面另存为jquery.min.js,将这个jquery.min.js放在static/js目录下。最后在home.html中引用这个js:

2.4 前后端逻辑交互

本文实现的前后端交互逻辑比较简单:从页面能够上传一张图像并显示,然后单击“开始处理”按钮将图像通过put接口传给后端,后端采用opencv算法对图像进行灰度化处理,处理结果图像以base64形式返回给前端并展示。

通过这样一个流程我们就可以打通前后端之间的联系,虽然实现的图像处理功能比较简单,但是一旦走通这个流程,后面我们就可以封装更多更复杂的算法逻辑。

最终实现效果如下图所示:
请添加图片描述

2.4.1 前端实现

完整前端代码如下(home.html):

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
  <meta name="description" content="" />
  <meta name="author" content="" />
  <title>数字图像处理系统</title>
  <link rel="icon" type="image/x-icon" href="/static/assets/favicon.ico" />
  <!-- Core theme CSS (includes Bootstrap)-->
  <link href="/static/css/styles.css" rel="stylesheet" />
  <!-- Bootstrap core JS-->
  <script src="/static/js/jquery.min.js"></script>
  <script src="/static/js/bootstrap.min.js"></script>
</head>

<body id="page-top">
  <!-- Navigation-->
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" id="mainNav">
    <div class="container px-4">
      <a class="navbar-brand" href="#page-top">控制台主页</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive"
        aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"><span
          class="navbar-toggler-icon"></span></button>
      <div class="collapse navbar-collapse" id="navbarResponsive">
        <ul class="navbar-nav ms-auto">
          <li class="nav-item"><a class="nav-link" href="#">创建项目</a></li>
        </ul>
      </div>
    </div>
  </nav>
  <!-- Header-->
  <header class="bg-primary bg-gradient text-white">
    <div class="container px-4 text-center">
      <h1 class="fw-bolder">数字图像处理系统</h1>
      <p class="lead">Welcome to Digital Image Processing System</p>
      <a class="btn btn-lg btn-light" data-toggle="modal" data-target="#myModal">测试</a>
    </div>
  </header>

  <!-- 模态框(Modal) -->
  <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h4 class="modal-title" id="myModalLabel">
            图像处理
          </h4>
        </div>
        <div class="modal-body">
          <div class="container-fluid">
            <div class="row">
              <div class="col-md-6 col-lg-6 col-xs-6">
                <img id="photoIn" src="/static/img/sample.png" class="img-responsive" style="max-width:200px">
                <input type="file" id="photo" name="photo" />
              </div>

              <div class="col-md-6 col-lg-6 col-xs-6">
                <img id="photoOut" class="img-responsive" style="max-width:200px">
              </div>
            </div>
          </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">关闭
          </button>
          <button type="button" id="btn_process" class="btn btn-primary" onclick="ProcessImg(this);">
            开始处理
          </button>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal -->
  </div>
  <script>
    $(function () {
      $('#photo').on('change', function () {
        var r = new FileReader();
        f = document.getElementById('photo').files[0];
        r.readAsDataURL(f);
        r.onload = function (e) {
          document.getElementById('photoIn').src = this.result;
        };
      });
    });
  </script>

  <script>
    //模型预测
    function ProcessImg(obj) {
      //提取图像数据
      var str_img_data = document.getElementById('photoIn').src;
      var dst_img_data = document.getElementById('photoOut').src;
      var file = document.getElementById('photo').files[0];

      if (file == "") {
        alert("请先选择要测试的图片!");
        return;
      }

      //封装请求
      var http_request;
      if (window.XMLHttpRequest) {
        http_request = new XMLHttpRequest();
      }
      else {
        http_request = new ActiveXObject("Microsoft.XMLHTTP");
      }

      var idx_postfix = str_img_data.indexOf("base64,");
      if (idx_postfix > 0) {
        str_img_data = str_img_data.substring(idx_postfix + 7, str_img_data.length);
      }

      //发送数据
      var data = { "image_data": str_img_data, };
      http_request.open("POST", "/compute", false);
      http_request.setRequestHeader("Content-type", "application/json");
      http_request.send(JSON.stringify(data));

      //解析返回数据并显示
      var obj_json = eval('(' + http_request.responseText + ')');
      var str_img = obj_json["img64"];

      var str_b64_type = "data:image/png;base64,";
      document.getElementById('photoOut').src = str_b64_type + str_img;
    }
  </script>

  <!-- Footer-->
  <footer class="py-5 bg-dark">
    <div class="container px-4">
      <p class="m-0 text-center text-white">Copyright &copy; 数字图像处理系统 2022</p>
    </div>
  </footer>

</body>
</html>

2.4.2 后端实现

为了能够方便的使用数字图像处理算法,我们首先安装opencv-python:

pip install opencv-python -i https://mirror.baidu.com/pypi/simple

完整的后端处理代码如下app.py:

from flask import Flask, request, render_template
import numpy as np
import cv2
import base64

app = Flask(__name__)


@app.route('/', methods=['GET'])
def home():
    if request.method == 'GET':
        return render_template('/home.html')


@app.route('/compute', methods=['POST',])
def compute():
    data = request.get_json()
    if request.method == 'POST':
        # 接收数据
        img_data = data['image_data']
        img_data = base64.b64decode(img_data)
        img_array = np.frombuffer(img_data, np.uint8)
        img = cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)
        # 图像变换
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 返回数据
        _, buffer_img = cv2.imencode('.png', gray)
        img64 = base64.b64encode(buffer_img)
        img64 = str(img64, encoding='utf-8')
        ret = {}
        ret["img64"] = img64
        return ret


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, threaded=True, debug=True)

到这里,我们的基本开发功能就全部结束了(虽然只搭了一个框架,但是路都打通了,后面只需要在这个基础上进行二次开发和完善即可)。

三、部署

3.1 Waitress工业级部署

前面开发过程中我们使用的是flask现成的开发服务器来启动项目的,这个开发服务器启动快、支持代码热更新,非常适合在开发过程中调试和测试页面效果。但是对于实际工业部署来说,这个开发服务器性能就不够用了,它的并发和稳定性都存在问题。因此,我们需要一个更强大的工业级服务器框架用来部署flask应用。

参照flask官网部署教程,我们使用Waitress来部署我们开发的应用。

Waitress是一个纯粹的Python WSGI服务器,它具有两大优势:

  • 易配置、易安装
  • 支持Windows

其中尤其需要注意Waitress支持windows系统来部署,这对于一些windows云服务器平台来说具有非常大的吸引力。

首先来安装Waitress。由于Waitress本质上就是一个python库,因此它的安装也只需要在虚拟环境中通过pip来安装:

pip install waitress

安装完以后我们可以在虚拟环境中使用pip list看一下当前的所有依赖库:
请添加图片描述
可以看到,目前我们的虚拟环境中的库还是比较简洁的,如果要部署到其它机器上,那么也需要提前安装好这些库(或者也可以使用docker将整个环境打包部署)。

接下来我们需要利用waitress来启动flask项目。

首先我们在项目根目录下新建一个python脚本文件run.py,内容如下:

from waitress import serve
import app
serve(app.app, host='0.0.0.0', port=5001)

然后使用下面的命令来启动项目:

python run.py

这样就完成了工业级部署了。可以说整个部署工作非常简单。

3.2 项目打包

前面的方法我们基本是用源码来进行部署,这种方式对于给甲方进行私有化部署来说就显得非常不合适了,毕竟给出了项目的完整源码,别人可以轻而易举将你辛辛苦苦开发的项目整个拷贝走。还有一个问题就是,这种部署方式需要甲方提前在他们的机器上安装好所有的依赖库环境,而且启动的时候需要输出命令行python run.py来启动。我们希望最终交给用户的部署方案是更安全、更简单的。

本小节我们使用pyinstaller来完成这样的打包部署任务。

首先安装pyinstaller:

pip install pyinstaller

在项目根目录下创建一个deploy.py文件,内容如下:

from PyInstaller.__main__ import run
import platform

if __name__ == '__main__':
    if platform.system() == "Windows":
        opts = ['run.py',  # 主程序文件
                '-n ImageProcessSys',  # 可执行文件名称
                '-F',  # 打包单文件
                # '-w', #是否以控制台黑窗口运行
                r'--icon=.\Creeper.ico',  # 可执行程序图标
                '-y',
                '--clean',
                '--workpath=build',
                '--add-data=templates;templates',  # 打包包含的html页面
                '--add-data=static;static',  # 打包包含的静态资源
                '--distpath=build',
                '--specpath=./'
                ]
        run(opts)
    elif platform.system() == "Linux":
        opts = ['run.py',  # 主程序文件
                '-nImageProcessSys', # 可执行文件名称
                '-F',  # 打包单文件
                r'--icon=./Creeper.ico',
                '--clean',
                '--add-data=templates:templates',  # 打包包含的html页面
                '--add-data=static:static',  # 打包包含的静态资源
                ]
        run(opts)
    else:
        print(platform.system())

运行这个deploy.py文件,在当前项目根目录下会生成dist和bulid文件夹,其中的dist文件夹中生成的程序就是我们最终打包部署后的程序,只需要使用命令./ImageProcessSys就能启动项目了。如果是在windows下,那么会生成ImageProcessSys.exe,双击这个exe就可以直接运行。

如果要给客户部署,那么直接把这个ImageProcessSys文件交给用户就行,用户不需要安装其它的依赖库了(只需要安装好python即可)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

flask数字图像处理系统开发全流程记录(基于OpenCV) 的相关文章

  • 使用 openCV 和 python 检测物体

    我正在尝试使用 OpenCV 和 Python 检测下图中的白点 我尝试使用函数 cv2 HoughCircles 但没有成功 我需要使用不同的方法吗 这是我的代码 import cv2 cv import numpy as np impo
  • 查找彼此接近的对象边界

    我正在研究一个计算机视觉问题 其中问题的第一步是找到物体彼此靠近的位置 例如 在下图中 我感兴趣的是找到灰色标记的区域 Input Output 我目前的方法是首先反转图像 然后通过侵蚀进行形态梯度跟随 然后删除一些不感兴趣的轮廓 脚本如下
  • Flask Restful 解析器列表字典

    我有一个解析请求列表字典的示例 shopping cart id 23323 qty 10 id 34232 qty 9 id 34232 qty 9 我如何使用flask restful RequestParser解析它 使用这样的东西
  • OpenCV:视频结束后如何重新启动?

    我正在播放视频文件 但播放完毕后如何再次播放 Javier 如果您想一遍又一遍地重新启动视频 也称为循环播放 可以通过在帧数达到时使用 if 语句来实现cap get cv2 cv CV CAP PROP FRAME COUNT 然后重置帧
  • 带 % 的 Flask URL 参数未正确处理

    EDIT2 对于缺乏清晰度 我深表歉意 我将提供几个值 第一个是我使用前端应用程序调用的 URL 第二个是调用前的值urllib unquote 第三个是调用后的值urlib unquote 前端 console log http loca
  • 相机标定(OpenCV 2.3)-如何使用畸变参数?

    我有一组带有一些附加标记的刚体图像 我在这些标记之一中定义了一个原点坐标系 我想获得该坐标系与在相机原点定义的坐标系之间的旋转和平移 我尝试了一段时间 POSIT 以下this http goo gl cUYYt 但从未获得可接受的结果 直
  • Opencv matchTemplate 和 np.where():仅保留唯一值

    继带有马里奥硬币的 opencv 教程 https opencv python tutroals readthedocs io en latest py tutorials py imgproc py template matching p
  • Opencv未找到所有轮廓

    我试图找到该图像的轮廓 但是该方法查找轮廓只返回1轮廓 轮廓突出显示image 2 我正在努力寻找all外部轮廓就像这些圆圈 里面有数字 我究竟做错了什么 我可以做什么来实现它 image 1 image 2 以下是我的代码的相关部分 th
  • 如何在给定目标大小的情况下在 python 中调整图像大小,同时保留纵横比?

    首先 我觉得这是一个愚蠢的问题 对此感到抱歉 目前 我发现计算最佳缩放因子 目标像素数的最佳宽度和高度 同时保留纵横比 的最准确方法是迭代并选择最佳缩放因子 但是必须有更好的方法来做到这一点 一个例子 import cv2 numpy as
  • 在运行时更改蓝图或重新加载 Flask 应用程序

    我正在编写一个支持插件架构的 Flask 应用程序 每个插件都位于一个单独的文件夹中 并且是一个模块 该模块至少具有一个类 该类是一个子类Plugin班级 出于安全原因 我不想在 Flask 应用程序最初运行时加载所有插件 相反 用户可以从
  • 如何设置K-means openCV c++的初始中心

    我正在尝试使用 OpenCv 和 Kmeans 对图像进行分割 我刚刚实现的代码如下 include opencv2 objdetect objdetect hpp include opencv2 highgui highgui hpp i
  • OpenCV的拼接模块可以拼接平行运动相机拍摄的图像吗?

    我想知道是否缝合 http docs opencv org modules stitching doc stitching html http docs opencv org modules stitching doc stitching
  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • 多视图几何

    我从相距一定距离的两台相同品牌的相机捕获了两张图像 捕获了相同的场景 我想计算两个相机之间的现实世界旋转和平移 为了实现这一点 我首先提取了两张图像的 SIFT 特征并进行匹配 我现在有基本矩阵也单应性矩阵 然而无法进一步进行 有很多混乱
  • OpenCV 3 中的 FLANN 错误

    我运行的是 Ubuntu 14 04 我正在尝试使用 openCV 3 运行 FLANN 但出现错误 下面的所有内容都是通过使用 AKAZE 和 ORB 进行尝试的 但代码来自我尝试使用 ORB 的情况 我使用 ORB 来查找描述符和关键点
  • OpenCV C++ 如何知道每行的轮廓数进行排序?

    我有一个二值图像 https i stack imgur com NRLVv jpg在这张图片中 我可以使用重载的函数轻松地对从上到下 从左到右找到的轮廓进行排序std sort 我首先通过以下方式从上到下排序 sort contours
  • Python 线程在 main 中调用一次时运行两次[重复]

    这个问题在这里已经有答案了 if name main t threading Thread target authtarget t daemon True t start print running thread app run debug
  • 为什么我无法在 Mac 12.0.1 (Monterey) 上使用 pip 安装 OpenCV? [复制]

    这个问题在这里已经有答案了 当我尝试使用 python pip 安装 OpenCV 时 它显示了以下内容 Remainder of file ignored Requirement already satisfied pip in Libr
  • 烧瓶 - 404 未找到

    我是烧瓶开发的新手 这是我在烧瓶中的第一个程序 但它向我显示了这个错误 在服务器上找不到请求的 URL 如果您输入了网址 请手动检查拼写并重试 这是我的代码 from flask import Flask app Flask name ap
  • 操作错误:尝试在 ubuntu 服务器中写入只读数据库

    我正在使用 FlaskApp 运行mod wsgi and apache2在 Ubuntu 服务器上 我尝试运行烧瓶应用程序localhost成功 然后部署到ubuntu服务器上 但是当我尝试更新数据库时 出现错误 Failed to up

随机推荐