🎨图像处理即服务🐍
AWS AI 直播!
👋 你好
你是否编写过图像转换脚本?你是否与他人共享过该脚本,或者在多台计算机上运行过?你需要更新脚本或设置说明多少次?最终你是否将其开发成服务或在线应用程序?如果你的脚本很有用,你很可能希望将其分享给其他人。部署处理服务是一个常见的需求,但也伴随着一系列挑战。无服务器技术可以帮助你轻松高效地解决这些挑战。
在这篇文章中,你将看到如何……
- 创建一个图像处理服务,用于生成着色页。
- 使用最少的资源将其发布到网上。
……而且全部用不到 200 行 Python 和 JavaScript 代码就能完成!
🛠️ 工具
要构建和部署一个涂色页生成器,你需要一些工具:
- 一个用于处理图像的库
- 一个Web应用程序框架
- 网络服务器
- 采用无服务器解决方案,使演示全天候可用
🧱 建筑
以下是使用 Cloud Run 构建着色页生成器的一种可能架构:
以下是工作流程:
- 1 - 用户打开 Web 应用程序:浏览器请求主页。
- 2 - Cloud Run 提供应用程序 HTML 代码。
- 3 - 浏览器请求所需的其他资源。
- 4 - Cloud Run 提供 CSS、JavaScript 和其他资源。
- A - 用户选择一张图片,前端将图片发送到
/api/coloring-page端点。 - B - 后端处理输入图像并返回输出图像,然后用户可以通过浏览器查看、下载或打印该图像。
🐍 软件栈
当然,有很多不同的软件栈可以用来实现这样的架构。
这里有一个基于 Python 的好例子:
其中包括:
- Gunicorn:一款生产级 WSGI HTTP 服务器
- Flask:一个流行的 Web 应用框架
- scikit-image:一个功能强大的图像处理库
在名为以下名称的文件中定义这些应用程序依赖项requirements.txt:
# https://pypi.org/project/gunicorn
gunicorn==20.1.0
# https://pypi.org/project/flask
Flask==2.1.1
# https://pypi.org/project/scikit-image
# scikit-image dependencies include NumPy and Pillow
scikit-image==0.19.2
🎨 图像处理
如何从图像中去除颜色?一种方法是检测物体边缘,然后去除结果图像中除边缘以外的所有颜色。这可以通过Sobel滤波器来实现,Sobel 滤波器是一种卷积滤波器,它可以检测图像强度变化最大的区域。
创建一个名为 `image.py` 的 Python 文件main.py,定义一个图像处理函数,并在其中使用 scikit-image 中的 Sobel 滤波器和其他函数:
import numpy as np
import skimage
from PIL import Image
from PIL.Image import Image as PilImage
def generate_coloring_page(input: PilImage) -> PilImage:
# Convert to grayscale if needed
if input.mode != "L":
input = input.convert("L")
np_image = np.asarray(input)
# Detect the edges
np_image = skimage.filters.sobel(np_image)
# Convert to 8 bpp
np_image = skimage.util.img_as_ubyte(np_image)
# Invert to get dark edges on a light background
np_image = 255 - np_image
# Improve the contrast
np_image = skimage.exposure.rescale_intensity(np_image)
return Image.fromarray(np_image)
注意:NumPy 和 Pillow 库作为 scikit-image 的依赖项自动安装。
例如,以下是 Cloud Run 徽标在每个步骤中的处理方式:
✨ Web应用程序
后端
要公开这两个端点(GET /和POST /api/coloring-page),请在以下位置添加 Flask 路由main.py:
import io
import flask
from PIL import Image
app = flask.Flask(__name__, static_url_path="")
@app.get("/")
def index():
return app.send_static_file("index.html")
@app.post("/api/coloring-page")
def coloring_page():
file = flask.request.files.get("input-image")
if file is None:
return "Missing input-image parameter", 400
input_image = Image.open(file.stream)
output_image = generate_coloring_page(input_image)
image_io = io.BytesIO()
output_format = "png"
output_image.save(image_io, format=output_format)
image_io.seek(0)
return flask.send_file(image_io, mimetype=f"image/{output_format}")
前端
在浏览器端,编写一个 JavaScript 函数,调用该/api/coloring-page端点并接收处理后的图像:
async function fetchColoringPage(inputFile) {
const formData = new FormData()
formData.append('input-image', inputFile)
const url = '/api/coloring-page'
const init = { method: 'POST', body: formData }
try {
const response = await fetch(url, init)
return response.ok ? response.blob() : null
} catch (error) {
console.error(error)
return null
}
}
你的应用基础已经搭建完成。现在你只需要添加一些 HTML、CSS 和 JS 代码,就能实现你想要的用户体验。
地方发展
要在您的计算机上开发和测试应用程序,在设置好环境后,请确保您拥有所需的依赖项:
pip install --upgrade -r requirements.txt
将以下代码块添加到main.py您的应用程序中。它只会在您手动运行应用程序时执行:
import os
# ...
if __name__ == "__main__":
os.environ["FLASK_ENV"] = "development"
app.run(host="localhost", port=8080, debug=True)
运行你的应用:
python main.py
Flask启动本地Web服务器:
* Serving Flask app 'main' (lazy loading)
* Environment: development
* Debug mode: on
* Restarting with stat
* Debugger is active!
* Debugger PIN: 718-408-327
* Running on http://localhost:8080/ (Press CTRL+C to quit)
注意:在此模式下,您使用的是开发用 Web 服务器(不适用于生产环境)。接下来,您将配置部署,以便使用 Gunicorn(一款生产级服务器)来运行您的应用程序。
一切就绪。localhost:8080在浏览器中打开,测试、改进、迭代。
🚀 部署
当您的应用准备就绪后,您可以使用名为以下名称的文件中的一行代码来定义它的服务方式Procfile:
web: gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
目前,一个典型的项目中包含以下文件:
.
├── main.py
├── Procfile
├── requirements.txt
└── static
├── favicon.ico
├── index.html
├── scripts.js
└── styles.css
好了,现在你可以从源代码文件夹部署你的应用了:
SERVICE="coloring-page-generator"
SOURCE="."
gcloud run deploy $SERVICE --source $SOURCE --allow-unauthenticated
⚙️ 引擎盖下
命令行输出详细列出了所有步骤:
This command is equivalent to running `gcloud builds submit --pack image=[IMAGE] SOURCE` and `gcloud run deploy SERVICE --image [IMAGE]`
Building using Buildpacks and deploying container to Cloud Run service [SERVICE] in project [PROJECT_ID] region [REGION]
OK Building and deploying... Done.
OK Creating Container Repository...
OK Uploading sources...
OK Building Container... Logs are available at […].
OK Creating Revision...
OK Routing traffic...
OK Setting IAM Policy...
Done.
Service [SERVICE] revision [SERVICE-REVISION] has been deployed and is serving 100 percent of traffic.
Service URL: https://SERVICE-PROJECTHASH-REGIONID.a.run.app
Cloud Build 间接用于容器化您的应用。其核心组件之一是 Google Cloud Buildpacks,它可以根据您的源代码自动构建可用于生产环境的容器镜像。以下是主要步骤:
- Cloud Build会获取源代码。
- Buildpacks 会自动检测应用程序语言(本例中为 Python),并使用相应的安全基础镜像。
- Buildpacks 安装应用程序依赖项(
requirements.txt在 Python 中定义)。 - Buildpacks 配置服务入口点(
Procfile在 Python 中定义)。 - Cloud Build 将容器镜像推送到Artifact Registry。
- Cloud Run 会基于此容器镜像创建服务的新版本。
- Cloud Run 将生产流量路由到它。
笔记:
- Buildpacks 目前支持以下运行时:Go、Java、.NET、Node.js 和 Python。
- 基础镜像由 Google 积极维护,定期扫描安全漏洞并修复已知问题。这意味着,当您部署更新时,您的服务将基于尽可能安全的镜像。
- 如果您需要构建自己的容器镜像,例如使用自定义运行时,您可以添加自己的镜像
Dockerfile,Buildpacks 将使用它。
💫 更新
来自真实用户的更多测试表明存在一些问题。
首先,该应用无法处理使用非原生方向拍摄的数码相机照片。您可以使用 EXIF 方向数据来解决此问题:
-from PIL import Image
+from PIL import Image, ImageOps
...
def generate_coloring_page(input: PilImage) -> PilImage:
# Convert to grayscale if needed
if input.mode != "L":
input = input.convert("L")
+ # Transpose if taken in non-native orientation (rotated digital camera)
+ NATIVE_ORIENTATION = 1
+ if input.getexif().get(0x0112, NATIVE_ORIENTATION) != NATIVE_ORIENTATION:
+ input = ImageOps.exif_transpose(input)
np_image = np.asarray(input)
...
此外,该应用对输入图像的细节过于敏感。绘画中的纹理或图片中的噪点会在处理后的图像中产生许多边缘。您可以通过预先添加一个去噪步骤来改进处理算法:
...
def generate_coloring_page(input: PilImage) -> PilImage:
...
+ # Remove some noise to keep the most visible edges
+ np_image = skimage.restoration.denoise_tv_chambolle(np_image, weight=0.05)
# Detect the edges
np_image = skimage.filters.sobel(np_image)
...
这一额外步骤可以使着色页更加干净,并且如果打印出来,还可以减少墨水用量:
重新部署后,应用程序将自动更新:
gcloud run deploy $SERVICE --source $SOURCE
🎉 它活了
该应用在 Cloud Run 中显示为一项服务:
服务控制面板可让您概览应用程序使用情况:
好了,你的图像处理应用程序已经上线了!
🤯 它是无服务器的
在这种架构中使用 Cloud Run 有诸多好处:
- 您的应用全天候24小时可用。
- 环境完全托管:您可以专注于代码编写,而无需担心基础设施。
- 您的应用已自动通过HTTPS提供服务。
- 您可以将您的应用映射到自定义域名。
- Cloud Run 会自动扩展实例数量,计费仅包含代码运行时使用的资源。
- 如果您的应用未使用,Cloud Run 将缩减至零。
- 如果您的应用流量增加(例如,它上了新闻),Cloud Run 会根据需要扩展实例数量。
- 您可以通过微调许多设置来控制性能和成本:CPU、内存、并发性、最小实例数、最大实例数等等。
- 每个月,免费套餐提供前 50 个 vCPU 小时、100 GiB 小时和 200 万次请求,无需付费。
💾 源代码
该项目仅包含七个文件和不到 200 行 Python + JavaScript 代码。
您可以将此示例作为基础,构建自己的图像处理应用程序:
🖖 更多
- 试试演示版,生成你自己的涂色页。
- 了解更多关于 Cloud Run 的信息。
- 如需了解更多云相关内容,请在 Twitter ( @PicardParis ) 或 LinkedIn ( in/PicardParis ) 上关注我,如有任何反馈或疑问,欢迎随时联系我。






