Python - 搭建 Flask 服务实现图像、视频修复需求

目录

一.引言

二.服务构建

1.主函数 upload_gif

2.文件接收

3.专属目录

4.图像修复

5.gif2mp4

6.mp42gif

7.图像返回

三.服务测试

1.服务启动

2.服务调用

四.总结


一.引言

前面我们介绍了如何使用 Real-ESRGAN 进行图像增强并在原始格式 jpeg、jpg、mp4 的基础上增加了 gif 图像的处理:

◆ 图像修复:  Python - Real-ESRGAN 提升图像、视频清晰度

◆ 动图修复:  Python - Real-ESRGAN 提高 gif 图像质量

为了方便随时随地上传图片即可修图,我们将上面的内容结合,通过 Flask 框架搭建图像修复服务。

二.服务构建

1.主函数 upload_gif

from flask import Flask, request, send_file, abort
from moviepy.editor import VideoFileClip
import os
import subprocess
import shutil
from enhance_frame import enhance

app = Flask(__name__)

output="./server/"

@app.route('/upload-gif', methods=['POST'])
def upload_gif():
    if 'gif' not in request.files:
        return abort(400, 'No gif file part in the request')

    file = request.files['gif']

    # 确保文件名安全
    if file.filename == '':
        return abort(400, 'No selected file')

    if file and file.filename.lower().endswith('.gif'):
        # 1.创建专属文件夹
        gif_name = file.filename.split(".")[0]
        cur_dir = os.path.join(output, gif_name)

        # 临时测试
        #shutil.rmtree(cur_dir)

        if not os.path.isdir(cur_dir):
            print(f"文件夹 {cur_dir} 不存在,创建中 ...")
            os.makedirs(cur_dir)

            #  2.图像转存至本地并切换为 mp4 格式
            input_path = os.path.join(cur_dir, file.filename)
            print(f"原始图像保存路径 {input_path}")
            file.save(input_path)
            mp4_path, w, h = gif2mp4(input_path, gif_name, cur_dir)
            print(f"GIF 转 MP4 路径 {mp4_path}")

            # 3.对图像进行增强行理
            enhance(mp4_path, cur_dir)
            enhance_output = os.path.join(cur_dir, gif_name + "_trans_out.mp4")

            # 4.转换为 gif 并返回
            final_output = os.path.join(cur_dir, gif_name + "_out.gif")
            mp42gif(enhance_output, final_output, w, h)

        else:
            print(f"文件夹 {cur_dir} 存在 ...")
            final_output = 'uploaded.gif'

        return send_file(final_output, mimetype='image/gif')

    return abort(400, 'The uploaded file is not a GIF')

主函数为 Post 形式,其通过 request.files 接收传入的 gif 图像并对图像进行修复,返回修复后的 gif 图像。下面分步骤对修复过程中的代码进行讲解。

2.文件接收

    if 'gif' not in request.files:
        return abort(400, 'No gif file part in the request')

    file = request.files['gif']

    # 确保文件名安全
    if file.filename == '':
        return abort(400, 'No selected file')

首先检查 gif 是否在传入的图像中,随后通过 .files['gif'] 获取传入的 gif 图像,最后检查文件名为空的异常情况。这里只做了简单的异常判断,大家可以根据自己场景进行扩充。

3.专属目录

    if file and file.filename.lower().endswith('.gif'):
        # 1.创建专属文件夹
        gif_name = file.filename.split(".")[0]
        cur_dir = os.path.join(output, gif_name)

        # 临时测试
        #shutil.rmtree(cur_dir)

        if not os.path.isdir(cur_dir):
            print(f"文件夹 {cur_dir} 不存在,创建中 ...")
            os.makedirs(cur_dir)

这里通过 file.filename 获取对应 gif 图的名称,并在输出文件中创建该 gif 图的专属文件夹,一方面是可以记录 Post 请求传来的图像以及修复后的状态,另一方面相当于做了一个本地 Cache,如果相同名称的 gif 图像再次 Post 传过来,可以直接在文件夹中找到缓存的返回。

