DeOldify Flask集成教程:将上色能力嵌入自有Web系统完整示例

DeOldify Flask集成教程:将上色能力嵌入自有Web系统完整示例

1. 项目概述

你是不是遇到过这样的场景:手头有一堆黑白老照片,想要让它们重焕光彩,但又不想学习复杂的深度学习技术?或者你正在开发一个Web应用,想要集成图片上色功能,却被模型部署和API对接搞得头大?

现在有了DeOldify图像上色服务,这些问题都能轻松解决。基于U-Net深度学习模型,这个服务能够智能地将黑白图片转换为彩色图片,而且最重要的是——你不需要懂任何深度学习知识,就能快速集成到自己的系统中。

本文将手把手教你如何将DeOldify图像上色能力集成到Flask Web应用中,从环境准备到完整代码实现,让你快速拥有一个专业的图片上色工具。

2. 环境准备与快速部署

2.1 系统要求

在开始之前,确保你的系统满足以下要求:

  • Python 3.8或更高版本
  • 至少4GB内存(处理大图片建议8GB以上)
  • 网络连接(用于下载模型和依赖包)

2.2 安装必要依赖

首先创建并激活虚拟环境:

# 创建项目目录 mkdir deoldify-flask-app cd deoldify-flask-app # 创建虚拟环境 python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # 安装核心依赖 pip install flask requests pillow 

2.3 验证DeOldify服务

确保DeOldify服务正在运行并可以访问:

# 检查服务健康状态 curl http://localhost:7860/health 

如果服务正常,你会看到类似这样的响应:

{ "service": "cv_unet_image-colorization", "status": "healthy", "model_loaded": true } 

3. Flask应用基础框架搭建

3.1 创建Flask应用结构

让我们先建立项目的基本文件结构:

deoldify-flask-app/ ├── app.py # 主应用文件 ├── static/ # 静态文件目录 │ ├── css/ │ ├── js/ │ └── images/ ├── templates/ # 模板目录 │ └── index.html ├── uploads/ # 上传文件临时目录 └── requirements.txt # 依赖列表 

3.2 基础Flask应用代码

创建主应用文件 app.py

from flask import Flask, render_template, request, send_file, jsonify import os from werkzeug.utils import secure_filename app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key-here' app.config['UPLOAD_FOLDER'] = 'uploads' app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 50MB限制 # 确保上传目录存在 os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) # DeOldify服务配置 DEOLDIFY_API = "http://localhost:7860" @app.route('/') def index(): """显示主页面""" return render_template('index.html') if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000) 

3.3 创建基础HTML模板

创建 templates/index.html

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DeOldify图片上色工具</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> </head> <body> <div> <h1>🎨 黑白图片上色工具</h1> <p>使用DeOldify AI技术为你的黑白照片添加色彩</p> <div> <h2>上传图片</h2> <form enctype="multipart/form-data"> <div> <input type="file" accept="image/*" hidden> <label for="imageInput"> <span>📁 选择图片或拖拽到此处</span> <p>支持 JPG, PNG, BMP 格式 (最大50MB)</p> </label> </div> <button type="submit">开始上色</button> </form> </div> <div> <h2>处理结果</h2> <div> <div> <h3>原始图片</h3> <img alt="原始图片"> </div> <div> <h3>上色结果</h3> <img alt="上色结果"> <div> <button onclick="downloadImage()">⬇️ 下载图片</button> </div> </div> </div> </div> <div> <div></div> <p>AI正在为图片上色,请稍候...</p> </div> </div> <script src="{{ url_for('static', filename='js/app.js') }}"></script> </body> </html> 

4. 集成DeOldify上色功能

4.1 创建图片上色工具函数

app.py 中添加核心的上色功能:

import requests import base64 from io import BytesIO from PIL import Image import time def colorize_image(image_file): """ 调用DeOldify服务为图片上色 """ try: # 准备请求数据 files = {'image': (image_file.filename, image_file.stream, image_file.mimetype)} # 调用API start_time = time.time() response = requests.post(f"{DEOLDIFY_API}/colorize", files=files) processing_time = time.time() - start_time if response.status_code == 200: result = response.json() if result.get('success'): return { 'success': True, 'image_data': result['output_img_base64'], 'format': result.get('format', 'png'), 'processing_time': round(processing_time, 2) } return { 'success': False, 'error': '上色处理失败', 'details': response.text } except requests.exceptions.ConnectionError: return { 'success': False, 'error': '无法连接到上色服务', 'details': '请确保DeOldify服务正在运行' } except Exception as e: return { 'success': False, 'error': '处理过程中发生错误', 'details': str(e) } 

4.2 添加上传和处理路由

app.py 中添加处理路由:

