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

GLM-4.6V-Flash-WEB Web界面使用指南,拖图就出结果

GLM-4.6V-Flash-WEB Web界面使用指南,拖图就出结果 你不需要配置环境、不用写一行推理代码、甚至不用打开终端——只要把一张截图拖进浏览器窗口,几秒钟后,它就能告诉你图里写了什么、画了什么、哪里有问题。这不是未来预告,而是你现在就能在本地跑起来的真实体验。 GLM-4.6V-Flash-WEB 是智谱AI最新开源的轻量级视觉语言模型,专为Web端实时交互而生。它不像某些“实验室模型”那样只存在于论文和Benchmark表格里,而是真正做到了:部署快、启动快、响应快、上手更快。一块RTX 3090,一个浏览器,一次拖拽,结果即刻呈现。 本文不讲训练原理,不列参数表格,不堆技术术语。我们只聚焦一件事:怎么用好它的Web界面?从零开始,到稳定产出,每一步都清晰可操作。 1. 为什么说“拖图就出结果”不是宣传话术? 很多多模态模型标榜“支持图文理解”,但实际用起来才发现:要装依赖、改路径、调精度、修CUDA版本、

前端防范 XSS(跨站脚本攻击)

目录 一、防范措施 1.layui util  核心转义的特殊字符 示例 2.js-xss.js库 安装 1. Node.js 环境(npm/yarn) 2. 浏览器环境 核心 API 基础使用 1. 基础过滤(默认规则) 2. 自定义过滤规则 (1)允许特定标签 (2)允许特定属性 (3)自定义标签处理 (4)自定义属性处理 (5)转义特定字符 常见场景示例 1. 过滤用户输入的评论内容 2. 允许特定富文本标签(如富文本编辑器内容) 注意事项 更多配置 XSS(跨站脚本攻击)是一种常见的网络攻击手段,它允许攻击者将恶意脚本注入到其他用户的浏览器中。

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

目录 1. 打开浏览器开发者工具 2. 使用 Network 面板 3. 查看具体的API请求 a. Headers b. Payload c. Response d. Preview e. Timing 4. 实际操作步骤 5. 常见问题及解决方法 a. 无法看到API请求 b. 请求失败 c. 跨域问题(CORS) 作为一名后端工程师,理解前端如何调用接口、传递参数以及接收返回值是非常重要的。下面将详细介绍如何通过浏览器开发者工具(F12)查看和分析这些信息,并附带图片案例帮助你更好地理解。 1. 打开浏览器开发者工具 按下 F12 或右键点击页面选择“检查”可以打开浏览器的开发者工具。常用的浏览器如Chrome、Firefox等都内置了开发者工具。下面是我选择我的一篇文章,打开开发者工具进行演示。 2. 使用

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例)

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例) 前端开发中最令人头疼的莫过于那些难以定位的UI问题——元素错位、样式冲突、响应式失效...传统调试方式往往需要反复修改代码、刷新页面、检查元素。现在,通过Cursor编辑器集成的Codex功能,你可以直接用截图交互快速定位和修复这些问题。本文将带你从零开始,掌握这套革命性的调试工作流。 1. 环境准备与基础配置 在开始之前,确保你已经具备以下环境: * Cursor编辑器最新版(v2.5+) * Node.js 18.x及以上版本 * React 18项目(本文以Chakra UI 2.x为例) 首先在Cursor中安装Codex插件: 1. 点击左侧扩展图标 2. 搜索"Codex"并安装 3. 登录你的OpenAI账户(需要ChatGPT Plus订阅) 关键配置项: // 在项目根目录创建.