4.图像修复

            #  2.图像转存至本地并切换为 mp4 格式
            input_path = os.path.join(cur_dir, file.filename)
            print(f"原始图像保存路径 {input_path}")
            file.save(input_path)
            mp4_path, w, h = gif2mp4(input_path, gif_name, cur_dir)
            print(f"GIF 转 MP4 路径 {mp4_path}")

            # 3.对图像进行增强行理
            enhance(mp4_path, cur_dir)
            enhance_output = os.path.join(cur_dir, gif_name + "_trans_out.mp4")

            # 4.转换为 gif 并返回
            final_output = os.path.join(cur_dir, gif_name + "_out.gif")
            mp42gif(enhance_output, final_output, w, h)

由于原始的 Real-ESRGAN 源码对视频只支持了 flv 和 mp4,因此对于要修复的 gif 我们需要:

◆ gif2mp4

先将其逐帧转换为 mp4 ,这一步由 gif2mp4 函数负责;

◆ enhance

转换为 mp4 后由 enhance 函数进行修复,这里 enhance 函数对应源码中的 inference_realesrgan_video.py ,enhance 函数对应源码中的 main() 函数,只需要修改名称即可;

◆ mp42gif

修复后再将 mp4 转换为 gif,这一步由 mp42gif 负责。

Tips:

如果觉得上述过程比较繁琐,可以直接通过 ffmpeg 在源码中实现对 gif 图像进行转换。

5.gif2mp4

def gif2mp4(file_path, filename, out):
    # 加载GIF文件
    clip = VideoFileClip(file_path)
    # 输出地址
    output = os.path.join(out, filename + "_trans.mp4")
    # 将GIF文件写到MP4文件
    clip.write_videofile(output, fps=clip.fps, codec="libx264", bitrate='8000k')
    # 关闭
    clip.close()
    return output, clip.w, clip.h

通过 moviepy 的 VideoFileClip 函数读取 mp4,随后通过 write_videofile 将 mp4 写出,这里 bitrate 可以控制输出 mp4 的码率,数值越高可以在一定程度提高输出视频的质量。同时为了保证输出的 gif 图像与原始 gif 图像的长宽保持一致,这里我们还返回了 clip.w 和 clip.h。

6.mp42gif

def mp42gif(file_path, out, w, h):

    # 加载GIF文件
    clip = VideoFileClip(file_path)

    # 目标大小
    resized_clip = clip.resize(width=w).resize(height=h)

    # 导出GIF
    resized_clip.write_gif(out, fps=15)  # fps参数可以减少帧数,来进一步降低文件大小

    # 释放资源
    clip.close()

还是通过 moviepy 进行 mp4 到 gif 的转换,使用 resize 保证输出的 gif 与原始 gif 尺寸相同,由于增强的缘故,新生成的 gif 会比之前的老图大 5-10 倍,如果有缩减的需要,可以减少 FPS 或者使用 reduction_factor 按百分比减少分辨率。

7.图像返回

        else:
            print(f"文件夹 {cur_dir} 存在 ...")
            final_output = 'uploaded.gif'

        return send_file(final_output, mimetype='image/gif')

    return abort(400, 'The uploaded file is not a GIF')

else 逻辑其实是该 gif 存在缓存文件夹,直接在文件夹找增强过的图像直接返回就可以了,这里省略了 Cache 的逻辑,有需要的同学也可以自己添加。最后就是通过 send_file 将 final_output 文件写出,作为 Post 的结果回传。

三.服务测试

1.服务启动

if __name__ == '__main__':
    # 这将允许你在你的开发机上本地运行它
    ip = "10.196.1.666"
    app.run(host=ip, port=5000, debug=True)

