AI繪圖開源工具Stable Diffusion WebUI前端API對接

背景
本文主要介紹 AI 繪圖開源工具 Stable Diffusion WebUI 的 API 開啟和基本調(diào)用方法,通過本文的閱讀,你將了解到 stable-diffusion-webui 的基本介紹、安裝及 API 環(huán)境配置;文生圖、圖生圖、局部重繪、后期處理等 API 接口調(diào)用;圖像處理開發(fā)中常用到一些方法如 Base64、PNG、Canvas及 URL 相互轉(zhuǎn)換、Canvas 顏色轉(zhuǎn)換等。
AI 繪圖工具目前市面上比較廣泛使用的主要有兩款,一個(gè)是 Midjourney,它提供面向用戶有好的操作界面,文生圖、圖生圖等功能非常強(qiáng)大,但是它是一款收費(fèi)軟件;另一個(gè)就是開源工具 Stable Diffusion, 同樣具有強(qiáng)大的AI繪圖和圖片再創(chuàng)造能力,但是學(xué)習(xí)成本和上手難度相對較大,不過由于它是開源的,現(xiàn)在有非常多的用戶和開發(fā)者,我們可以找到豐富的訓(xùn)練模型和學(xué)習(xí)資源。本文介紹的 Stable Diffusion WebUI 就是基于 Stable Diffusion 的具有比較完善的可視化操作界面的 AI 繪圖開源工具,它的 github 訪問地址是 https://github.com/AUTOMATIC1111/stable-diffusion-webui。
順便一提,本文上方的
Banner圖就是使用Stable Diffusion生成的??
使用體驗(yàn)
在正式開發(fā)之前,我們可以先體驗(yàn)一下 Stable Diffusion WebUI 以及兩個(gè)接口封裝和操作界面比較優(yōu)秀的 AI 繪圖網(wǎng)站,了解文生圖、圖生圖、后期處理等基本操作步驟。

環(huán)境配置
安裝 Stable Diffusion WebUI
我們首先需要先在本地或者服務(wù)器安裝部署 Stable Diffusion WebUI,可以從Github克隆倉庫,然后按說明文檔進(jìn)行安裝,對前端開發(fā)來說安裝流程非常簡單,詳細(xì)安裝流程大家可以自行搜索,現(xiàn)在網(wǎng)上已經(jīng)有很多保姆級的教程,本文不再贅述。

安裝完成后,在 Windows操作系統(tǒng)中進(jìn)入 stable-diffusion-webui 根目錄,然后雙擊 webui-user.bat 文件即可開啟本地運(yùn)行服務(wù),在瀏覽器中輸入 http://localhost:7860 加載如下所示的界面。在 txt2img 輸入框中輸入需要生圖圖像的的正向關(guān)鍵詞和反向關(guān)鍵詞,點(diǎn)擊 Generate 按鈕即可生成圖像。

完成基本安裝后,還可以安裝界面漢化插件、關(guān)鍵字中文翻譯插件、自己喜歡的風(fēng)格模型等,都可以按照教程非常容易實(shí)現(xiàn)。
開啟 API 功能
在 stable-diffusion-webui 根目錄下找到文件 webui-user.bat,使用編輯器打開這個(gè)文件,然后在 COMMANDLINE_ARGS 配置項(xiàng)后面添加 --api。
set COMMANDLINE_ARGS= --lowvram --precision full --api --listen
然后雙擊 webui-user.bat 重啟服務(wù),此時(shí)在瀏覽器中輸入地址 https://localhost:7860/doc,就能看到如下所示的所有接口文檔了,我們可以從文檔中找到需要接入的接口及詳細(xì)參數(shù)。

??我們還可以配置如上所示的 --listen 參數(shù),這樣就可以通過局域網(wǎng)訪問 stable-diffusion-webui 的接口了。
實(shí)現(xiàn)
文生圖
文生圖接口,可以通過向 stable-diffusion-webui 服務(wù)發(fā)送正向關(guān)鍵字、反向關(guān)鍵字、圖片尺寸、采樣步數(shù)等參數(shù)來調(diào)用AI能力生成圖片。我們先來看看它有哪些可配置的 payload 參數(shù)選項(xiàng)。(暫時(shí)只用到后面寫了注釋的參數(shù),基本上可以滿足大部分文生圖參數(shù)配置)

