复刻PhotoDirector笔刷取样填充功能的技术实现问询
Hey there! Let me walk through what I've been building, the optimizations I've tried, and the core question I'm grappling with:
Replicating PhotoDirector's "Cutout" Brush Feature
Background & Current Progress
- I'm working to replicate the Cutout brush tool from PhotoDirector—this tool lets you paint a brush path to sample multiple colors, then automatically fills connected matching regions when you release the mouse.
- My current auto-fill result looks like this: Auto-fill demo
- I started with Unity's official
TextureFloodFillcode from their Wiki, which uses single-click color sampling and grows the fill by comparing each pixel to the initial sampled color, stopping when colors don't match.
Optimizations I've Implemented So Far
- Since I need to sample multiple pixels along a single brush stroke, I abandoned using a
Listfor color checks (which was extremely slow) and switched to a nested boolean class structure (RLookup→GLookup→bool[]) for much faster color lookups. - I initially used HSB color space but hit edge cases: low-saturation, high/low-brightness colors made hue comparisons unreliable. I reverted to RGB for now, but plan to switch back to HSB with two additional nested boolean lookup classes:
- One for grayscale-adjacent scenarios (saturation below threshold but with visible brightness) — only checks saturation and brightness
- One for extremely dark/bright pixels — only checks brightness
This should fix the hue comparison issues in those edge cases.
Key Issues & Suspicions
- I'm starting to think the problem isn't just color detection—it's also the growth logic. My current code only checks the next adjacent pixel to decide whether to stop growing, which leads to fragmented fills. PhotoDirector has far cleaner edge detection: it seems to look ahead a few pixels—if most consecutive pixels don't match, it stops; if only a handful differ, it ignores them and continues, eliminating those annoying fragments.
- Another notable difference: PhotoDirector limits fill growth to a bounding box-like area. My code will fill the entire image if colors match, even with a small sample, while PD keeps fills as neat, bounded regions. I haven't added this bounding box logic yet, since I'm focusing first on stabilizing fills near the brush path.
Core Question
What's the standard implementation approach for a feature like PhotoDirector's brush-sample + release-to-flood-fill? Is it primarily about refining color sampling/detection logic, or is there a specialized growth algorithm that handles edge continuity and fragmentation more effectively?
Relevant Code Snippet
public class GLookup { public bool[] bBools; public GLookup(int num) { bBools = new bool[num]; } } public class RLookup { public GLookup[] gLookup; public RLookup(int num) { gLookup = new GLookup[num]; for(int i = 0; i < num; i++) { gLookup[i] = new GLookup(num); } } } static void ResetLookup() { for(int i = 0; i < Grid.Paint.Options.colorLookupRes; i++) { rgbLookup[i] = new RLookup(Grid.Paint.Options.colorLookupRes); rgbCheck[i] = new RLookup(Grid.Paint.Options.colorLookupRes); } } static void InsertLookup(Color32 rgb, float tol) { int r = (int)(rgb.r/byteToLookup); int g = (int)(rgb.g/ byteToLookup); int b = (int)(rgb.b/ byteToLookup); if(r == Grid.Paint.Options.colorLookupRes) r = Grid.Paint.Options.colorLookupRes - 1; if(g == Grid.Paint.Options.colorLookupRes) g = Grid.Paint.Options.colorLookupRes-1; if(b == Grid.Paint.Options.colorLookupRes) b = Grid.Paint.Options.colorLookupRes-1; if(rgbCheck[r].gLookup[g].bBools[b]) { return; } rgbCheck[r].gLookup[g].bBools[b] = true; int tolNum = Grid.Paint.Options.maxTolNum; // Initial InsertLookupEntry(r, g, b); InsertNeighborSatBri(r, g, b, tolNum); // Hue fills int currentHue; // +- 5 hue if tol 1 for(int i = 0; i < Grid.Paint.Options.hueFill; i++) { // Higher hue currentHue = r + (i + 1); if(currentHue > Grid.Paint.Options.colorLookupRes-1) currentHue = Grid.Paint.Options.colorLookupRes-1; InsertLookupEntry(currentHue, g, b); InsertNeighborSatBri(currentHue, g, b, tolNum); // Lower hue currentHue = r - (i + 1); if(currentHue < 0) currentHue = 0; InsertLookupEntry(currentHue, g, b); InsertNeighborSatBri(currentHue, g, b, tolNum); } }
内容的提问来源于stack exchange,提问作者Bito Ishmael
相关产品推荐
相关产品推荐