运行主函数后提示下述信息即代表 Http 服务启动,Running on http: 后面就是对应的 URL。如果显示异常可以尝试切换 port 重新启动: 

2.服务调用

在本地执行下述命令:

#!/bin/bash

# gif 路径
gif_path="gif=@/Users/xxx/Desktop/892f4f60de074a7b9c682f744a5cf6f8.gif"
# post 调用 URL
url="http://10.192.1.666:5000/upload-gif"
# 输出地址
out="response.gif"

curl -X POST $url -F $gif_path --output $out

◆ 服务端日志

服务端日志会把 Flask 程序里相关的 print 都打印出来,最后 inference 是视频修复的 tqdm 进度条,这里 nb_frames: 12 代表当前 gif 转换的 mp4 共包含 12 帧,程序在单线程的情况下需要逐帧转换,有需要的同学也可以使用多线程实现,分 Frame 处理,最后使用 ffmpeg 进行合并。

◆ 本地日志

本地日志会记录调用的时间以及相关接收数据等信息。 

◆ gif 修复前

 ◆ gif 修复后

四.总结

本文使用 Flask 搭建了轻量级的图像修复服务,可以优化的点还有很多,大家可以多多交流讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/237570.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MAC配置环境变量

1、配置 JAVA JDK 1.1、查看 JDK 安装目录 (1)可以在Android Studio中查看,复制该路径 (2)也可以在官网下载 Java JDK下载地址 mac中的安装地址是"资源库->Java->JavaVirtualMachines"中 1.2、…

【Nacos】在Windows环境下搭建Nacos服务与Python开发示例

在Windows环境下搭建Nacos服务与Python开发示例 Nacos是一个开源的动态服务发现、配置和服务管理平台。本文将介绍在Windows环境下搭建Nacos服务,并提供一个简单的Python示例,演示如何通过Nacos实现服务注册与发现。 官方提示:Nacos定义为一…

nodejs+vue+微信小程序+python+PHP的外卖数据分析-计算机毕业设计推荐django

构建一种完全可实现、可操作的开放源代码信息收集系统,帮助记者完成工作任务。采编人员仅需输入所收集到的网址及题目即可迅速启动收集工作并进行信息归类。 2.根据新的数据收集要求,采用云计算技术实现新的收集器的迅速部署。对于资料采集点的改版&…

IoTDB控制台工具Workbench

文章目录 概述环境要求安装下载启动服务 登录用户界面主界面 连接 概述 Workbench是一个可创建多个连接的图形化数据库管理工具,用于管理IoTDB,提供元数据的可视化与管理、数据的增删改查以及权限控制等功能。Workbench不仅满足专业开发人员的所有需求&…

读程序员的README笔记08_依赖管理

1. 行为准则 2. 依赖管理 2.1. 在现有的代码上增加一个依赖似乎是一个简单的决定 2.2. 不要重复自己”(Don’t repeat yourself,DRY)是一个通常被教导的原则 2.3. 依赖关系带来了风险 2.3.1. 不兼容的变化 2.3.2. 循环依赖 2.3.3. 版本冲突 2.3.4. 缺乏控制 …

