Node.jsからStable Diffusionを呼び出す!プログラムに画像生成を組み込もう!
- 2023.04.25
- AI関連 Node.js Stable Diffusion プログラム関連
- AI, nodejs, StableDiffusion
最も普及している、stable diffusion web UIをNode.jsから呼びだして画像生成する方法を解説します。
Stable Diffusionは、AUTOMATIC1111 WebUI と呼ばれているものを利用
AUTOMATIC1111 WebUIでAPI呼び出しを有効化する
Stable DiffusionのRest APIを有効化するには、起動時に --api
パラメータを追記します。
webui-user.bat
を開き COMMANDLINE_ARGS
を設定してから起動します。
@echo off
set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--api
call webui.bat
node-sd-webui の使い方
Node.jsから、Stable Diffusion を呼び出すのには、node-sd-webui
を使います。
GitHub – nerdenough/node-sd-webui: A Node.js client for Automatic1111’s Stable Diffusion WebUI
インストール
npm i -S node-sd-webui
node-sd-webui
を使って、Stable Diffusionの txt2image, img2img, pnginfo を実行していきます。
txt2imageの呼び出し
txt2img()
を使って、プロンプト文字列から画像を生成します。
- プロンプト: 青い髪の侍ガール
- ネガティブプロンプト: とりあえず、指の数が異なるものを排除
- 画像サイズ: 800 x 400
- シード: 5
- 生成画像数: 1
const sdwebui = require('node-sd-webui');
const fs = require('fs');
// StableDiffusionのURL
// ※末尾に "/" を付けない
const STABLE_DIFFUSION_URL = "http://127.0.0.1:7860";
async function main() {
const client = sdwebui.default({apiUrl: STABLE_DIFFUSION_URL});
try {
const response = await client.txt2img({
prompt: '1girl, solo, blue hair, samurai, looking at viwer',
negativePrompt: 'More than five fingers, less than five fingers',
samplingMethod: sdwebui.SamplingMethod.Euler_A,
width: 800,
height: 400,
steps: 20,
seed: 5, // シード値.-1でランダム
batchSize: 1, // 生成する画像数
});
const parameters = response.parameters;
console.log("parameters", parameters); // 各種生成パラメータ
const info = JSON.parse(response.info); // 生成時のシード情報など
console.log("info", info);
const images = response.images;
for (let i=0; i<images.length; ++i) {
const image = images[i]; // Base64で画像データ
const seed = info.all_seeds[i];
// image-<タイムスタンプ>-<seed>.png として画像保存
const filename = `./out/image-${info.job_timestamp}-${seed}.png`;
console.log("save: ", filename);
fs.writeFileSync(filename, image, 'base64');
}
} catch (err) {
console.error(err)
}
}
main();
要注意ポイント
response.info
は、Json形式のテキストなので、パースする- 生成画像のシード値は、
info.all_seeds[]
に入っている。 response.images
は、Base64でエンコードされた画像データ。ファイルに保存するなら、fs.writeFileSync()
にbase64
を指定する。
生成された画像がこちら
水の斬撃エフェクトのある、侍っぽい気配のある美少女が生成できました。
img2imgの呼び出し
img2img()
を使って、画像から画像を生成します。
- 元画像: 読み込んだ画像データをBase64エンコードして、
imageData
パラメータに配列で渡す - プロンプト: 1匹のトイプードル
- 画像サイズ: 768 x 1100
- シード: 5
- 生成画像数: 1
const sdwebui = require('node-sd-webui');
const fs = require('fs');
// StableDiffusionのURL
// ※末尾に "/" を付けない
const STABLE_DIFFUSION_URL = "http://127.0.0.1:7860";
async function main() {
const client = sdwebui.default({apiUrl: STABLE_DIFFUSION_URL});
try {
// 入力画像を読み込んで Base64エンコードに変換
const imageData = fs.readFileSync("./sample_data/my_dog.jpg");
const imageBase64 = Buffer.from(imageData).toString('base64');
const response = await client.img2img({
imageData: [imageBase64],
prompt: '1dog, toy-poodle, looking at viwer',
negativePrompt: 'More than five fingers, less than five fingers',
samplingMethod: sdwebui.SamplingMethod.Euler_A,
width: 768,
height: 1100,
steps: 20,
seed: 5, // シード値.-1でランダム
batchSize: 1, // 生成する画像数
});
console.log("response", response);
const parameters = response.parameters;
console.log("parameters", parameters); // 各種生成パラメータ
const info = JSON.parse(response.info); // 生成時のシード情報など
console.log("info", info);
const images = response.images;
for (let i=0; i<images.length; ++i) {
const image = images[i]; // Base64で画像データ
const seed = info.all_seeds[i];
// image-<タイムスタンプ>-<seed>.png として画像保存
const filename = `./out/image-${info.job_timestamp}-${seed}.png`;
console.log("save: ", filename);
fs.writeFileSync(filename, image, 'base64');
}
} catch (err) {
console.error(err)
}
}
main();
入力パラメータに imageData
が増える以外は txt2img とほぼ同じです。
生成結果
出力画像
色味や、構図が似た感じのトイプードルのイラストができました。
美少女イラストが得意なモデルを使ったので、女の子っぽい雰囲気に仕上がってます。
pnginfoの呼び出し
pnginfo()
を使って、pngファイルから生成時の情報を取得できます。
ここでは、先程生成した侍ガールを入力しています。
const sdwebui = require('node-sd-webui');
const fs = require('fs');
// StableDiffusionのURL
// ※末尾に "/" を付けない
const STABLE_DIFFUSION_URL = "http://127.0.0.1:7860";
async function main() {
const client = sdwebui.default({apiUrl: STABLE_DIFFUSION_URL});
try {
// 入力画像を読み込んで Base64エンコードに変換
const imageData = fs.readFileSync("./out/image-20230421000100-5.png");
const imageBase64 = Buffer.from(imageData).toString('base64');
const response = await client.pngInfo({
imageData: imageBase64,
});
console.log("response", response);
} catch (err) {
console.error(err)
}
}
main();
出力結果
response {
prompt: '1girl, solo, blue hair, samurai, looking at viwer',
steps: 20,
samplingMethod: 'Euler a',
cfgScale: 7,
seed: 5,
width: 800,
height: 400,
modelHash: '2202fecad7',
model: 'TriPhaze_C',
negativePrompt: 'More than five fingers, less than five fingers'
}
使ったモデルから、各種パラメータまで取得できました。
node-sd-webui でサポートされない機能の呼び出し
他の機能も Rest API を参考に直接呼び出せます。
APIリファレンスの確認方法
まず Stable Diffusion WebUI の下の方から api
というリンクをクリックします。
すると、このようなリファレンスが確認できます。
デフォルトの設定の人は http://127.0.0.1:7860/docs からAPIのリファレンスが見られます。
taggerでタグやレーティング判定
Stable Diffusion WebUI拡張の1つ、taggerを呼び出して画像に写っている要素のタグや、レーティングを取得してみましょう。
GitHub – toriato/stable-diffusion-webui-wd14-tagger: Labeling extension for Automatic1111’s Web UI
tagger APIリファレンス/tagger/v1/interrogate
にパラメータは3つ付けて POST すれば良いことがわかります。
- Base64形式の
image
- 解析用の
model
- タグ判定する閾値
threshold
tagger APIのレスポンス
レスポンスは、 caption
要素に タグ名: 重み
形式で取得できます。
サンプルでは、http通信のために axios
というnpmパッケージを利用しています。
axios – npm
これを使うと、async / await で待ち合わせする形でhttp通信が簡単にできます。
その前に axios
をインストールしておきましょう
npm install axios
tagger APIへアクセスするコード
const axios = require('axios');
const fs = require('fs');
// StableDiffusionのURL
// ※末尾に "/" を付けない
const STABLE_DIFFUSION_URL = "http://127.0.0.1:7860";
async function main() {
try {
// 入力画像を読み込んで Base64エンコードに変換
const imageData = fs.readFileSync("./out/image-20230421000100-5.png");
const imageBase64 = Buffer.from(imageData).toString('base64');
const data = {
image: imageBase64,
model: "wd14-vit-v2",
threshold: 0.35, // [0-1]
};
const url = STABLE_DIFFUSION_URL + "/tagger/v1/interrogate";
const response = await axios.post(url, data);
// captionのうち、"general", "sensitive", "questionable", "explicit"がレーティング判定
// その他は画像に含まれるタグ
const caption = response.data.caption;
console.log(caption);
} catch (err) {
console.error(err)
}
}
main();
こちらも先程のsamuraiガールを入力しています。
実行すると次のような結果が取得できました。
{
general: 0.4399340748786926,
sensitive: 0.527866780757904,
questionable: 0.001455068588256836,
explicit: 0.00033295154571533203,
'1girl': 0.9881388545036316,
solo: 0.9644424915313721,
blue_hair: 0.9189961552619934,
looking_at_viewer: 0.8000155687332153,
ponytail: 0.7931246161460876,
brown_eyes: 0.6853416562080383,
grey_background: 0.6733701229095459,
long_hair: 0.6240038871765137,
hair_ornament: 0.6151501536369324,
closed_mouth: 0.5795429348945618,
bangs: 0.562977135181427,
weapon: 0.5414935946464539,
sword: 0.5020155310630798,
makeup: 0.4913225769996643,
upper_body: 0.48966968059539795,
portrait: 0.4799497127532959,
hair_between_eyes: 0.4498511552810669,
orange_eyes: 0.40047234296798706
}
レーティングは general
, sensitive
, questionable
, explicit
のパラメータを見て評価できます。general
< sensitive
< questionable
< explicit
の順に画像の内容が過激になっていきます。
- sensitive 52%なので、センシティブな画像の可能性あり
タグ判定は、レーティング関連のタグ以外で評価されます。
今回はsamuraiとは判定されなかったけど、ponytailなどの特徴は拾えています。
今後の応用
今回の内容で、Node.jsからStable Diffusionで画像生成できるようになりました。
単体で画像生成するツールだけでなく、他のサービスと組み合わせるといろんなことができるようになります。
例えば、次のようなことが考えられます。
- slackのchatbotから画像生成して返答
- GPT4が書いたストーリーから、挿絵のpromptを作成して、Stable Diffusionで画像生成
- 画像投稿サイトから画像を大量取得して、taggerでエッチな画像だけ保存する
Stable Diffusionで大量生産した画像を taggerの結果で分類すれば良い画像を判定とかできるかも!?
-
前の記事
ゲームデザイナーにも知っておいて欲しい!ChatGPTの基本とキーポイント 2023.04.02
-
次の記事
AIで短編小説作ってみた!プロンプト付き 2023.05.13