V 2.2.7 lama iopaint 去水印

This commit is contained in:
2024-06-06 13:12:04 +08:00
parent 8b011856c2
commit f27ec08724
39 changed files with 2495 additions and 547 deletions
+288 -1
View File
@@ -1,6 +1,16 @@
import { errorMessage, successMessage } from "../generalTools";
import path from "path";
import path, { resolve } from "path";
import { Tools } from "../tools";
import fs from "fs";
import { ImageSetting } from "../../define/setting/imageSetting";
import { isEmpty, reject } from "lodash";
import { basicApi } from "../../api/apiBasic";
import sharp from 'sharp';
import { file, image } from "../../define/Tools";
import { define } from "../../define/define";
import { spawn } from 'child_process'
import { LOGGER_DEFINE } from "../../define/logger_define";
import { DEFINE_STRING } from "../../define/define_string";
export class Image {
constructor(global) {
@@ -45,4 +55,281 @@ export class Image {
return errorMessage(error.message);
}
}
/**
* 将base64转换为文件
* @param {*} value
* @returns
*/
async Base64ToFile(value) {
try {
value = JSON.parse(value);
let base64 = value[0];
let out_file_str = value[1];
let base64Data = base64.replace(/^data:image\/\w+;base64,/, "");
let dataBuffer = Buffer.from(base64Data, 'base64');
let out_file = path.join(this.global.config.project_path, out_file_str);
let out_folder = path.dirname(out_file);
await this.tools.checkFolderExistsOrCreate(out_folder);
await fs.promises.writeFile(out_file, dataBuffer);
// await this.tools.writeArrayToFile(dataBuffer, out_file);
return successMessage(out_file, "base64保存到本地图片成功");
} catch (error) {
return errorMessage("base64保存到本地图片失败,失败原因如下:" + error.message);
}
}
/**
* 图片处理,去除水印
* @param {*} value
* @returns
*/
async ProcessImage(value) {
return new Promise(async (resolve, reject) => {
try {
value = JSON.parse(value);
value.out_file = value.out_file ? value.out_file : `data/mask/temp/${new Date().getTime()}.png`;
// 判断当前使用的是什么
let mask_setting = (await ImageSetting.GetDefineConfigJsonByProperty(JSON.stringify(["img_base", "mask_setting", false, {}]))).data;
let isRemote = mask_setting.isRemote ? mask_setting.isRemote : false;
let urls = mask_setting.localUrl ? mask_setting.localUrl + "api/v1/inpaint" : "";
if (isRemote && isEmpty(urls)) {
throw new Error("使用iopaint图片处理,但是没有配置图片处理地址");
}
if (!isRemote && isEmpty(value.out_file)) {
throw new Error("水印处理,使用软件直接处理类型为file,需要指定输出的文件地址");
}
let out_file;
if (!isEmpty(value.out_file)) {
out_file = path.join(this.global.config.project_path, value.out_file);
let out_folder = path.dirname(out_file);
await this.tools.checkFolderExistsOrCreate(out_folder);
}
let res;
if (isRemote) {
let headers = {
"accept": '*/*',
'accept-language': 'zh-CN,zh;q=0.9',
'content-type': 'application/json'
}
let data = {
"image": value.image,
"mask": value.mask,
"ldm_steps": 30,
"ldm_sampler": "ddim",
"zits_wireframe": true,
"cv2_flag": "INPAINT_NS",
"cv2_radius": 5,
"hd_strategy": "Crop",
"hd_strategy_crop_triger_size": 640,
"hd_strategy_crop_margin": 128,
"hd_trategy_resize_imit": 2048 * 5,
"prompt": "",
"negative_prompt": "out of frame, lowres, error, cropped, worst quality, low quality, jpeg artifacts, ugly, duplicate, morbid, mutilated, out of frame, mutation, deformed, blurry, dehydrated, bad anatomy, bad proportions, extra limbs, disfigured, gross proportions, malformed limbs, watermark, signature",
"use_croper": false,
"croper_x": 284,
"croper_y": 284,
"croper_height": 512,
"croper_width": 512,
"use_extender": false,
"extender_x": 0,
"extender_y": 0,
"extender_height": 1080,
"extender_width": 1080,
"sd_mask_blur": 12,
"sd_strength": 1,
"sd_steps": 50,
"sd_guidance_scale": 7.5,
"sd_sampler": "DPM++ 2M",
"sd_seed": -1,
"sd_match_histograms": false,
"sd_lcm_lora": false,
"paint_by_example_example_image": null,
"p2p_image_guidance_scale": 1.5,
"enable_controlnet": false,
"controlnet_conditioning_scale": 0.4,
"controlnet_method": "",
"enable_brushnet": false,
"brushnet_method": "random_mask",
"brushnet_conditioning_scale": 1,
"enable_powerpaint_v2": false,
"powerpaint_task": "text-guided"
};
res = await basicApi.post(urls, data, headers);
this.global.logger.info(LOGGER_DEFINE.REMOVE_WATERMARK, `iopaint去除水印请求成功`);
if (value.type == 'arrayBuffer') {
resolve(successMessage(res.data, "图片处理成功", LOGGER_DEFINE.REMOVE_WATERMARK));
} else if (value.type == "file") {
let buffer = Buffer.from(res.data);
await fs.promises.writeFile(out_file, buffer)
resolve(successMessage(out_file, "图片处理成功", LOGGER_DEFINE.REMOVE_WATERMARK));
}
} else {
let lama_script = path.resolve(define.scripts_path, `lama/lama_inpaint.exe`);
// 就是判断指定的文件和文件夹是不是存在
let has_exe = await file.CheckFileOrDirExist(lama_script);
if (!has_exe) {
throw new Error("图片水印处理组件不存在,请看教程自行下载");
}
let has_model = await file.CheckFileOrDirExist(path.resolve(define.scripts_path, 'lama/model/big-lama.pt'))
if (!has_model) {
throw new Error("图片水印处理的模型不存在,请看教程自行下载")
}
this.global.logger.info(LOGGER_DEFINE.REMOVE_WATERMARK, `开始使用lama去除水印,开始调用lama程序`);
// 先将对应的base64文件写道本地
let image_path = await this.Base64ToFile(JSON.stringify([value.image, `data/mask/temp/${new Date().getTime()}.png`]))
let mask_path = await this.Base64ToFile(JSON.stringify([value.mask, `data/mask/mask_temp_${new Date().getTime()}.png`]))
if (image_path.code == 0) {
throw new Error(image_path.message)
}
if (mask_path.code == 0) {
throw new Error(mask_path.message)
}
let child = spawn(lama_script, ['-l', image_path.data, mask_path.data, out_file], { encoding: 'utf-8' });
// let child = spawn('python', [lama_script, '-l', image_path.data, mask_path.data, out_file], { encoding: 'utf-8' });
child.on('error', (error) => {
reject(error.toString())
return
})
child.stdout.on('data', (data) => {
console.log(data.toString())
})
child.stderr.on('data', (data) => {
reject(data.toString())
return
})
child.on('close', async (data) => {
if (data != 0) {
this.global.logger.error(LOGGER_DEFINE.REMOVE_WATERMARK, `lama去除水印失败,错误码:${data.toString()}`);
reject("lama去除水印错误。请看日志详细信息!")
return
}
// 判断是不是有输出文件
let has_out = await file.CheckFileOrDirExist(out_file);
if (!has_out) {
reject("lama去除水印失败,没有输出文件")
return
}
if (value.type == 'arrayBuffer') {
// 读取导出的文件
let res_data = await fs.promises.readFile(out_file);
resolve(successMessage(res_data, "图片处理成功", LOGGER_DEFINE.REMOVE_WATERMARK));
} else if (value.type == "file") {
resolve(successMessage(out_file, "图片处理成功", LOGGER_DEFINE.REMOVE_WATERMARK));
}
})
}
} catch (error) {
reject("图片处理失败,失败原因如下:" + error.message)
}
})
}
// 批量处理所有的图片,去除水印
async BatchProcessImage(value) {
try {
let input_folder = value;
input_folder = path.resolve(this.global.config.project_path, input_folder)
if (!(await this.tools.checkExists(input_folder))) {
throw new Error("输入的文件夹不存在");
}
let new_input_folder = path.join(this.global.config.project_path, `tmp/bak/${path.basename(input_folder)}`);
// 在备份之前判断,旧的文件是不是存在,里面是不是有图片,没有图片,直接删除,在备份过去,存在直接开始下面的请求
let has_files = await file.CheckFileOrDirExist(new_input_folder);
if (has_files) {
let files = await file.GetFilesWithExtensions(new_input_folder, ['.png']);
if (files.length <= 0) {
// 删除指定的文件夹
await fs.promises.rm(new_input_folder, { recursive: true });
await file.BackupFileOrFolder(input_folder, new_input_folder);
// 创建新的input_folder
await fs.promises.mkdir(input_folder, { recursive: true })
}
} else {
await file.BackupFileOrFolder(input_folder, new_input_folder);
// 创建新的input_folder
await fs.promises.mkdir(input_folder, { recursive: true })
}
// 开始备份
// 获取蒙板
let mask_setting = (await ImageSetting.GetDefineConfigJsonByProperty(JSON.stringify(["img_base", "mask_setting", false, {}]))).data;
if (mask_setting.isRemote && isEmpty(mask_setting.localUrl)) {
throw new Error("使用iopaint图片处理,但是没有配置图片处理地址");
}
if (isEmpty(mask_setting.mask_path)) {
throw new Error("没有配置蒙板的路径");
}
// 获取文件夹里面所有的图片文件
// let png_files = await this.tools.getFilesWithExtensions(input_folder, '.png');
let png_files = await file.GetFilesWithExtensions(new_input_folder, ['.png']);
if (png_files.length == 0) {
throw new Error("没有找到任何的抽帧图片文件");
}
// 获取图片的总数,将数据返回前端,更新进度条
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.IMG.BATCH_PROCESS_IMAGE_RESULT, successMessage({
total: png_files.length,
current: 0
}))
// 默认所有的的宽高都是一样的,获取第一张图片的宽高
let first_image = png_files[0];
let first_image_size = await image.GetImageSize(first_image);
// 重新设置蒙板的宽高,和图片的宽高一样
let mask_base = await image.ResizeImage(mask_setting.mask_path, first_image_size.width, first_image_size.height, 'base64');
mask_base = `data:image/png;base64,${mask_base}`;
// 开始处理所有的图片
for (let i = 0; i < png_files.length; i++) {
const element = png_files[i];
// 获取指定的图片,并且转换为base64
let image_base = await fs.promises.readFile(element);
image_base = image_base.toString('base64');
image_base = `data:image/png;base64,${image_base}`;
// 开始处理图片
let res = await this.ProcessImage(JSON.stringify({
image: image_base,
mask: mask_base,
type: "file",
out_file: `tmp/input_crop/${path.basename(element)}`
}))
if (res.code == 0) {
throw new Error(res.message);
}
// 删除之前的
await this.tools.deleteFileOrDirectory(element)
await this.tools.delay(1000)
// 当前图片处理成功,将信息返回前端,更新进度条
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.IMG.BATCH_PROCESS_IMAGE_RESULT, successMessage({
total: png_files.length,
current: i + 1
}))
}
return successMessage("所有的图片处理成功", LOGGER_DEFINE.REMOVE_WATERMARK);
} catch (error) {
return errorMessage("图片处理失败,失败原因如下:" + error.message, LOGGER_DEFINE.REMOVE_WATERMARK);
}
}
}