<url-pattern>/</url-pattern>与<url-pattern>/*</url-pattern>的区别

<url-pattern>/</url-pattern> servlet的url-pattern设置为/时&#xff0c; 它仅替换servlet容器的默认内置servlet&#xff0c;用于处理所有与其他注册的servlet不匹配的请求。直白点说就是&#xff0c;所有静态资源&#xff08;js&#xff0c;css&#xff0c;ima…

nodejs+vue+微信小程序+python+PHP基于spark的酒店管理系统-计算机毕业设计推荐

通过管理系统进行全面的线上管理。管理者可以通过基于spark的酒店管理系统&#xff0c;全面掌握酒店客房的各项状态&#xff0c;会员通过系统查询酒店客房信息&#xff0c;在线预定。 酒店作为旅游过程必须的设施&#xff0c;也逐渐需需要进行信息化管理&#xff0c;把酒店类型…

【PyTorch】现代卷积神经网络

文章目录 1. 理论介绍1.1. 深度卷积神经网络&#xff08;AlexNet&#xff09;1.1.1. 概述1.1.2. 模型设计 1.2. 使用块的网络&#xff08;VGG&#xff09;1.3. 网络中的网络&#xff08;NiN&#xff09;1.4. 含并行连结的网络&#xff08;GoogLeNet&#xff09; 2. 实例解析2.1…

连连看游戏

连通块记忆性递归的综合运用 这里x&#xff0c;y的设置反我平常的习惯&#xff0c;搞得我有点晕 实际上可以一输入就交换x&#xff0c;y的数据的 如果设置y1为全局变量的话会warning&#xff1a; warning: built-in function y1 declared as non-function 所以我改成p和q了…

Python---综合案例

一、系统需求分析 1、需求分析 使用面向对象编程思想完成学员管理系统的开发&#xff0c;具体如下&#xff1a; ① 系统要求&#xff1a;学员数据存储在文件中 ② 系统功能&#xff1a;添加学员、删除学员、修改学员信息、查询学员信息、显示所有学员信息、保存学员信息及退…

Kotlin基础——基础内容

文章目录 1 函数和变量1.1 基本程序1.2 函数1.3 变量1.3.1 变量的类型推导1.3.2 可变变量和不可变量1.3.3 变量使用规则 1.4 字符串模板 2 类和属性2.1 属性2.2 自定义访问器2.3 目录和包2.3.1 同包访问2.3.2 不同包导入2.3.3 包名类名定义规则 3 枚举和“when”3.1 声明枚举类…

软件测试之压力测试详解

一、什么是压力测试 软件测试中&#xff1a;压力测试&#xff08;Stress Test&#xff09;&#xff0c;也称为强度测试、负载测试。压力测试是模拟实际应用的软硬件环境及用户使用过程的系统负荷&#xff0c;长时间或超大负荷地运行测试软件&#xff0c;来测试被测系统的性能、…

leetcode-19-删除链表的倒数第N个节点

题目&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]示…

深度学习 Day15——P4猴痘病识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU&#xff08;如果设备上支持GPU就使用GPU,否则使用C…

Swagger快速上手

快速开始&#xff1a; 导入maven包 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0</version> </dependency><dependency><groupId>io.springfox<…

UDS DTC故障码格式

文章目录 DTC的定义DTC 故障码的分类DTC 故障码的组成1、OBD DTC 格式结构2、UDS DTC&#xff08;ISO 14229-1、ISO 15031-6&#xff09;格式结构 参考 DTC的定义 DTC&#xff0c;Diagnostic Trouble Code&#xff0c;诊断故障码&#xff0c;即 故障类型的 ID。 一个完整的DT…

【快速应用开发】看看RedwoodJS

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

CommonJs模块化实现原理ES Module模块化原理

CommonJs模块化实现原理 首先看一个案例 初始化项目 npm init npm i webpack -D目录结构如下&#xff1a; webpack.config.js const path require("path"); module.exports {mode: "development",entry: "./src/index.js",output: {path: p…

VBA信息获取与处理:在EXCEL中随机函数的利用

《VBA信息获取与处理》教程(版权10178984)是我推出第六套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。这部教程给大家讲解的内容有&#xff1a;跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互…

助力工业生产质检,基于轻量级yolov5-seg开发构建工业场景下滚珠丝杠传动表面缺陷分割检测系统

AI赋能工业生产是一个强有力的方式&#xff0c;在我们之前的系列博文中也有很多相应的开发实践&#xff0c;感兴趣的胡都可以自行移步阅读&#xff0c;本文的核心思想就是想要基于轻量级的实例分割模型来开发构建工业场景下的滚珠丝杠传动表面缺陷分割检测系统&#xff0c;首先…