{
"enable_hr": false, // 開啟高清hr
"denoising_strength": 0, // 降噪強(qiáng)度
"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": "", // 正向關(guān)鍵字
"styles": [
"string"
],
"seed": -1, // 隨機(jī)種子
"subseed": -1, // 子級種子
"subseed_strength": 0, // 子級種子影響力度
"seed_resize_from_h": -1,
"seed_resize_from_w": -1,
"sampler_name": "string",
"batch_size": 1, // 每次生成的張數(shù)
"n_iter": 1, // 生成批次
"steps": 50, // 生成步數(shù)
"cfg_scale": 7, // 關(guān)鍵詞相關(guān)性
"width": 512, // 生成圖像寬度
"height": 512, // 生成圖像高度
"restore_faces": false, // 面部修復(fù)
"tiling": false, // 平鋪
"do_not_save_samples": false,
"do_not_save_grid": false,
"negative_prompt": "string", // 反向關(guān)鍵字
"eta": 0, // 等待時(shí)間
"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 模型參數(shù)配置
"sampler_index": "Euler", // 采樣方法
"script_name": "string",
"send_images": true, // 是否發(fā)送圖像
"save_images": false, // 是否在服務(wù)端保存生成的圖像
"alwayson_scripts": {} // alwayson配置
}
根據(jù)需要的參數(shù),在頁面邏輯中,我們可以像下面這樣實(shí)現(xiàn),此時(shí)服務(wù)端會(huì)根據(jù)接口參數(shù),一次生成4張對應(yīng)的圖。接口返回成功之后,我們會(huì)接收到一個(gè)包含所有圖片數(shù)據(jù)名為 images 的數(shù)組,數(shù)組項(xiàng)是格式為 base64 的圖片,我們可以向下面這樣轉(zhuǎn)化為頁面上可直接顯示的圖片。
const response = await txt2img({
id_task: `task(${taskId})`,
// 正向關(guān)鍵詞
prompt: 'xxxx',
// 反向關(guān)鍵詞
negative_prompt: 'xxxx',
// 隨機(jī)種子
seed: 'xxxx',
// 生成步數(shù)
steps: 7,
// 關(guān)鍵詞相關(guān)性
cfg_scale: 20,
width: 1024,
height: 1024,
// 每次生成的張數(shù)
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 圖中的粉色長頭發(fā)的 3D 卡通風(fēng)格小姐姐 ? ,正向關(guān)鍵字大致是 girl, long hair, pink,模型采用的是 3dAnimationDiffusion_v10,其他參數(shù)可自行調(diào)節(jié)。本文后續(xù)實(shí)例的圖生圖、圖優(yōu)化都將采用這張圖作為參考圖進(jìn)行演示。

圖生圖
圖生圖接口,stable-diffusion-webui 將根據(jù)我們從接口傳送的參考圖,生成內(nèi)容和風(fēng)格類似的圖片,就像最近抖音上很火的瞬息全宇宙特效一樣,也可以將同一張圖片通過選擇不同模型轉(zhuǎn)化為另一種畫風(fēng)。下面是圖生圖接口的詳細(xì) payload 參數(shù),可以觀察到基本上和文生圖是一樣的,多了一些與參考圖片相關(guān)的配置,如 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": {}
}
在頁面接口邏輯中,我們可以通過以下方法實(shí)現(xiàn),其他參數(shù)和文生圖都是一樣的,我們只需要把參考圖以 base64 格式添加到 init_images 數(shù)組即可。
const response = await img2img({
// 正向關(guān)鍵詞
prompt: prompt,
// 反向關(guān)鍵詞
negative_prompt: negativePrompt,
// 初始圖像
init_images: [sourceImage.value],
// 尺寸縮放
resize_mode: 0,
// ...
});
我們將文生圖示例中的圖片作為參考圖,然后將大模型切換為 墨幽人造人_v1030,就能得到如下圖所示的真人寫實(shí)風(fēng)格的圖片。

局部重繪
圖生圖 API 還可以實(shí)現(xiàn)圖片局部重繪、涂鴉、重繪蒙版、高清放大、圖像擴(kuò)充等效果。本文中,我們簡單講解以下如何實(shí)現(xiàn)局部重繪功能。
要實(shí)現(xiàn)局部重繪功能,首先我們需要使用 Canvas 創(chuàng)建一個(gè)畫布,然后通過鼠標(biāo)移動(dòng)在畫布上涂抹出需要重繪的路徑,在實(shí)際開發(fā)時(shí)我們可以實(shí)現(xiàn)一個(gè)如下圖所示的圖片重繪編輯器,右側(cè)圖片黃色區(qū)域 ?? 是經(jīng)過畫筆涂抹需要重繪修改的區(qū)域。涂抹功能可以通過以下代碼簡單實(shí)現(xiàn),像擦除、畫筆大小顏色選擇、撤銷重做等擴(kuò)展功能可自行搜索如何實(shí)現(xiàn)。

<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');
// 設(shè)置canvas寬高與圖像尺寸相同
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext('2d');
var isDrawing = false; // 是否正在繪制
var lastX = 0;
var lastY = 0;
// 鼠標(biāo)按下事件處理程序
canvas.addEventListener('mousedown', function(e) {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
});
// 鼠標(biāo)移動(dòng)事件處理程序
canvas.addEventListener('mousemove', function(e) {
if (!isDrawing) return;
drawMask(e.offsetX, e.offsetY);
});
// 鼠標(biāo)釋放事件處理程序
canvas.addEventListener('mouseup', function() {
isDrawing = false;
});
// 繪制遮罩函數(shù)
function drawMask(x, y) {
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.strokeStyle = 'rgba(0, 0, 0, 1)'; // 設(shè)置遮罩顏色(黑色)
ctx.lineWidth = 20; // 設(shè)置遮罩寬度
ctx.lineCap = 'round'; // 設(shè)置線條末端形狀為圓形
ctx.stroke();
[lastX, lastY] = [x, y];
}
// 清除遮罩函數(shù)
function clearMask() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
</script>
涂抹完成后,我們右鍵保存圖片,可以得到如下圖左側(cè)所示的圖片。但是 stable-diffusion-webui 需要的 Mask遮罩圖是涂改區(qū)域?yàn)榧儼咨切薷膮^(qū)域?yàn)楹谏掖笮⌒枰驮瓐D一致,如右側(cè)圖片所示。此時(shí)就需要將得到的左側(cè)透明遮罩層轉(zhuǎn)換為右側(cè)需要的遮罩層圖片。

