背景

本文次要介绍 AI 绘图开源工具 Stable Diffusion WebUIAPI 开启和根本调用办法,通过本文的浏览,你将理解到 stable-diffusion-webui 的根本介绍、装置及 API 环境配置;文生图、图生图、部分重绘、前期解决等 API 接口调用;图像处理开发中罕用到一些办法如 Base64PNGCanvasURL 互相转换、Canvas 色彩转换等。

AI 绘图工具目前市面上比拟宽泛应用的次要有两款,一个是 Midjourney,它提供面向用户有好的操作界面,文生图、图生图等性能十分弱小,然而它是一款免费软件;另一个就是开源工具 Stable Diffusion, 同样具备弱小的AI绘图和图片再发明能力,然而学习老本和上手难度绝对较大,不过因为它是开源的,当初有十分多的用户和开发者,咱们能够找到丰盛的训练模型和学习资源。本文介绍的 Stable Diffusion WebUI 就是基于 Stable Diffusion 的具备比较完善的可视化操作界面的 AI 绘图开源工具,它的 github 拜访地址是 https://github.com/AUTOMATIC1111/stable-diffusion-webui。

顺便一提,本文上方的 Banner 图就是应用 Stable Diffusion 生成的

应用体验

在正式开发之前,咱们能够先体验一下 Stable Diffusion WebUI 以及两个接口封装和操作界面比拟优良的 AI 绘图网站,理解文生图图生图前期解决等根本操作步骤。

  • https://stablediffusionweb.com/WebUI
  • https://d.design
  • https://www.liblibai.com

环境配置

装置 Stable Diffusion WebUI

咱们首先须要先在本地或者服务器装置部署 Stable Diffusion WebUI,能够从Github克隆仓库,而后按阐明文档进行装置,对前端开发来说装置流程非常简单,具体装置流程大家能够自行搜寻,当初网上曾经有很多保姆级的教程,本文不再赘述。

装置实现后,在 Windows操作系统中进入 stable-diffusion-webui 根目录,而后双击 webui-user.bat 文件即可开启本地运行服务,在浏览器中输出 http://localhost:7860 加载如下所示的界面。在 txt2img 输入框中输出须要生图图像的的正向关键词和反向关键词,点击 Generate 按钮即可生成图像。

实现根本装置后,还能够装置界面汉化插件、关键字中文翻译插件、本人喜爱的格调模型等,都能够依照教程非常容易实现。

开启 API 性能

stable-diffusion-webui 根目录下找到文件 webui-user.bat,应用编辑器关上这个文件,而后在 COMMANDLINE_ARGS 配置项前面增加 --api

set COMMANDLINE_ARGS= --lowvram --precision full --api --listen

而后双击 webui-user.bat 重启服务,此时在浏览器中输出地址 https://localhost:7860/doc,就能看到如下所示的所有接口文档了,咱们能够从文档中找到须要接入的接口及具体参数。

咱们还能够配置如上所示的 --listen 参数,这样就能够通过局域网拜访 stable-diffusion-webui 的接口了。

实现

文生图

文生图接口,能够通过向 stable-diffusion-webui 服务发送正向关键字、反向关键字、图片尺寸、采样步数等参数来调用AI能力生成图片。咱们先来看看它有哪些可配置的 payload 参数选项。(临时只用到前面写了正文的参数,基本上能够满足大部分文生图参数配置)

