Spaces:
Running
Running
刘宇轩
commited on
Commit
·
3a8ba72
1
Parent(s):
8bf2c1e
Initial Commit
Browse files- .gitignore +13 -0
- app.py +398 -0
- asset/chaojihui-v2.png +0 -0
- asset/chaojihui.png +0 -0
- asset/chaojihui45.png +0 -0
- asset/zhushe.png +0 -0
- db_examples.py +98 -0
- images/dummy.png +0 -0
- images/original_1.jpg +0 -0
- images/original_2.jpg +0 -0
- images/original_3.jpg +0 -0
- images/original_4.jpg +0 -0
- images/reference_1.jpg +0 -0
- images/reference_2.jpg +0 -0
- images/reference_3.jpg +0 -0
- images/reference_4.jpg +0 -0
- images/resimg_1.webp +0 -0
- images/resimg_2.webp +0 -0
- images/resimg_3.webp +0 -0
- images/resimg_4.webp +0 -0
- images/restxt_1.webp +0 -0
- images/restxt_2.webp +0 -0
- images/restxt_3.webp +0 -0
- images/restxt_4.webp +0 -0
- images/restxt_5.webp +0 -0
- images/restxt_6.webp +0 -0
- images/restxt_7.webp +0 -0
- images/restxt_8.webp +0 -0
- ops.py +135 -0
- watermark.py +49 -0
.gitignore
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ossutil_output
|
| 2 |
+
__pycache__
|
| 3 |
+
.DS_Store
|
| 4 |
+
test.jpg
|
| 5 |
+
test.py
|
| 6 |
+
test.sh
|
| 7 |
+
app.sh
|
| 8 |
+
__pycache__
|
| 9 |
+
r1.jpg
|
| 10 |
+
r2.png
|
| 11 |
+
r11.png
|
| 12 |
+
test.jpg
|
| 13 |
+
temp.py
|
app.py
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib
|
| 2 |
+
import time
|
| 3 |
+
import uuid
|
| 4 |
+
from urllib.parse import urlencode
|
| 5 |
+
import json
|
| 6 |
+
import requests
|
| 7 |
+
from PIL import Image, ImageOps
|
| 8 |
+
import os
|
| 9 |
+
import gradio as gr
|
| 10 |
+
|
| 11 |
+
import ops
|
| 12 |
+
from watermark import WatermarkApp
|
| 13 |
+
import db_examples
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class ApiClient(object):
|
| 17 |
+
|
| 18 |
+
def __init__(self, app_key: str, access_key_id: str, access_key_secret: str, endpoint: str):
|
| 19 |
+
self.app_key = app_key
|
| 20 |
+
self.access_key_id = access_key_id
|
| 21 |
+
self.access_key_secret = access_key_secret
|
| 22 |
+
self.endpoint = endpoint
|
| 23 |
+
self.base_url = 'http://' + self.endpoint + '/api'
|
| 24 |
+
self.timeout = 8000
|
| 25 |
+
self.session = requests.Session()
|
| 26 |
+
self.session.headers.update(
|
| 27 |
+
{
|
| 28 |
+
"Content-Type": "application/json;charset=utf-8",
|
| 29 |
+
"accessKey": self.access_key_id,
|
| 30 |
+
"appKey": self.app_key
|
| 31 |
+
}
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
def send_get(self, headers=None, params=None):
|
| 35 |
+
if headers is None:
|
| 36 |
+
headers = {}
|
| 37 |
+
if params is None:
|
| 38 |
+
params = {}
|
| 39 |
+
args = self.cleanNoneValue(
|
| 40 |
+
{
|
| 41 |
+
"url": self.base_url,
|
| 42 |
+
"headers": self._prepare_headers(headers),
|
| 43 |
+
"params": self._prepare_params(params),
|
| 44 |
+
"timeout": self.timeout
|
| 45 |
+
}
|
| 46 |
+
)
|
| 47 |
+
response = self._dispatch_request("GET")(**args)
|
| 48 |
+
self._handle_exception(response)
|
| 49 |
+
try:
|
| 50 |
+
data = response.json()
|
| 51 |
+
except ValueError:
|
| 52 |
+
data = response.text
|
| 53 |
+
return data
|
| 54 |
+
|
| 55 |
+
def send_post(self, headers=None, params=None):
|
| 56 |
+
if headers is None:
|
| 57 |
+
headers = {}
|
| 58 |
+
if params is None:
|
| 59 |
+
params = {}
|
| 60 |
+
args = self.cleanNoneValue(
|
| 61 |
+
{
|
| 62 |
+
"url": self.base_url,
|
| 63 |
+
"headers": self._prepare_headers(headers),
|
| 64 |
+
"json": params,
|
| 65 |
+
"timeout": self.timeout
|
| 66 |
+
}
|
| 67 |
+
)
|
| 68 |
+
response = self._dispatch_request("POST")(**args)
|
| 69 |
+
self._handle_exception(response)
|
| 70 |
+
try:
|
| 71 |
+
data = response.json()
|
| 72 |
+
except ValueError:
|
| 73 |
+
data = response.text
|
| 74 |
+
return data
|
| 75 |
+
|
| 76 |
+
def _prepare_headers(self, headers):
|
| 77 |
+
headers['requestId'] = str(uuid.uuid1())
|
| 78 |
+
timestamp = int(round(time.time() * 1000))
|
| 79 |
+
headers['timestamp'] = str(timestamp)
|
| 80 |
+
headers['sign'] = self._get_sign(timestamp)
|
| 81 |
+
return headers
|
| 82 |
+
|
| 83 |
+
def _prepare_params(self, params):
|
| 84 |
+
return self.encoded_string(self.cleanNoneValue(params))
|
| 85 |
+
|
| 86 |
+
def _get_sign(self, timestamp):
|
| 87 |
+
key = self.app_key + self.access_key_id + str(timestamp) + self.access_key_secret
|
| 88 |
+
md5hash = hashlib.md5(str.encode(key, 'utf-8'))
|
| 89 |
+
return md5hash.hexdigest()
|
| 90 |
+
|
| 91 |
+
def _dispatch_request(self, http_method):
|
| 92 |
+
return {
|
| 93 |
+
"GET": self.session.get,
|
| 94 |
+
"DELETE": self.session.delete,
|
| 95 |
+
"PUT": self.session.put,
|
| 96 |
+
"POST": self.session.post,
|
| 97 |
+
}.get(http_method, "GET")
|
| 98 |
+
|
| 99 |
+
def _handle_exception(self, response):
|
| 100 |
+
status_code = response.status_code
|
| 101 |
+
if status_code < 400:
|
| 102 |
+
return
|
| 103 |
+
raise Exception(response.text)
|
| 104 |
+
|
| 105 |
+
def encoded_string(self, query):
|
| 106 |
+
|
| 107 |
+
return urlencode(query, True).replace("%40", "@")
|
| 108 |
+
|
| 109 |
+
def cleanNoneValue(self, d) -> dict:
|
| 110 |
+
out = {}
|
| 111 |
+
for k in d.keys():
|
| 112 |
+
if d[k] is not None:
|
| 113 |
+
out[k] = d[k]
|
| 114 |
+
return out
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
api_key = os.environ['APIKEY']
|
| 118 |
+
ak = os.environ['AK']
|
| 119 |
+
sk = os.environ['SK']
|
| 120 |
+
endpoint = os.environ['ENDPOINT']
|
| 121 |
+
apiname = os.environ['APINAME']
|
| 122 |
+
callbackapiname = os.environ['CALLBACKAPINAME']
|
| 123 |
+
osssigneapiname = os.environ['OSSSIGNAPINAME']
|
| 124 |
+
|
| 125 |
+
client = ApiClient(api_key, ak, sk, endpoint)
|
| 126 |
+
watermark_app = WatermarkApp()
|
| 127 |
+
|
| 128 |
+
def upload_to_oss(file_path, accessid, policy, signature, host, key, callback):
|
| 129 |
+
with open(file_path, 'rb') as f:
|
| 130 |
+
files = {'file': (key, f)}
|
| 131 |
+
data = {
|
| 132 |
+
'OSSAccessKeyId': accessid,
|
| 133 |
+
'policy': policy,
|
| 134 |
+
'Signature': signature,
|
| 135 |
+
'key': key,
|
| 136 |
+
'callback': callback,
|
| 137 |
+
}
|
| 138 |
+
response = requests.post(host, files=files, data=data)
|
| 139 |
+
if response.status_code == 204 or response.ok:
|
| 140 |
+
return key
|
| 141 |
+
else:
|
| 142 |
+
print(f"file upload failed: {response.text}")
|
| 143 |
+
return None
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def upload_oss_bucket(image_pil):
|
| 147 |
+
headers = {
|
| 148 |
+
'apiName': osssigneapiname
|
| 149 |
+
}
|
| 150 |
+
params = {
|
| 151 |
+
'fileType': '1'
|
| 152 |
+
}
|
| 153 |
+
result = client.send_get(headers, params)
|
| 154 |
+
try:
|
| 155 |
+
result = result['data']
|
| 156 |
+
except Exception as e:
|
| 157 |
+
raise ValueError('oss sign error')
|
| 158 |
+
accessid = result['accessid']
|
| 159 |
+
policy = result['policy']
|
| 160 |
+
signature = result['signature']
|
| 161 |
+
host = result['host']
|
| 162 |
+
callback = ''
|
| 163 |
+
oss_key = os.path.join(result['dir'], '{}.jpg'.format(result['expire']))
|
| 164 |
+
file_path = 'test.jpg'
|
| 165 |
+
image_pil.save(file_path)
|
| 166 |
+
oss_key = upload_to_oss(file_path, accessid, policy, signature, host, oss_key, callback)
|
| 167 |
+
if oss_key is None:
|
| 168 |
+
raise ValueError('oss upload error')
|
| 169 |
+
return oss_key
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def call_text_guided_relighting(image, mode, prompt, seed, steps):
|
| 173 |
+
headers = {
|
| 174 |
+
'apiName': apiname
|
| 175 |
+
}
|
| 176 |
+
image = ImageOps.exif_transpose(image).convert('RGB')
|
| 177 |
+
image = ops.resize_keep_hw_rate(image, tar_res=1280)
|
| 178 |
+
image = upload_oss_bucket(image)
|
| 179 |
+
ops.print_with_datetime('start call_text_guided_relighting')
|
| 180 |
+
ops.print_with_datetime(prompt)
|
| 181 |
+
params = {
|
| 182 |
+
'image': image,
|
| 183 |
+
'inference_mode': 'free_txt2bg_gen',
|
| 184 |
+
'mode': mode,
|
| 185 |
+
'prompt': prompt,
|
| 186 |
+
'seed': seed,
|
| 187 |
+
'steps': steps,
|
| 188 |
+
}
|
| 189 |
+
ops.print_with_datetime(f'length params, {len(json.dumps(params))}')
|
| 190 |
+
task_id = client.send_post(headers, params)['data']
|
| 191 |
+
time.sleep(10)
|
| 192 |
+
headers = {
|
| 193 |
+
'apiName': callbackapiname
|
| 194 |
+
}
|
| 195 |
+
params = {
|
| 196 |
+
'id': task_id
|
| 197 |
+
}
|
| 198 |
+
flag = True
|
| 199 |
+
while flag:
|
| 200 |
+
result = client.send_get(headers, params)['data']
|
| 201 |
+
if result['status'] != 1:
|
| 202 |
+
flag = False
|
| 203 |
+
else:
|
| 204 |
+
time.sleep(10)
|
| 205 |
+
if result['status'] != 2:
|
| 206 |
+
raise ValueError('something wrong in the process')
|
| 207 |
+
|
| 208 |
+
result_1 = result['sasMyCreationPicVOs'][0]['picUrl']
|
| 209 |
+
result_2 = result['sasMyCreationPicVOs'][0]['maskUrl']
|
| 210 |
+
result_1 = ops.decode_img_from_url(result_1)
|
| 211 |
+
result_1 = watermark_app.process_image(result_1)
|
| 212 |
+
result_2 = ops.decode_img_from_url(result_2)
|
| 213 |
+
return result_1, result_2
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def call_image_guided_relighting(image, ref_img, seed, steps):
|
| 217 |
+
headers = {
|
| 218 |
+
'apiName': apiname
|
| 219 |
+
}
|
| 220 |
+
image = ImageOps.exif_transpose(image).convert('RGB')
|
| 221 |
+
image = ops.resize_keep_hw_rate(image, tar_res=1280)
|
| 222 |
+
image = upload_oss_bucket(image)
|
| 223 |
+
|
| 224 |
+
ref_img = ImageOps.exif_transpose(ref_img).convert('RGB')
|
| 225 |
+
ref_img = ops.resize_keep_hw_rate(ref_img, tar_res=1280)
|
| 226 |
+
ref_img = upload_oss_bucket(ref_img)
|
| 227 |
+
|
| 228 |
+
ops.print_with_datetime('start call_image_guided_relighting')
|
| 229 |
+
params = {
|
| 230 |
+
'image': image,
|
| 231 |
+
'inference_mode': 'replica_gen',
|
| 232 |
+
'mode': 'normal',
|
| 233 |
+
'ref_img': ref_img,
|
| 234 |
+
'seed': seed,
|
| 235 |
+
'steps': steps,
|
| 236 |
+
}
|
| 237 |
+
ops.print_with_datetime(f'length params, {len(json.dumps(params))}')
|
| 238 |
+
task_id = client.send_post(headers, params)
|
| 239 |
+
print(task_id)
|
| 240 |
+
task_id = task_id['data']
|
| 241 |
+
time.sleep(10)
|
| 242 |
+
headers = {
|
| 243 |
+
'apiName': callbackapiname
|
| 244 |
+
}
|
| 245 |
+
params = {
|
| 246 |
+
'id': task_id
|
| 247 |
+
}
|
| 248 |
+
flag = True
|
| 249 |
+
while flag:
|
| 250 |
+
result = client.send_get(headers, params)
|
| 251 |
+
result = result['data']
|
| 252 |
+
if result['status'] != 1:
|
| 253 |
+
flag = False
|
| 254 |
+
else:
|
| 255 |
+
time.sleep(10)
|
| 256 |
+
if result['status'] != 2:
|
| 257 |
+
raise ValueError('something wrong in the process')
|
| 258 |
+
|
| 259 |
+
result_1 = result['sasMyCreationPicVOs'][0]['picUrl']
|
| 260 |
+
result_2 = result['sasMyCreationPicVOs'][0]['maskUrl']
|
| 261 |
+
result_1 = ops.decode_img_from_url(result_1)
|
| 262 |
+
result_1 = watermark_app.process_image(result_1)
|
| 263 |
+
result_2 = ops.decode_img_from_url(result_2)
|
| 264 |
+
return result_1, result_2
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
quick_prompts = [
|
| 269 |
+
'warm lighting',
|
| 270 |
+
'sunshine from window',
|
| 271 |
+
'neon lighting',
|
| 272 |
+
'at noon. bright sunlight',
|
| 273 |
+
'at dusk',
|
| 274 |
+
'golden time',
|
| 275 |
+
'natural lighting',
|
| 276 |
+
'shadow from window',
|
| 277 |
+
'soft studio lighting',
|
| 278 |
+
'red lighting',
|
| 279 |
+
'purple lighting'
|
| 280 |
+
]
|
| 281 |
+
quick_prompts = [[x] for x in quick_prompts]
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
quick_content_prompts = [
|
| 285 |
+
'by the sea',
|
| 286 |
+
'in the forest',
|
| 287 |
+
'on the snow mountain',
|
| 288 |
+
'by the city street',
|
| 289 |
+
'on the grassy field',
|
| 290 |
+
'cityscape',
|
| 291 |
+
'on the desert',
|
| 292 |
+
'in the living room',
|
| 293 |
+
]
|
| 294 |
+
quick_content_prompts = [[x] for x in quick_content_prompts]
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
quick_subjects = [
|
| 298 |
+
'portrait photography of a woman',
|
| 299 |
+
'portrait photography of man',
|
| 300 |
+
'product photography',
|
| 301 |
+
]
|
| 302 |
+
quick_subjects = [[x] for x in quick_subjects]
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
with gr.Blocks().queue() as demo:
|
| 306 |
+
gr.HTML("""
|
| 307 |
+
<div style="text-align: center; font-size: 32px; font-weight: bold; margin-bottom: 20px;">
|
| 308 |
+
FreeLighting: relighting model with both text-condition and image-condition
|
| 309 |
+
</div>
|
| 310 |
+
""")
|
| 311 |
+
with gr.Row():
|
| 312 |
+
gr.Markdown("See more information in https://github.com/liuyuxuan3060/FreeLighting")
|
| 313 |
+
with gr.Row():
|
| 314 |
+
gr.Markdown("We use a open source segmentation model to generate image mask")
|
| 315 |
+
|
| 316 |
+
with gr.Tabs():
|
| 317 |
+
with gr.TabItem("text-guided relighting") as t2v_tab:
|
| 318 |
+
with gr.Row():
|
| 319 |
+
with gr.Column():
|
| 320 |
+
with gr.Row():
|
| 321 |
+
image = gr.Image(label="original_image", type="pil", height=480)
|
| 322 |
+
image_mask = gr.Image(label="image_mask", type="pil", height=480)
|
| 323 |
+
with gr.Row():
|
| 324 |
+
prompt = gr.Textbox(value="", label="text prompt")
|
| 325 |
+
with gr.Row():
|
| 326 |
+
mode = gr.Radio(choices=["normal", "uniform-lit"], value='normal', label="uniform-lit mode will use double time", type='value')
|
| 327 |
+
seed = gr.Number(value=12345, label="random seed", precision=0)
|
| 328 |
+
steps = gr.Slider(label="Steps", minimum=1, maximum=100, value=20, step=1)
|
| 329 |
+
button = gr.Button("generate")
|
| 330 |
+
|
| 331 |
+
with gr.Row():
|
| 332 |
+
example_quick_subjects = gr.Dataset(samples=quick_subjects, label='Subject Quick List', samples_per_page=1000, components=[prompt])
|
| 333 |
+
with gr.Row():
|
| 334 |
+
example_quick_prompts = gr.Dataset(samples=quick_prompts, label='Lighting Quick List', samples_per_page=1000, components=[prompt])
|
| 335 |
+
with gr.Row():
|
| 336 |
+
example_quick_content_prompts = gr.Dataset(samples=quick_content_prompts, label='Content Quick List', samples_per_page=1000, components=[prompt])
|
| 337 |
+
with gr.Column():
|
| 338 |
+
relighting_image = gr.Image(label="relighted_image", type="pil", height=480)
|
| 339 |
+
|
| 340 |
+
with gr.Row():
|
| 341 |
+
gr.Examples(
|
| 342 |
+
examples=db_examples.text_guided_examples,
|
| 343 |
+
inputs=[
|
| 344 |
+
image, mode, prompt, seed, steps
|
| 345 |
+
, relighting_image
|
| 346 |
+
],
|
| 347 |
+
outputs=[relighting_image],
|
| 348 |
+
examples_per_page=1024
|
| 349 |
+
)
|
| 350 |
+
|
| 351 |
+
button.click(
|
| 352 |
+
fn=call_text_guided_relighting,
|
| 353 |
+
inputs=[
|
| 354 |
+
image, mode, prompt, seed, steps
|
| 355 |
+
],
|
| 356 |
+
outputs=[relighting_image, image_mask],
|
| 357 |
+
)
|
| 358 |
+
example_quick_content_prompts.click(lambda x, y: ', '.join(y.split(', ')[:2] + [x[0]]), inputs=[example_quick_content_prompts, prompt], outputs=prompt, show_progress=False, queue=False)
|
| 359 |
+
example_quick_prompts.click(lambda x, y: ', '.join(y.split(', ')[:2] + [x[0]]), inputs=[example_quick_prompts, prompt], outputs=prompt, show_progress=False, queue=False)
|
| 360 |
+
example_quick_subjects.click(lambda x: x[0], inputs=example_quick_subjects, outputs=prompt, show_progress=False, queue=False)
|
| 361 |
+
|
| 362 |
+
with gr.TabItem("image-guided relighting") as i2v_tab:
|
| 363 |
+
with gr.Row():
|
| 364 |
+
with gr.Column():
|
| 365 |
+
with gr.Row():
|
| 366 |
+
image = gr.Image(label="original_image", type="pil", height=480)
|
| 367 |
+
ref_img = gr.Image(label="reference_image", type="pil", height=480)
|
| 368 |
+
image_mask = gr.Image(label="image_mask", type="pil", height=480)
|
| 369 |
+
with gr.Row():
|
| 370 |
+
seed = gr.Number(value=12345, label="random seed", precision=0)
|
| 371 |
+
steps = gr.Slider(label="Steps", minimum=1, maximum=100, value=20, step=1)
|
| 372 |
+
button = gr.Button("generate")
|
| 373 |
+
with gr.Column():
|
| 374 |
+
relighting_image = gr.Image(label="relighted_image", type="pil", height=480)
|
| 375 |
+
|
| 376 |
+
with gr.Row():
|
| 377 |
+
gr.Examples(
|
| 378 |
+
examples=db_examples.image_guided_examples,
|
| 379 |
+
inputs=[
|
| 380 |
+
image, ref_img, seed, steps
|
| 381 |
+
, relighting_image
|
| 382 |
+
],
|
| 383 |
+
outputs=[relighting_image],
|
| 384 |
+
examples_per_page=1024
|
| 385 |
+
)
|
| 386 |
+
|
| 387 |
+
button.click(
|
| 388 |
+
fn=call_image_guided_relighting,
|
| 389 |
+
inputs=[
|
| 390 |
+
image, ref_img, seed, steps
|
| 391 |
+
],
|
| 392 |
+
outputs=[relighting_image, image_mask],
|
| 393 |
+
)
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
demo.launch()
|
| 397 |
+
|
| 398 |
+
|
asset/chaojihui-v2.png
ADDED
|
asset/chaojihui.png
ADDED
|
asset/chaojihui45.png
ADDED
|
asset/zhushe.png
ADDED
|
db_examples.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
text_guided_examples = [
|
| 2 |
+
[
|
| 3 |
+
'images/original_1.jpg',
|
| 4 |
+
'uniform-lit',
|
| 5 |
+
'portrait photography of a woman, at noon. bright sunlight, by the sea',
|
| 6 |
+
1,
|
| 7 |
+
20,
|
| 8 |
+
'images/restxt_1.webp',
|
| 9 |
+
],
|
| 10 |
+
[
|
| 11 |
+
'images/original_1.jpg',
|
| 12 |
+
'uniform-lit',
|
| 13 |
+
'portrait photography of a woman, neon lighting, by the city street',
|
| 14 |
+
1,
|
| 15 |
+
20,
|
| 16 |
+
'images/restxt_2.webp',
|
| 17 |
+
],
|
| 18 |
+
[
|
| 19 |
+
'images/original_2.jpg',
|
| 20 |
+
'normal',
|
| 21 |
+
'portrait photography of a woman, purple lighting, in the living room',
|
| 22 |
+
1,
|
| 23 |
+
20,
|
| 24 |
+
'images/restxt_3.webp',
|
| 25 |
+
],
|
| 26 |
+
[
|
| 27 |
+
'images/original_2.jpg',
|
| 28 |
+
'normal',
|
| 29 |
+
'portrait photography of a woman, warm lighting, on the desert',
|
| 30 |
+
1,
|
| 31 |
+
20,
|
| 32 |
+
'images/restxt_4.webp',
|
| 33 |
+
],
|
| 34 |
+
[
|
| 35 |
+
'images/original_3.jpg',
|
| 36 |
+
'uniform-lit',
|
| 37 |
+
'portrait photography of a woman, at noon. bright sunlight, cityscape',
|
| 38 |
+
1,
|
| 39 |
+
20,
|
| 40 |
+
'images/restxt_5.webp',
|
| 41 |
+
],
|
| 42 |
+
[
|
| 43 |
+
'images/original_3.jpg',
|
| 44 |
+
'normal',
|
| 45 |
+
'portrait photography of a woman, at noon. bright sunlight, cityscape',
|
| 46 |
+
1,
|
| 47 |
+
20,
|
| 48 |
+
'images/restxt_6.webp',
|
| 49 |
+
],
|
| 50 |
+
[
|
| 51 |
+
'images/original_4.jpg',
|
| 52 |
+
'normal',
|
| 53 |
+
'portrait photography of a woman, at noon. bright sunlight, cityscape',
|
| 54 |
+
1,
|
| 55 |
+
20,
|
| 56 |
+
'images/restxt_7.webp',
|
| 57 |
+
],
|
| 58 |
+
[
|
| 59 |
+
'images/original_4.jpg',
|
| 60 |
+
'normal',
|
| 61 |
+
'portrait photography of a woman, neon lighting, by the city street',
|
| 62 |
+
1,
|
| 63 |
+
20,
|
| 64 |
+
'images/restxt_8.webp',
|
| 65 |
+
],
|
| 66 |
+
]
|
| 67 |
+
|
| 68 |
+
image_guided_examples = [
|
| 69 |
+
[
|
| 70 |
+
'images/original_1.jpg',
|
| 71 |
+
'images/reference_2.jpg',
|
| 72 |
+
12345,
|
| 73 |
+
20,
|
| 74 |
+
'images/resimg_1.webp',
|
| 75 |
+
],
|
| 76 |
+
[
|
| 77 |
+
'images/original_3.jpg',
|
| 78 |
+
'images/reference_4.jpg',
|
| 79 |
+
12345,
|
| 80 |
+
20,
|
| 81 |
+
'images/resimg_2.webp',
|
| 82 |
+
],
|
| 83 |
+
[
|
| 84 |
+
'images/original_4.jpg',
|
| 85 |
+
'images/reference_3.jpg',
|
| 86 |
+
12345,
|
| 87 |
+
20,
|
| 88 |
+
'images/resimg_3.webp',
|
| 89 |
+
],
|
| 90 |
+
[
|
| 91 |
+
'images/original_2.jpg',
|
| 92 |
+
'images/reference_3.jpg',
|
| 93 |
+
12345,
|
| 94 |
+
20,
|
| 95 |
+
'images/resimg_4.webp',
|
| 96 |
+
],
|
| 97 |
+
]
|
| 98 |
+
|
images/dummy.png
ADDED
|
images/original_1.jpg
ADDED
|
images/original_2.jpg
ADDED
|
images/original_3.jpg
ADDED
|
images/original_4.jpg
ADDED
|
images/reference_1.jpg
ADDED
|
images/reference_2.jpg
ADDED
|
images/reference_3.jpg
ADDED
|
images/reference_4.jpg
ADDED
|
images/resimg_1.webp
ADDED
|
images/resimg_2.webp
ADDED
|
images/resimg_3.webp
ADDED
|
images/resimg_4.webp
ADDED
|
images/restxt_1.webp
ADDED
|
images/restxt_2.webp
ADDED
|
images/restxt_3.webp
ADDED
|
images/restxt_4.webp
ADDED
|
images/restxt_5.webp
ADDED
|
images/restxt_6.webp
ADDED
|
images/restxt_7.webp
ADDED
|
images/restxt_8.webp
ADDED
|
ops.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import base64
|
| 2 |
+
import numpy as np
|
| 3 |
+
import cv2
|
| 4 |
+
import json
|
| 5 |
+
import pickle
|
| 6 |
+
import itertools
|
| 7 |
+
import requests
|
| 8 |
+
from io import StringIO
|
| 9 |
+
|
| 10 |
+
from io import BytesIO
|
| 11 |
+
import re, os
|
| 12 |
+
from PIL import Image
|
| 13 |
+
from datetime import datetime
|
| 14 |
+
import random
|
| 15 |
+
|
| 16 |
+
import torch
|
| 17 |
+
|
| 18 |
+
import socket
|
| 19 |
+
r_b64_prefix = r'^data:image/.+;base64,'
|
| 20 |
+
|
| 21 |
+
from PIL import ImageOps
|
| 22 |
+
import oss2
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class OSS2:
|
| 26 |
+
def __init__(self, bucket):
|
| 27 |
+
self.bucket = bucket
|
| 28 |
+
|
| 29 |
+
def get_download(self, object_name, download_name=None, minute=5):
|
| 30 |
+
"""
|
| 31 |
+
获取文件下载地址
|
| 32 |
+
:param object_name: OSS 路径
|
| 33 |
+
:param download_name: 下载重命名
|
| 34 |
+
:param minute: 请求超时时间
|
| 35 |
+
:return: 授权URL
|
| 36 |
+
"""
|
| 37 |
+
params = None
|
| 38 |
+
if download_name:
|
| 39 |
+
params = {"response-content-disposition": 'attachment;filename="{0}"'.format(quote(download_name, 'utf-8'))}
|
| 40 |
+
url = self.bucket.sign_url('GET', object_name, minute * 60, params=params)
|
| 41 |
+
return url
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def _pil_image_push_ossdir(bucket, image_pil, object_key, quality=85, format='jpeg'):
|
| 48 |
+
import io
|
| 49 |
+
print_with_datetime('upload object_key {}'.format(object_key))
|
| 50 |
+
oss_path = None
|
| 51 |
+
for _ in range(5):
|
| 52 |
+
try:
|
| 53 |
+
img_byte_arr = io.BytesIO()
|
| 54 |
+
image_pil.save(img_byte_arr, format=format, quality=quality) # 根据实际图片格式选择保存格式
|
| 55 |
+
img_byte_arr.seek(0) # 回到开始位置
|
| 56 |
+
bucket.put_object(object_key, img_byte_arr)
|
| 57 |
+
oss_path = object_key
|
| 58 |
+
return oss_path
|
| 59 |
+
except Exception as e:
|
| 60 |
+
print_with_datetime('error, upload oss failed, {}'.format(str(e)))
|
| 61 |
+
return oss_path
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def resize_keep_hw_rate(image, tar_res):
|
| 66 |
+
w, h = image.size
|
| 67 |
+
if w > h:
|
| 68 |
+
tar_w = tar_res
|
| 69 |
+
tar_h = int(tar_w * h / w)
|
| 70 |
+
elif h > w:
|
| 71 |
+
tar_h = tar_res
|
| 72 |
+
tar_w = int(tar_h * w / h)
|
| 73 |
+
else:
|
| 74 |
+
tar_w = tar_res
|
| 75 |
+
tar_h = tar_res
|
| 76 |
+
image = image.resize((tar_w, tar_h), Image.LANCZOS)
|
| 77 |
+
return image
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def decode_img_from_url(url):
|
| 81 |
+
import requests
|
| 82 |
+
from io import BytesIO
|
| 83 |
+
for _ in range(5):
|
| 84 |
+
try:
|
| 85 |
+
content = requests.get(url, stream=True, timeout=10).content
|
| 86 |
+
img = Image.open(BytesIO(content))
|
| 87 |
+
img = ImageOps.exif_transpose(img)
|
| 88 |
+
break
|
| 89 |
+
except Exception as e:
|
| 90 |
+
print_with_datetime(f"url decode error {url} {str(e)}")
|
| 91 |
+
img = None
|
| 92 |
+
return img
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def make_sub_file_folder(file_path):
|
| 96 |
+
subdir = file_path.split(os.path.basename(file_path))[0]
|
| 97 |
+
os.makedirs(subdir, exist_ok=True)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def get_random_file_name():
|
| 101 |
+
timing_cur = datetime.now().timestamp() * 1000000
|
| 102 |
+
timing_cur = str(int(timing_cur)) + f'-{random.randint(0,99999999)}'
|
| 103 |
+
return timing_cur
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def print_with_datetime(string):
|
| 107 |
+
print(f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: {string}', flush=True)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def b64_pil(base64Data, mode = 'RGB'):
|
| 111 |
+
try:
|
| 112 |
+
base64Data = re.sub(r_b64_prefix, '', base64Data)
|
| 113 |
+
imgData = base64.b64decode(base64Data)
|
| 114 |
+
image = Image.open(BytesIO(imgData))
|
| 115 |
+
except:
|
| 116 |
+
image = None
|
| 117 |
+
return image
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def pil_b64(pil_img, fmt='jpeg', quality=75):
|
| 121 |
+
output_buffer = BytesIO()
|
| 122 |
+
pil_img.save(output_buffer, format=fmt, quality=quality)
|
| 123 |
+
byte_data = output_buffer.getvalue()
|
| 124 |
+
base64_str = base64.b64encode(byte_data).decode('utf-8')
|
| 125 |
+
if fmt == 'jpeg':
|
| 126 |
+
fmt_out = 'jpg'
|
| 127 |
+
else:
|
| 128 |
+
fmt_out = fmt
|
| 129 |
+
return f'data:image/{fmt_out};base64,' + base64_str
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def get_ip():
|
| 133 |
+
hostname = socket.gethostname()
|
| 134 |
+
ip_address = socket.gethostbyname(hostname)
|
| 135 |
+
return ip_address
|
watermark.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import oss2
|
| 3 |
+
from PIL import Image
|
| 4 |
+
import gradio as gr
|
| 5 |
+
import numpy as np
|
| 6 |
+
from io import BytesIO
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class WatermarkApp:
|
| 11 |
+
def __init__(self):
|
| 12 |
+
pass
|
| 13 |
+
|
| 14 |
+
def process_image(self, image):
|
| 15 |
+
watermark = Image.open('asset/chaojihui-v2.png')
|
| 16 |
+
# 获取水印的等比例缩放尺寸
|
| 17 |
+
wm_width, wm_height = watermark.size
|
| 18 |
+
target_size = 100
|
| 19 |
+
alpha = 0.3
|
| 20 |
+
|
| 21 |
+
if wm_width > wm_height:
|
| 22 |
+
new_wm_width = target_size
|
| 23 |
+
new_wm_height = int((wm_height / wm_width) * target_size)
|
| 24 |
+
else:
|
| 25 |
+
new_wm_height = target_size
|
| 26 |
+
new_wm_width = int((wm_width / wm_height) * target_size)
|
| 27 |
+
|
| 28 |
+
wm = watermark.resize((new_wm_width, new_wm_height), Image.Resampling.LANCZOS)
|
| 29 |
+
|
| 30 |
+
# 处理透明度
|
| 31 |
+
if alpha < 1.0:
|
| 32 |
+
wm = self.apply_transparency(wm, alpha)
|
| 33 |
+
|
| 34 |
+
# 确保原图是RGBA模式
|
| 35 |
+
if image.mode != 'RGBA':
|
| 36 |
+
image = image.convert('RGBA')
|
| 37 |
+
|
| 38 |
+
# 在整个图片上铺满水印
|
| 39 |
+
for y in range(0, image.height, new_wm_height):
|
| 40 |
+
for x in range(0, image.width, new_wm_width):
|
| 41 |
+
image.alpha_composite(wm, dest=(x, y))
|
| 42 |
+
return image
|
| 43 |
+
|
| 44 |
+
def apply_transparency(self, watermark, alpha):
|
| 45 |
+
"""应用透明度"""
|
| 46 |
+
matrix = watermark.split()[-1].point(lambda x: x * alpha)
|
| 47 |
+
watermark.putalpha(matrix)
|
| 48 |
+
return watermark
|
| 49 |
+
|