Canvas 遮罩層轉(zhuǎn)換方法可以通過如下方式實(shí)現(xiàn),繪制 Mask 圖片,Canvas 使用鼠標(biāo)繪制黑色圖案,導(dǎo)出圖片時(shí)需要把空白部分變?yōu)楹谏L制線條的部分變?yōu)榘咨⑶倚枰D(zhuǎn)換成和原圖相同的尺寸。其中兩個(gè)參數(shù) _canvas 是需要轉(zhuǎn)換的畫布,_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;
// 修改圖像數(shù)據(jù)中的像素顏色
for (let i = 0; i < imageDataContent.length; i += 4) {
// 判斷透明度是否小于閾值
if (imageDataContent[i + 3] < 128) {
// 將透明部分設(shè)置為黑色
imageDataContent[i] = 0;
imageDataContent[i + 1] = 0;
imageDataContent[i + 2] = 0;
imageDataContent[i + 3] = 255;
} else {
// 將線條部分設(shè)置為白色
imageDataContent[i] = 255;
imageDataContent[i + 1] = 255;
imageDataContent[i + 2] = 255;
imageDataContent[i + 3] = 255;
}
}
// 將修改后的圖像數(shù)據(jù)導(dǎo)出為圖片格式
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);
});
}
然后我們將轉(zhuǎn)換后的遮罩圖以 base64 的形式作為 mask 參數(shù)添加到接口參數(shù)中,添加一些正向關(guān)鍵字等參數(shù)進(jìn)行圖生圖接口請求,返回結(jié)果和上述 API 都是一樣的,最終就可以得到下面所示的圖像,可以觀察到被涂抹區(qū)域的花朵消失了 ??。
const response = await img2img({
init_images: [sourceImage.value],
mask: data.mask,
// ...
});