{  "enable_hr": false,                 // 开启高清hr  "denoising_strength": 0,            // 降噪强度  "hr_scale": 2,                      // 高清级别  "hr_upscaler": "string",  "hr_second_pass_steps": 0,  "hr_resize_x": 0,  "hr_resize_y": 0,  "hr_sampler_name": "string",  "hr_prompt": "",  "hr_negative_prompt": "",  "prompt": "",                       // 正向关键字  "styles": [    "string"  ],  "seed": -1,                         // 随机种子  "subseed": -1,                      // 子级种子  "subseed_strength": 0,              // 子级种子影响力度  "seed_resize_from_h": -1,  "seed_resize_from_w": -1,  "sampler_name": "string",  "batch_size": 1,                    // 每次生成的张数  "n_iter": 1,                        // 生成批次  "steps": 50,                        // 生成步数  "cfg_scale": 7,                     // 关键词相关性  "width": 512,                       // 生成图像宽度  "height": 512,                      // 生成图像高度  "restore_faces": false,             // 面部修复  "tiling": false,                    // 平铺  "do_not_save_samples": false,  "do_not_save_grid": false,  "negative_prompt": "string",        // 反向关键字  "eta": 0,                           // 等待时间  "s_min_uncond": 0,  "s_churn": 0,  "s_tmax": 0,  "s_tmin": 0,  "s_noise": 1,  "override_settings": {},             // 覆盖性配置  "override_settings_restore_afterwards": true,  "script_args": [],                   // lora 模型参数配置  "sampler_index": "Euler",            // 采样办法  "script_name": "string",  "send_images": true,                 // 是否发送图像  "save_images": false,                // 是否在服务端保留生成的图像  "alwayson_scripts": {}               // alwayson配置}

依据须要的参数,在页面逻辑中,咱们能够像上面这样实现,此时服务端会依据接口参数,一次生成4张对应的图。接口返回胜利之后,咱们会接管到一个蕴含所有图片数据名为 images 的数组,数组项是格局为 base64 的图片,咱们能够向上面这样转化为页面上可间接显示的图片。

const response = await txt2img({  id_task: `task(${taskId})`,  // 正向关键词  prompt: 'xxxx',  // 反向关键词  negative_prompt: 'xxxx',  // 随机种子  seed: 'xxxx',  // 生成步数  steps: 7,  // 关键词相关性  cfg_scale: 20,  width: 1024,  height: 1024,  // 每次生成的张数  batch_size: 4,  // 生成批次  n_iter: 1,  // 采样办法  sampler_index: 'xxxx',  // 采纳的模型哈希值  sd_model_hash: 'xxxx',  override_settings: {    sd_model_checkpoint: sdModelCheckpoint,    eta_noise_seed_delta: 0.0,    CLIP_stop_at_last_layers: 1.0,  },})if (response.status === 200 && response.data) {  try {    const images = response.data.images;    if (images.length === 0) return;    data.imageUrls = images.map(item => `data:image/png;base64,${item}`);  } catch (err) {}}

生成成果就是本文 Banner 图中的粉色长头发的 3D 卡通格调小姐姐 正向关键字大抵是 girl, long hair, pink,模型采纳的是 3dAnimationDiffusion_v10,其余参数可自行调节。本文后续实例的图生图图优化都将采纳这张图作为参考图进行演示。

图生图

图生图接口stable-diffusion-webui 将依据咱们从接口传送的参考图,生成内容和格调相似的图片,就像最近抖音上很火的瞬息全宇宙特效一样,也能够将同一张图片通过抉择不同模型转化为另一种画风。上面是图生图接口的具体 payload 参数,能够察看到基本上和文生图是一样的,多了一些与参考图片相干的配置,如 init_images

{  "init_images": [    "string"  ],  "resize_mode": 0,  "denoising_strength": 0.75,  "image_cfg_scale": 0,  "mask": "string",  "mask_blur": 0,  "mask_blur_x": 4,  "mask_blur_y": 4,  "inpainting_fill": 0,  "inpaint_full_res": true,  "inpaint_full_res_padding": 0,  "inpainting_mask_invert": 0,  "initial_noise_multiplier": 0,  "prompt": "",  "styles": [    "string"  ],  "seed": -1,  "subseed": -1,  "subseed_strength": 0,  "seed_resize_from_h": -1,  "seed_resize_from_w": -1,  "sampler_name": "string",  "batch_size": 1,  "n_iter": 1,  "steps": 50,  "cfg_scale": 7,  "width": 512,  "height": 512,  "restore_faces": false,  "tiling": false,  "do_not_save_samples": false,  "do_not_save_grid": false,  "negative_prompt": "string",  "eta": 0,  "s_min_uncond": 0,  "s_churn": 0,  "s_tmax": 0,  "s_tmin": 0,  "s_noise": 1,  "override_settings": {},  "override_settings_restore_afterwards": true,  "script_args": [],  "sampler_index": "Euler",  "include_init_images": false,  "script_name": "string",  "send_images": true,  "save_images": false,  "alwayson_scripts": {}}

在页面接口逻辑中,咱们能够通过以下办法实现,其余参数和文生图都是一样的,咱们只须要把参考图以 base64 格局增加到 init_images 数组即可。

const response = await img2img({  // 正向关键词  prompt: prompt,  // 反向关键词  negative_prompt: negativePrompt,  // 初始图像  init_images: [sourceImage.value],  // 尺寸缩放  resize_mode: 0,  // ...});

咱们将文生图示例中的图片作为参考图,而后将大模型切换为 墨幽人造人_v1030,就能失去如下图所示的真人写实格调的图片。

部分重绘

图生图 API 还能够实现图片部分重绘、涂鸦、重绘蒙版、高清放大、图像裁减等成果。本文中,咱们简略解说以下如何实现部分重绘性能。

要实现部分重绘性能,首先咱们须要应用 Canvas 创立一个画布,而后通过鼠标挪动在画布上涂抹出须要重绘的门路,在理论开发时咱们能够实现一个如下图所示的图片重绘编辑器,右侧图片黄色区域 是通过画笔涂抹须要重绘批改的区域。涂抹性能能够通过以下代码简略实现,像擦除画笔大小色彩抉择撤销重做等扩大性能可自行搜寻如何实现。

<div>  <canvas id="canvas"></canvas>  <img src="your_image.jpg" id="image">  <button onclick="clearMask()">革除遮罩</button></div><script>var canvas = document.getElementById('canvas');var image = document.getElementById('image');// 设置canvas宽高与图像尺寸雷同canvas.width = image.width;canvas.height = image.height;var ctx = canvas.getContext('2d');var isDrawing = false; // 是否正在绘制var lastX = 0;var lastY = 0;// 鼠标按下事件处理程序canvas.addEventListener('mousedown', function(e) {  isDrawing = true;  [lastX, lastY] = [e.offsetX, e.offsetY];});// 鼠标挪动事件处理程序canvas.addEventListener('mousemove', function(e) {  if (!isDrawing) return;  drawMask(e.offsetX, e.offsetY);});// 鼠标开释事件处理程序canvas.addEventListener('mouseup', function() {  isDrawing = false;});// 绘制遮罩函数function drawMask(x, y) {  ctx.beginPath();  ctx.moveTo(lastX, lastY);  ctx.lineTo(x, y);  ctx.strokeStyle = 'rgba(0, 0, 0, 1)'; // 设置遮罩色彩(彩色)  ctx.lineWidth = 20;                   // 设置遮罩宽度  ctx.lineCap = 'round';                // 设置线条末端形态为圆形  ctx.stroke();  [lastX, lastY] = [x, y];}// 革除遮罩函数function clearMask() {  ctx.clearRect(0, 0, canvas.width, canvas.height);}</script>

涂抹实现后,咱们右键保留图片,能够失去如下图左侧所示的图片。然而 stable-diffusion-webui 须要的 Mask遮罩图是涂改区域为纯白色,非批改区域为彩色,且大小须要和原图统一,如右侧图片所示。此时就须要将失去的左侧通明遮罩层转换为右侧须要的遮罩层图片。

Canvas 遮罩层转换方法能够通过如下形式实现,绘制 Mask 图片,Canvas 应用鼠标绘制彩色图案,导出图片时须要把空白局部变为彩色,绘制线条的局部变为红色,并且须要转换成和原图雷同的尺寸。其中两个参数 _canvas 是须要转换的画布,_image 是涂抹的原图。其中用于获取图像原始尺寸的办法 getImageOriginSize 能够在本文开端办法汇总中查看

export const drawMask = async (_canvas, _image) => {  return new Promise(async(resolve) => {    const canvas = _canvas;    const ctx = canvas.getContext('2d');    const imageData = ctx.getImageData(0, 0, canvas.clientWidth, canvas.clientHeight);    const imageDataContent = imageData.data;    // 批改图像数据中的像素色彩    for (let i = 0; i < imageDataContent.length; i += 4) {      // 判断透明度是否小于阈值      if (imageDataContent[i + 3] < 128) {      // 将通明局部设置为彩色        imageDataContent[i] = 0;        imageDataContent[i + 1] = 0;        imageDataContent[i + 2] = 0;        imageDataContent[i + 3] = 255;      } else {        // 将线条局部设置为红色        imageDataContent[i] = 255;        imageDataContent[i + 1] = 255;        imageDataContent[i + 2] = 255;        imageDataContent[i + 3] = 255;      }    }    // 将批改后的图像数据导出为图片格式    const exportCanvas = document.createElement('canvas');    exportCanvas.width = canvas.clientWidth;    exportCanvas.height = canvas.clientHeight;    const exportCtx = exportCanvas.getContext('2d');    exportCtx.putImageData(imageData, 0, 0);    // mask放大到和原图统一    const size = await getImageOriginSize(_image);    const finalMask = await scaleImage(exportCanvas.toDataURL(), size.width, size.height);    resolve(finalMask);  });}

而后咱们将转换后的遮罩图以 base64 的模式作为 mask 参数增加到接口参数中,增加一些正向关键字等参数进行图生图接口申请,返回后果和上述 API 都是一样的,最终就能够失去上面所示的图像,能够察看到被涂抹区域的花朵隐没了

const response = await img2img({  init_images: [sourceImage.value],  mask: data.mask,  // ...});

本文实现中将用到十分多对于图像转换的办法,,比方PNG转Base64、URL转Base64、Canvas转Base64等,这些办法的具体实现将放在文章开端的汇总中。

前期解决

前期解决接口,能够实现图片高清放大、裁切、裁减等性能,有批量和单图调整两种接口,如下所示是单图调整接口。咱们先来看看单图优化 API 能够接管的参数有哪些:

{  "resize_mode": 0,  "show_extras_results": true,  "gfpgan_visibility": 0,  "codeformer_visibility": 0,  "codeformer_weight": 0,  "upscaling_resize": 2,  "upscaling_resize_w": 512,  "upscaling_resize_h": 512,  "upscaling_crop": true,  "upscaler_1": "None",  "upscaler_2": "None",  "extras_upscaler_2_visibility": 0,  "upscale_first": false,  "image": ""                       // 原图}

其余

更多接口

stable-diffusion-webui 还有许多实用的 API 能够调用,比方能够通过进度查问接口实时获取到生成图片的进度、剩余时间、排队状态等、能够通过配置查问接口获取到配置信息、已装置的模型列表等;反向推理接口能够通过已生成的图片反推出图像信息、形容关键字等。具体接口应用办法和参数都能够在 API 文档中查问。

实用办法

在做 Web 图片解决利用时须要用到很多图片相干的实用办法,以下是一些简略汇总。

① Canvas转Base64/PNG

要将 Canvas 转换为 Base64 格局图像数据,能够应用 CanvastoDataURL() 办法。该办法将返回一个蕴含图像数据的字符串,其中包含图像的类型,如 image/pngBase64 编码的图像数据。

// 获取 Canvas 元素var canvas = document.getElementById("myCanvas");var ctx = canvas.getContext("2d");// 将 Canvas 转换为 Base64 格局的图像数据var dataURL = canvas.toDataURL();
② 图片URL转Base64
export const convertUrlToBase64 = src => {  return new Promise(resolve => {    const img = new Image()    img.crossOrigin = ''    img.src = src    img.onload = function () {      const canvas = document.createElement('canvas');      canvas.width = img.width;      canvas.height = img.height;      const ctx = canvas.getContext('2d');      ctx.drawImage(img, 0, 0, img.width, img.height);      const ext = img.src.substring(img.src.lastIndexOf('.') + 1).toLowerCase();      const dataURL = canvas.toDataURL('image/' + ext);      resolve(dataURL);    }  });};
③ Base64转PNG
export const convertBase64ToImage = src => {  return new Promise((resolve) => {    const arr = src.split(',');    const byteString = atob(arr[1]);    const ab = new ArrayBuffer(byteString.length);    const ia = new Uint8Array(ab);    for (let i = 0; i < byteString.length; i++) {      ia[i] = byteString.charCodeAt(i);    }    const file = new File([ab], generateRandomId(), { type: 'image/png' });    resolve(file);  });}
④ 获取图像原始尺寸
export const getImageOriginSize = (src) => {  return new Promise((resolve) => {    const image = new Image();    image.src = src;    image.onload = () => {      resolve({        width: image.naturalWidth,        height: image.naturalHeight      });    };  });}
⑤ 等比缩放Base64
export const scaleImage = (src, width, height) => {  return new Promise((resolve) => {    const image = new Image();    image.src = src;    image.onload = () => {      const canvas = document.createElement('canvas');      canvas.width = width;      canvas.height = height;      const ctx = canvas.getContext('2d');      ctx.drawImage(image, 0, 0, width, height);      resolve(canvas.toDataURL());    };  })};

还有上述文章中提到的将通明黑白 Canvas 转化为 stable-diffusion-webui 部分重绘所需的黑底红色图案办法等。

总结

本文次要蕴含的知识点包含:

  • stable-diffusion-webui 的根本介绍
  • stable-diffusion-webui 装置及 API 环境配置
  • 文生图、图生图、部分重绘、前期解决等 API 接口调用
  • 图像处理开发中罕用到一些办法如 Base64PNGCanvasURL 互相转换、Canvas 色彩转换等
想理解其余前端常识或其余未在本文中详细描述的AI相干开发技术相干常识,可浏览我往期的文章。如果有疑难能够在评论中留言,如果感觉文章对你有帮忙,不要忘了一键三连哦

附录

  • [1]. Three.js 打造缤纷夏日3D梦中情岛
  • [2]. Three.js 实现炫酷的赛博朋克格调3D数字地球大屏
  • [3]. Three.js 实现2022冬奥主题3D趣味页面,含冰墩墩
  • [4]. Three.js 实现3D凋谢世界小游戏:阿狸的多元宇宙
  • [5]. Three.js 进阶之旅:全景漫游-高阶版在线看房
  • ...
  • 【Three.js 进阶之旅】系列专栏拜访
  • 【前端玩转AIGC】专栏拜访

参考

  • [1]. Stable Diffusion WebUI
  • [2]. stable-diffusion-webui github
  • [3]. stable diffusion 远端跑图—— Api基础知识把握
  • [4]. 哩布哩布AI