Stable Diffusion使用WEB UI虽然可以通过交互界面生成图像,但是,如果遇到批量处理以及自动化处理图像的情形,使用交互界面的模式就不适用了。
这里,主要讨论如何使用API的方式自动调用ControlNet插件,并实现Stable Diffusion自动出图。
首先,确保Stable Diffusion和ControlNet已经安装好,并且其在WEB UI状态下可以正常出图。打开命令行工具,在sd文件夹下输入.\webui.bat --medvram --xformers --nowebui,以无界面方式运行sd。
然后,打开PyCharm新建一个项目,在项目根目录下新建一个名newAPIControlNet.py的文件。该脚本的主要方法是get Image2Image,通过这个方法来完成图生图操作。
下面我们来解析一下这个脚本,首先将导入需要的库类和方法,图片裁切和图片格式转换方法,以及英文翻译方法,可自行编写,这里就不做赘述了。
然后,定义四个在图生图转换过程中会用到的方法,分别是encode_pil_to_base64()方法,用于将图片转换成64位的编码,方便SD读取;submit_post()方法,用于向SD提请API请求;save_encoded_image()方法,用于保存图片;joinLoraList()方法,用于控制lora列表。
接下来,让我们解析getImage2Image()这个方法,第一步,预处理原始图片,先定义原始图片的地址以及裁切后图片的地址和保存png图片的地址,再将原始图片进行编辑并保存为64位的编码;第二步,将数据带入API进行运算,这里着重要讲ControlNet的数据格式。controlnet的数据被放在alwayson_scripts条目下,可以同时支持三个controlnet的模型,这里使用了openpose,tile和inpaint三个模型,同时每个模型都指定了权重,并且它们的目标图像与图生图原始图像保持一致。最后一步,发起API请求后,保存图片到指定的地址。
下面我们将相关提示词和lora补全,这里使用了一个泰国衣服风格的lora。开始进行图片生成,等待后台运算,打开原始图片,检查生成后的图片,可以看到生成的图片保持了原图片的姿势,衣服在原有的基础上做了风格上的调整。如果要输出更多变化的结果,可以调低tile和inpaint的权重。
调高权重后,我们再次输出试试,可以看到衣服变化的幅度加大了,是不是很神奇?
这就是使用API调用controlnet的方法,你学会了吗?
相关代码newAPIControlNet.py的内容:
from imageCrop import cropImage2Video
from pythonJpgToPng import image2png
from translateFromCh2EnYoudao import translateYouDao
from PIL import Image
import io
import os
import json
import base64
import random
import requests
def encode_pil_to_base64(image):
with io.BytesIO() as output_bytes:
image.save(output_bytes, format="png")
bytes_data = output_bytes.getvalue()
return base64.b64encode(bytes_data).decode("utf-8")
def submit_post(url: str, data: dict):
return requests.post(url, data=json.dumps(data))
def save_encoded_image(b64_image: str, output_path: str):
with open(output_path, "wb") as image_file:
image_file.write(base64.b64decode(b64_image))
def joinLoraList(loraName01,weight01,loraName02,weight02,loraName03,weight03):
if loraName01 == "" :
loraPart01 = ""
else:
loraPart01 = "<lora:%s:%2.1f>"%(loraName01,weight01)
if loraName02 == "":
loraPart02 = ""
else:
loraPart02 = "<lora:%s:%2.1f>"%(loraName02,weight02)
if loraName03 == "":
loraPart03 = ""
else:
loraPart03 = "<lora:%s:%2.1f>"%(loraName03,weight03)
loraList = loraPart01 + loraPart02 + loraPart03
print(loraList)
return loraList
def getImage2Image(text_prompt,loraList,denoisingStrength,localPythonExePath,gifImageNum,seed,tileweight,inpaintweight):
localFilePath = "D:\SDM\sendReq2DB\Frames\%d.jpg"%gifImageNum #原始图片地址
localCroppedFilePath = localPythonExePath + "\image\i2i\croppedimage\croppedpromptimage.jpg"
cropImage2Video(localFilePath,localCroppedFilePath) #对图片进行尺寸转换,如果图片尺寸已经裁切好,可省略此步骤
promptImageFilePath = localPythonExePath + "\image\i2i\croppedimage"
image2png(promptImageFilePath,"png") #将裁剪后的jpg图片保存为png格式,如果原始图片就是png,可省略此步骤
promptimage_temp = Image.open(localPythonExePath + "\prompt_image\croppedpromptimage.png")
promptimage_temp_code = encode_pil_to_base64(promptimage_temp) #调用save_encoded_image方法,将图片转换成64位编码
os.remove("%s\prompt_image\croppedpromptimage.png"%localPythonExePath) # 将转换到本地的png文件删除
image2Image_url = 'http://127.0.0.1:7861/sdapi/v1/img2img'
data = {
"init_images": [promptimage_temp_code],
# "mask":mask_temp_code,
"prompt": text_prompt+loraList,
'brach_size': 1,
# "sampler_name":"DPM++ 2m Karras",
"steps": 20,
"denoising_strength": denoisingStrength,
"cfg_scale": 7,
"width": 512,
"height": 910,
"seed": seed,
"restore_faces": "true",
"negative_prompt": "nsfw,blurry,bad anatomy,low quality,worst quality,normal quality",
"alwayson_scripts": {
"ControlNet": {
"args": [{
"enabled": "true",
"pixel_perfect": "true",
"module": "none",
"model": "control_v11p_sd15_openpose",
"weight": 1,
"image": promptimage_temp_code
},{
"enabled": "true",
"pixel_perfect": "true",
"module": "none",
"model": "control_v11f1e_sd15_tile",
"weight": tileweight,
"image": promptimage_temp_code
},{
"enabled": "true",
"pixel_perfect": "true",
"module": "none",
"model": "control_v11p_sd15_inpaint",
"weight": inpaintweight,
"image": promptimage_temp_code
}]
}
}
}
response = submit_post(image2Image_url, data)
save_encoded_image(response.json()['images'][0], 'FramesNew\%d.png'%(gifImageNum)) #保存生成的图片到指定地址
print("图片已经生成,并保存在image目录中")
if __name__ == '__main__':
text_prompt = "美女,黑色腰带,短裙子,mahalaiuniform,站立姿势,正常手部" # mahalaiuniform-000001泰国风格
text_prompt = translateYouDao(text_prompt) #将提示词翻译成英文
loraList = joinLoraList("mahalaiuniform-000001", 1.0, '', 1.0, '', 1.0)
denoisingStrength = 0.8 #重绘强度
seed = random.randint(1, 10000000)
localPythonExePath = "D:\SDM\sendReq2DB"
gifImageNum = 0
getImage2Image(text_prompt, loraList, denoisingStrength, localPythonExePath, gifImageNum, seed,0.1,0.1)