??本文實(shí)現(xiàn)中將用到非常多關(guān)于圖像轉(zhuǎn)換的方法,,比如PNG轉(zhuǎn)Base64、URL轉(zhuǎn)Base64、Canvas轉(zhuǎn)Base64等,這些方法的具體實(shí)現(xiàn)將放在文章末尾的匯總中。
后期處理
后期處理接口,可以實(shí)現(xiàn)圖片高清放大、裁切、擴(kuò)充等功能,有批量和單圖調(diào)整兩種接口,如下所示是單圖調(diào)整接口。我們先來看看單圖優(yōu)化 API 可以接收的參數(shù)有哪些:

{
"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 還有許多實(shí)用的 API 可以調(diào)用,比如可以通過進(jìn)度查詢接口實(shí)時(shí)獲取到生成圖片的進(jìn)度、剩余時(shí)間、排隊(duì)狀態(tài)等、可以通過配置查詢接口獲取到配置信息、已安裝的模型列表等;反向推理接口可以通過已生成的圖片反推出圖像信息、描述關(guān)鍵字等。具體接口使用方法和參數(shù)都可以在 API 文檔中查詢。

實(shí)用方法
在做 Web 圖片處理應(yīng)用時(shí)需要用到很多圖片相關(guān)的實(shí)用方法,以下是一些簡單匯總。
① Canvas轉(zhuǎn)Base64/PNG
要將 Canvas 轉(zhuǎn)換為 Base64 格式圖像數(shù)據(jù),可以使用 Canvas 的 toDataURL() 方法。該方法將返回一個(gè)包含圖像數(shù)據(jù)的字符串,其中包括圖像的類型,如 image/png 和 Base64 編碼的圖像數(shù)據(jù)。
// 獲取 Canvas 元素
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// 將 Canvas 轉(zhuǎn)換為 Base64 格式的圖像數(shù)據(jù)
var dataURL = canvas.toDataURL();
② 圖片URL轉(zhuǎn)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轉(zhuǎn)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 轉(zhuǎn)化為 stable-diffusion-webui 局部重繪所需的黑底白色圖案方法等。
總結(jié)
本文主要包含的知識點(diǎn)包括:
stable-diffusion-webui的基本介紹stable-diffusion-webui安裝及API環(huán)境配置- 文生圖、圖生圖、局部重繪、后期處理等
API接口調(diào)用 - 圖像處理開發(fā)中常用到一些方法如
Base64、PNG、Canvas及URL相互轉(zhuǎn)換、Canvas顏色轉(zhuǎn)換等
想了解其他前端知識或其他未在本文中詳細(xì)描述的AI相關(guān)開發(fā)技術(shù)相關(guān)知識,可閱讀我往期的文章。如果有疑問可以在評論中留言,如果覺得文章對你有幫助,不要忘了一鍵三連哦 ??。
附錄
- [1]. ?? Three.js 打造繽紛夏日3D夢中情島
- [2]. ?? Three.js 實(shí)現(xiàn)炫酷的賽博朋克風(fēng)格3D數(shù)字地球大屏
- [3]. ?? Three.js 實(shí)現(xiàn)2022冬奧主題3D趣味頁面,含冰墩墩
- [4]. ?? Three.js 實(shí)現(xiàn)3D開放世界小游戲:阿貍的多元宇宙
- [5]. ?? Three.js 進(jìn)階之旅:全景漫游-高階版在線看房
...- 【Three.js 進(jìn)階之旅】系列專欄訪問 ??
- 【前端玩轉(zhuǎn)AIGC】專欄訪問 ??
參考
- [1]. Stable Diffusion WebUI
- [2]. stable-diffusion-webui github
- [3]. stable diffusion 遠(yuǎn)端跑圖—— Api基礎(chǔ)知識掌握
- [4]. 哩布哩布AI
本文作者:dragonir 本文地址:http://www.rzrgm.cn/dragonir/p/17668699.html

浙公網(wǎng)安備 33010602011771號