Project_WL/AgentScripts/WL814x4_pergroup.py

77 lines
3.7 KiB
Python
Raw Permalink Normal View History

# WL-814x4 — 부위 그룹(M05/Skin/Hair)별로 _DiffuseColor 역이득을 따로 탐색한다.
# 전역 이득 1개로는 못 맞추는 이유 = 부위마다 밝기 분포가 달라 그레이딩 회전량이 다르기 때문.
import json, sys
import numpy as np
from PIL import Image
RAW='Screenshots_WL/WL814x/4th/raw'
REN=sys.argv[1] if len(sys.argv)>1 else 'a_now'
def L(n): return np.asarray(Image.open(RAW+'/'+n+'.png').convert('RGB'),dtype=np.uint8)
def lum(c): return 0.299*c[0]+0.587*c[1]+0.114*c[2]
def hue(c):
r,g,b=[float(x) for x in c]; mx,mn=max(r,g,b),min(r,g,b); d=mx-mn
if d<1e-6: return 0.0
if mx==r: h=((g-b)/d)%6
elif mx==g: h=(b-r)/d+2
else: h=(r-g)/d+4
return h*60.0
def sat(c):
mx=max(c); return (mx-min(c))/mx if mx>1e-6 else 0
def dh(a,b): return (b-a+540)%360-180
idm=L('idmap'); maF=L('mask_Face')[:,:,0]>127; ma=(L('mask_all')[:,:,0]>127)&~maF
G=np.array(Image.open('Assets/WL/Look/Character/Textures/WLPalette_FINAL.png')).shape[0]//8
idref=np.array([[9+j*15,240-j*11,40+j*7] for j in range(G*G)],np.float32)
fl=idm.reshape(-1,3).astype(np.float32); d2=((fl[:,None,:]-idref[None,:,:])**2).sum(2)
kid=np.where((d2.min(1).reshape(idm.shape[:2])<400)&(idm.sum(2)>12), d2.argmin(1).reshape(idm.shape[:2]), -1)
tgt={int(k):np.array(v,np.float32) for k,v in json.load(open('AgentScripts/WL814x2_target.json')).items()}
PART={'Body_m05':'M05','Arm_m05':'M05','Leg_M05':'M05','Head':'Skin','Hair05':'Hair'}
pm={p:(L('mask_'+p)[:,:,0]>127) for p in PART}
im=L(REN)
cells={}
for j in range(G*G):
sel=ma&(kid==j); n=int(sel.sum())
if n<800: continue
grp=PART[max(((k,int((sel&v).sum())) for k,v in pm.items()),key=lambda t:t[1])[0]]
cells.setdefault(grp,[]).append((j,n,tgt[j].astype(np.float64),im[sel].mean(0).astype(np.float64)))
best={}
print('%-6s %-24s %8s %8s (칸 %d)'%('그룹','최적 _DiffuseColor','dHue','최대',0))
for grp,cs in cells.items():
def ev(g, full=False):
e=[];w=[];pen=0.0;pw=0.0
for j,n,o,s in cs:
c=np.clip(s*g,0,255)
if sat(o)>0.12:
e.append(abs(dh(hue(o),hue(c)))); w.append(n)
# 채도 보존: 보정으로 채도가 줄면(색이 빠지면) 벌점
pen += n*max(0.0, sat(s)-sat(c))*260.0; pw += n
else:
# 무채색 목표(흰옷·부츠)는 화면에서도 무채여야 한다
pen += n*max(0.0, sat(c)-0.14)*700.0; pw += n
if not e: return 0.0,0.0,0.0
e=np.array(e);w=np.array(w,float)
return (e*w).sum()/w.sum(), e.max(), pen/max(pw,1)
bb=None
for gr in np.arange(0.88,1.145,0.005):
for gb in np.arange(0.80,1.145,0.005):
gg=(1.0-0.299*gr-0.114*gb)/0.587
if gg<0.88 or gg>1.15: continue
g=np.array([gr,gg,gb]); a,m,pn=ev(g)
sc=a+0.4*m+pn
if bb is None or sc<bb[0]: bb=(sc,g,a,m)
a0,m0,_=ev(np.ones(3))
print('%-6s %-24s %8.1f %8.1f (보정 전 %.1f / 최대 %.1f · 칸 %d)'%(grp,str(np.round(bb[1],3)),bb[2],bb[3],a0,m0,len(cs)))
best[grp]=[float(x) for x in bb[1]]
for j,n,o,s in cs:
c=np.clip(s*bb[1],0,255)
print('%2d n=%6d 원본%-16s 지금%-16s%-16s dHue %+6.1f%+6.1f'%(j,n,
tuple(int(x) for x in o),tuple(int(x) for x in s),tuple(int(x) for x in c),dh(hue(o),hue(s)),dh(hue(o),hue(c))))
json.dump(best,open('AgentScripts/WL814x4_pergroup.json','w'),indent=1)
# 전체 가중 평균 예측
e=[];w=[]
for grp,cs in cells.items():
g=np.array(best[grp])
for j,n,o,s in cs:
if sat(o)<=0.12: continue
e.append(abs(dh(hue(o),hue(np.clip(s*g,0,255))))); w.append(n)
e=np.array(e);w=np.array(w,float)
print('예상 전체 유채 가중 dHue %.1f° (최대 %.1f°)'%((e*w).sum()/w.sum(),e.max()))