If your AI-generated portrait looks like a golden retriever instead of Draco Malfoy’s cooler sister, it’s probably not the model’s fault—it’s your lighting. A new write-up from the builder behind malfoidai.com breaks down exactly why "platinum" hair consistently drifts into yellow or grey territory in image pipelines. The author, who builds independent studio tools for "Malfoid" (Female Malfoy) portraits, argues that users can’t fix the model’s internal priors but can strictly control the input photo and measure the output with data rather than eyesight.
The Science of Failing to Be Platinum
The core issue is that "platinum" is a narrow numerical target: high lightness (L* 70+), low chroma, and a blue-yellow axis (b*) near zero. The article explains that latent diffusion models pull toward the average of their training data, which is predominantly golden blonde. Furthermore, the default Malfoid scene is a candlelit academy corridor. Candlelight is warm, and very light hair reflects that warmth. If your source photo has a yellow kitchen bulb or blue monitor cast, the model conditions on that skin tone and drags the whole image’s color balance along with it.
Compression and Decoder Losses
Even if the generation is perfect, the pipeline destroys it. Highlights are the first casualty of 8-bit compression and re-encoding. The author notes that near-white hair sits at the top of the dynamic range where JPEG artifacts flatten faint color differences, turning hair into a "grey shape." Additionally, latent decoders are lossy on fine, low-contrast textures. This is why pale hair often looks like a "plastic helmet" at full resolution but appears acceptable on a small phone screen. Noise from a dark source photo that was brightened in an editor is also read as detail, resulting in grey speckle.
hair_tone.py: Measure Don’t Guess
To combat subjective arguments with your eyes, the builder released hair_tone.py, a script using NumPy and Pillow to convert specific regions of an image to CIELAB color space. It calculates the median L*, a*, and b* values for the hair region, ignoring the mean to prevent stray dark strands from skewing results. The script provides a verdict like "golden/yellow blond" or "platinum range" based on specific thresholds. For example, a b* value over 18 indicates golden drift, while a chroma under 6 with L* under 70 indicates a dull grey failure. It also includes a --cast flag to analyze the source photo’s overall color balance before you even pay for a generation.
Key Takeaways
- Lighting is the Primary Input Control: Since Malfoid portraits lack a prompt box for color adjustments, the source photo’s lighting (specifically avoiding warm/cool casts) is the only lever users have to influence hair tone.
- Compression Kills Highlights: JPEG re-saving and screenshotting degrade the subtle color variations that define platinum hair, turning it into a flat grey mass.
- Quantify the Problem: Use CIELAB metrics (L*, a*, b*) to objectively determine if hair is golden, ashy, or grey, rather than relying on subjective visual inspection which varies by screen settings.
The Bottom Line
Stop blaming the model for bad hair days when the culprit is a yellow kitchen bulb or aggressive JPEG compression. Measure the output with data, fix the input light, and save your credits.