洋紅幕配深紅披風:整件衣服被吃成半透明,腳本一聲都沒吭

去背分四步:選底色、生圖、key 掉、驗收。9 月 1 日撞的是第一步:幕色跟主體撞色,那一塊會跟背景一起被吃掉,而且不報錯。更早之前為了一頂帽子連生四輪,全都沒用,因為問題不在生圖那一端。

劉關張三張常服立繪,上排是純藍底的原圖,下排是去背之後的透明 PNG

chroma key 不會告訴你底色挑錯了。它照分數做事,主體身上哪一塊顏色跟幕色夠近,那一塊就跟背景一起走,全程一行錯誤訊息也沒有。

9 月 1 日下午在重生視覺小說《咒泉鄉桃園三結義》裡關羽的一張立繪,她身上裹著一件深紅色的短披風。幕色用慣用的洋紅 #FF00FF,key 完貼上去一看,整件披風是半透明的:換青色底就透出青色,換洋紅底就透出洋紅,像模型把它畫成了一層紗。紅跟洋紅在色相上只差一點,夠近就會中。

只要素材最後要疊到別的圖上,就會走到這一關:角色立繪、表情與服裝差分、道具、貼圖都一樣。整條流程四步,選底色、生圖、key 掉、驗收。第一步挑錯,後面三步就得一直替它擦屁股。

這條線上的工具是 cutout-skill:SKILL.md 寫做法,cutout.py 做事,兩個檔案都是 AI 寫的。剩下那一半是我的:要它做什麼、東西交回來的時候看出哪裡不對、要它改。

下面那頂帽子的四輪,就是挑錯底色的學費。

灰的不是那頂帽子

黑洞先生頭上那頂卡其色禮帽,配的是黃幕 #ffff00,出圖每一次都灰灰的。AI 連續四輪重生,全押在生圖提示詞上:把顏色講得更白話、把 hex 直接塞進提示詞、補一句 NEVER grey。四輪都沒用。

帽子的顏色一次都沒畫錯過。卡其跟黃幕靠得太近,帽子被 key 走一大半,剩下那層半透明貼在白底上,看起來就是灰的。去背成品習慣貼白底檢查,透明處在白底上就是白或淺灰,跟「模型把它畫成灰色」看起來一模一樣。換洋紅 #ff00ff,一次就過。黑洞先生的來歷寫在七日創作者挑戰那篇。

後來多認一個數字

肉眼那一關還是要過,但只靠「看起來像不像」不夠,所以判準換成一個數得出來的東西:不透明區內部(不算邊緣那圈環帶)還剩幾顆半透明像素。健康的圖只有幾百顆,上萬就代表有整片被吃進背景了。

披風那張換綠幕重生之後,這個數字從 99,254 掉到 717。這種量級的差別,縮圖上一點都看不出來。

負控制要一起配。棋盤格跟白底都藏得住「整片被吃掉」,要把成品貼到一個跟主體、跟幕色都離很遠的顏色上,透明區才會現形。所以 cutout.py check 每次都多吐一張貼在對照底色上的圖,預設是洋紅。

也可以數不透明像素,修好前後的差值就是被吃掉的量,帽子那次是 30k 變 51k。

這條判準是那晚幾輪重生之間寫進 SKILL.md 的。這篇裡的像素數多半是腳本印出來的,帽子那組跟百分比是概數。

挑幕色的三條

一、不要叫模型出透明圖或無背景圖。它回的是烤死的棋盤格、一層灰霧,或一圈光暈,疊到真的背景上就顯髒。要它畫的是主體單獨站在一片平塗的純色前面。

二、幕色從主體的顏色清單反推。先把主體身上所有顏色攤開,色相離得最遠的那一支才是候選。手邊常備兩支,綠 #00FF00 與洋紅 #FF00FF,主體偏綠就走洋紅,主體偏粉紫就走綠。

三、一個角色的素材從頭到尾綁死同一支幕色。基本立繪、表情、服裝、姿勢差分全部同一支,切出來才是同一組參數,疊上去也才對得齊。

底色選對之後,才輪到演算法

9 月 1 日 cutout-skill 進了四筆 commit,撞色那條是其中一筆。另外三筆都在處理演算法:

這三條每一條都有差。可是它們站在同一個前提上:幕色沒有撞到主體。撞色的時候,這三條照樣在做事,救不了選錯的那一步。

接下來的九天

9 月 3 日,第三色從「責任在你」變成做得起來。 skill 原本寫的是綠幕洋紅幕以外的顏色後果自負。把分數的算法攤開來看,它只是在看 key 色佔哪幾個通道:綠幕 g - max(r,b)、洋紅幕 min(r,b) - g、藍幕 b - max(r,g),同一個式子套到藍、青、黃都成立。

同一天也把黑、白、灰擋死。它們沒有色度,chroma key 在數學上無從下手,傳進去會直接報錯停住,不會安靜地什麼都不做。自動判幕還是只認綠與洋紅,判到別的顏色就擋下來要求重生,第三色得自己傳 --key #RRGGBB。

9 月 4 日,劉關張整組換藍幕。 綠幕救了披風,可是同一個人換回正裝就換一個問題:袍子是深綠織金,看起來會撞上綠幕。三個人的配色是米白配墨綠、深綠織金加紅披風、黑配紅。綠幕吃綠,洋紅幕吃關張身上的紅,常備的兩支看起來都不保險,整組改成純藍 #0000FF。

這支常數現在散在 larch-taoyuan 的 7 支腳本裡:常服、表情與姿勢差分、可收集 CG、配角,還有番外白帝城的立繪。封面上排那三張就是它們去背之前的樣子。

9 月 10 日,防線推到生圖那一步,還是漏掉一個。 做四個練習小故事的素材包時,八個角色的立繪用洋紅幕,提示詞裡寫死:衣服與頭髮不可以用紅色、粉紅色、紫色。理論上撞色在生圖那一刻就切掉了,等於用配色的自由度換產線的穩定,記錄裡沒寫這筆交換划不划算。

老闆娘那張沒切掉。她穿深綠圍裙,裡面是米白上衣配深色長裙,那條長裙帶紫,洋紅幕照樣把它吃成半透明。

拿 raw/ 裡的原圖重跑一次 key,那張的半透明像素是 118,672,出貨版是 58,543,中間差的六萬顆是後來補回不透明的。修法沒有回第一步換幕色,是在 build.py 裡加一支 refill():用原圖重判哪裡才是真的背景(純幕色分數夠高,或者從畫面邊界連得到),主體內部那些本身不太像幕色的補回不透明,邊緣留 3px 抗鋸齒帶。

所以生圖那端的禁色只是把撞色的機率壓低,沒有關掉。最後守門的還是驗收那個數字。

自己拿去用

skill 掛 MIT,repo 在 https://github.com/yazelin/cutout-skill。它不綁 Claude,README 寫的是任何 agent 讀 SKILL.md 就能照用法跑 cutout.py,依賴只有 numpy、Pillow、scipy。想先確認環境沒問題就跑 python3 cutout.py demo,它會印四角 alpha、alpha 分佈、殘留色邊,還有「背景沒去乾淨」那一欄。

同一套 chroma 判定也在 LINE 貼圖工作室 那條線上跑,那邊的上架防呆後來被移植回這支 skill 的驗收。自家貼圖產線的 README 把背景沒去乾淨列為上架防呆的第一條,整包出貨前逐張跑一次 check,別等退件通知回來才找是哪一張。