@app.route('/api/colorize', methods=['POST']) def api_colorize(): """API接口:处理图片上色""" if 'image' not in request.files: return jsonify({'success': False, 'error': '没有上传图片'}) image_file = request.files['image'] if image_file.filename == '': return jsonify({'success': False, 'error': '没有选择文件'}) # 验证文件类型 allowed_extensions = {'jpg', 'jpeg', 'png', 'bmp', 'tiff', 'webp'} if '.' not in image_file.filename or \ image_file.filename.rsplit('.', 1)[1].lower() not in allowed_extensions: return jsonify({'success': False, 'error': '不支持的图片格式'}) # 保存原始图片用于显示 filename = secure_filename(image_file.filename) original_path = os.path.join(app.config['UPLOAD_FOLDER'], f"original_{filename}") image_file.save(original_path) # 重置文件指针并调用上色服务 image_file.stream.seek(0) result = colorize_image(image_file) if result['success']: # 保存处理结果 colored_path = os.path.join(app.config['UPLOAD_FOLDER'], f"colored_{filename}") img_data = base64.b64decode(result['image_data']) with open(colored_path, 'wb') as f: f.write(img_data) result['original_filename'] = filename result['original_path'] = original_path result['colored_path'] = colored_path return jsonify(result) @app.route('/download/<filename>') def download_file(filename): """下载处理后的图片""" safe_filename = secure_filename(filename) file_path = os.path.join(app.config['UPLOAD_FOLDER'], safe_filename) if os.path.exists(file_path) and safe_filename.startswith('colored_'): return send_file(file_path, as_attachment=True) else: return '文件不存在', 404 

5. 前端交互功能实现

5.1 创建CSS样式文件

创建 static/css/style.css

* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; background: white; border-radius: 15px; padding: 30px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); } h1 { text-align: center; color: #333; margin-bottom: 10px; font-size: 2.5em; } p { text-align: center; color: #666; margin-bottom: 30px; } .upload-section { background: #f8f9fa; padding: 30px; border-radius: 10px; margin-bottom: 30px; } .file-upload { margin-bottom: 20px; } .upload-label { display: block; padding: 60px; border: 3px dashed #ccc; border-radius: 10px; text-align: center; cursor: pointer; transition: all 0.3s ease; } .upload-label:hover { border-color: #667eea; background: #f0f4ff; } .upload-label span { font-size: 1.2em; color: #667eea; display: block; margin-bottom: 10px; } .upload-label p { color: #999; margin: 0; } .btn-primary { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 15px 30px; border-radius: 8px; font-size: 1.1em; cursor: pointer; width: 100%; transition: transform 0.2s ease; } .btn-primary:hover { transform: translateY(-2px); } .btn-primary:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } .result-section { margin-top: 30px; } .comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-top: 20px; } .image-box { text-align: center; } .image-box h3 { margin-bottom: 15px; color: #333; } .image-box img { max-width: 100%; height: auto; border-radius: 8px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } .download-btn { margin-top: 15px; } .download-btn button { background: #28a745; color: white; border: none; padding: 10px 20px; border-radius: 6px; cursor: pointer; } .loading { text-align: center; padding: 40px; } .spinner { width: 50px; height: 50px; border: 5px solid #f3f3f3; border-top: 5px solid #667eea; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 20px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .error { background: #ffe6e6; color: #d63384; padding: 15px; border-radius: 8px; margin: 20px 0; text-align: center; } .success { background: #e6f7e6; color: #28a745; padding: 15px; border-radius: 8px; margin: 20px 0; text-align: center; } @media (max-width: 768px) { .comparison { grid-template-columns: 1fr; } .container { padding: 15px; } } 

5.2 创建JavaScript交互逻辑

创建 static/js/app.js

document.addEventListener('DOMContentLoaded', function() { const form = document.getElementById('uploadForm'); const fileInput = document.getElementById('imageInput'); const uploadLabel = document.querySelector('.upload-label'); const resultSection = document.querySelector('.result-section'); const loading = document.querySelector('.loading'); // 拖拽上传功能 uploadLabel.addEventListener('dragover', function(e) { e.preventDefault(); this.style.borderColor = '#667eea'; this.style.background = '#f0f4ff'; }); uploadLabel.addEventListener('dragleave', function(e) { e.preventDefault(); this.style.borderColor = '#ccc'; this.style.background = 'transparent'; }); uploadLabel.addEventListener('drop', function(e) { e.preventDefault(); this.style.borderColor = '#ccc'; this.style.background = 'transparent'; const files = e.dataTransfer.files; if (files.length > 0) { fileInput.files = files; updateFileName(files[0].name); } }); // 文件选择变化 fileInput.addEventListener('change', function() { if (this.files.length > 0) { updateFileName(this.files[0].name); } }); // 表单提交 form.addEventListener('submit', async function(e) { e.preventDefault(); if (!fileInput.files.length) { alert('请选择要上传的图片'); return; } const formData = new FormData(); formData.append('image', fileInput.files[0]); // 显示加载中 showLoading(); hideResult(); hideError(); try { const response = await fetch('/api/colorize', { method: 'POST', body: formData }); const result = await response.json(); if (result.success) { showResult(result); } else { showError(result.error, result.details); } } catch (error) { showError('网络错误', '无法连接到服务器'); } finally { hideLoading(); } }); function updateFileName(filename) { const span = uploadLabel.querySelector('span'); span.textContent = `📁 已选择: ${filename}`; } function showLoading() { loading.style.display = 'block'; form.querySelector('button').disabled = true; } function hideLoading() { loading.style.display = 'none'; form.querySelector('button').disabled = false; } function showResult(result) { // 显示原始图片 const originalImage = document.getElementById('originalImage'); originalImage.src = URL.createObjectURL(fileInput.files[0]); // 显示上色结果 const coloredImage = document.getElementById('coloredImage'); coloredImage.src = `data:image/${result.format};base64,${result.image_data}`; // 存储文件名用于下载 coloredImage.dataset.filename = result.original_filename; // 显示处理时间 const timeElement = document.createElement('div'); timeElement.className = 'success'; timeElement.innerHTML = `✅ 上色完成!处理时间: ${result.processing_time}秒`; resultSection.prepend(timeElement); resultSection.style.display = 'block'; } function hideResult() { resultSection.style.display = 'none'; } function showError(title, message) { const errorDiv = document.createElement('div'); errorDiv.className = 'error'; errorDiv.innerHTML = ` <strong>❌ ${title}</strong> <p>${message}</p> `; const container = document.querySelector('.container'); const uploadSection = document.querySelector('.upload-section'); container.insertBefore(errorDiv, uploadSection.nextSibling); // 5秒后自动隐藏错误信息 setTimeout(() => { errorDiv.remove(); }, 5000); } function hideError() { const errorDiv = document.querySelector('.error'); if (errorDiv) { errorDiv.remove(); } } }); // 下载图片功能 function downloadImage() { const coloredImage = document.getElementById('coloredImage'); const filename = coloredImage.dataset.filename; if (filename) { const link = document.createElement('a'); link.href = coloredImage.src; link.download = `colored_${filename}`; link.click(); } } 

6. 完整应用测试与部署

6.1 测试应用功能

现在启动你的Flask应用进行测试:

python app.py 

打开浏览器访问 http://localhost:5000,你应该能看到图片上色工具界面。尝试上传一张黑白图片,等待几秒钟后就能看到上色效果。

6.2 添加错误处理和日志记录

为了完善应用,添加错误处理和日志记录:

import logging from datetime import datetime # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('app.log'), logging.StreamHandler() ] ) logger = logging.getLogger(__name__) @app.errorhandler(413) def too_large(e): return jsonify({'success': False, 'error': '文件太大', 'details': '请上传小于50MB的图片'}), 413 @app.errorhandler(500) def internal_error(e): logger.error(f'服务器内部错误: {str(e)}') return jsonify({'success': False, 'error': '服务器内部错误'}), 500 # 在colorize_image函数中添加日志记录 def colorize_image(image_file): try: logger.info(f'开始处理图片: {image_file.filename}') # ... 原有代码 ... if result['success']: logger.info(f'图片处理成功: {image_file.filename}, 耗时: {processing_time}秒') else: logger.error(f'图片处理失败: {image_file.filename}, 错误: {result.get("error")}') return result except Exception as e: logger.error(f'处理图片时发生错误: {str(e)}') return { 'success': False, 'error': '处理过程中发生错误', 'details': str(e) } 

6.3 生产环境部署建议

对于生产环境,建议使用Gunicorn和Nginx:

  1. 安装Gunicorn:
pip install gunicorn 
  1. 创建Gunicorn配置文件 gunicorn_conf.py
bind = "0.0.0.0:5000" workers = 4 worker_class = "sync" timeout = 120 
  1. 使用Gunicorn启动应用:
gunicorn -c gunicorn_conf.py app:app 
  1. 配置Nginx反向代理(可选但推荐)

7. 总结

通过本教程,你已经成功将DeOldify图像上色能力集成到了Flask Web应用中。现在你拥有一个功能完整的图片上色工具,支持:

  • 🖼️ 拖拽上传和文件选择两种方式
  • 🎨 调用DeOldify AI服务进行智能上色
  • 📱 响应式设计,支持移动端访问
  • ⬇️ 一键下载上色结果
  • ⚡ 实时进度显示和错误处理

这个示例展示了如何将复杂的AI能力以简单的方式集成到Web应用中,即使你没有深度学习背景也能轻松实现。你可以在此基础上进一步扩展功能,比如添加批量处理、历史记录、用户管理等功能。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 ZEEKLOG星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Read more

F076 中医中药知识智能问答与图谱构建研究系统 Vue+Flask+Neo4j

F076 中医中药知识智能问答与图谱构建研究系统 Vue+Flask+Neo4j

文章结尾部分有ZEEKLOG官方提供的学长 联系方式名片 关注B站,私信获取! 麦麦大数据 编号: F076 视频 <<待上传>> 1 系统简介 系统简介:本系统是一个基于Vue+Flask+Neo4j+MySQL构建的《中医中药知识智能问答与图谱构建研究系统》。其核心围绕中医证型、中药信息的数字化管理、智能问答及知识图谱的构建与多维度可视化分析能力展开。 本系统主要面向用户提供中医证型查询、中药推荐、病症知识智能问答等功能,同时面向管理员提供数据分析、用户管理、基础数据维护等系统级管理功能。其关键技术栈涵盖前后端分离架构、图数据库Neo4j、传统关系型数据库MySQL,结合多种文本挖掘算法(如TF-IDF、TextRank、YAKE)完成对数据内容的智能分析。 主要功能模块包括:用户登录与注册、中医证型管理、中药信息展示、知识图谱可视化、智能问答、病症知识推荐、用户画像分析、系统数据管理、个人信息设置等。 2 功能设计

如何轻松分析大疆无人机信号?DJI DroneID 信号解析工具全指南

如何轻松分析大疆无人机信号?DJI DroneID 信号解析工具全指南 🛸 【免费下载链接】dji_droneid 项目地址: https://gitcode.com/gh_mirrors/dj/dji_droneid DJI DroneID 信号分析项目(dji_droneid)是一个开源工具集,专为无人机爱好者和研究人员设计,通过软件定义无线电(SDR)技术捕获、解码和分析大疆无人机发射的DroneID信号。该项目提供完整的信号处理流程,从原始IQ数据捕获到最终数据帧解析,支持Octave和MATLAB环境运行,帮助用户深入理解无人机通信机制。 📌 项目核心功能与技术架构 🔍 信号捕获与处理全流程 项目实现了从射频信号到数据帧的完整解析链路,主要包括: * 原始信号采集:支持32位浮点IQ数据文件输入(需配合SDR设备录制) * ZC序列检测:通过归一化互相关算法定位信号中的Zadoff-Chu序列 * 频率校正:自动检测并补偿信号中的频率偏移 * OFDM符号提取:精准提取9个OFDM符号(含2个ZC序列符号) * 相位校正与均衡:解决无线信道引入的

低代码集成:将PDF-Extract-Kit-1.0接入Power Platform的完整教程

低代码集成:将PDF-Extract-Kit-1.0接入Power Platform的完整教程 你是不是也遇到过这样的情况:公司里每天都有大量PDF格式的合同、发票、报告需要处理,手动复制粘贴不仅费时费力,还容易出错?而开发一个完整的自动化系统又太复杂,API调用、身份验证、数据解析……光是想想就头大。 别担心,今天我要分享的这个方法,完全不需要写一行后端代码,就能把强大的AI驱动PDF解析能力——PDF-Extract-Kit-1.0,轻松集成到你的Power Apps应用中。哪怕你是零编程基础的业务人员,也能在30分钟内完成整个流程。 PDF-Extract-Kit-1.0 是目前开源社区中表现最出色的PDF内容提取工具之一。它不仅能精准识别文本、表格、图像和公式,还能理解文档的布局结构,即便是扫描件或模糊文件也能保持高准确率。更重要的是,它的模型已经预置在ZEEKLOG星图镜像广场中,支持一键部署为HTTP服务,这为我们通过Power Automate调用提供了极大便利。 本文将带你从零开始,一步步实现: * 如何快速部署 PDF-Extract-Kit-1.0 镜像

OpenClaw基础-3-telegram机器人配置与加入群聊

OpenClaw基础-3-telegram机器人配置与加入群聊 💡 大家好,我是可夫小子,《小白玩转ChatGPT》专栏作者,关注AI编程、AI自动化和自媒体。 Openclaw的优势是接入各种聊天工作,在前面的文章里,已经介绍了如何接入飞书。但之前我也提到了,飞书的最大的问题是请求多的限制,以及无法在非认证企业账号下面组建群聊。但这些限制另一个聊天工具可以打破,那就是Telegram,今天就跟大家分享一下,如果在OpenClaw里面接入Telegram。 第一步:Openclaw端配置 通过命令openclaw config,local→channels→telegrams 这里等待输入API Token,接下来我们去Telegram里面获取 第二步:Telegram端配置 1. 1. 在聊天窗口找到BotFather,打开对话与他私聊 2. 3. 然后再输入一个机器人,再输入一个账号名username,这里面要求以Bot或者Bot结尾,这个是全网的id,要 2. /newbot 来创建一个机器人,输入一个名字name