add internal holes detection in jump-hop image processing
This commit is contained in:
@@ -38,6 +38,10 @@ pub struct GeneratedAssetSheetAlphaOptions {
|
||||
pub key_color: GeneratedAssetSheetKeyColor,
|
||||
pub remove_near_white_background: bool,
|
||||
pub remove_disconnected_hard_key_background: bool,
|
||||
// 中文注释:检测并清除被主体包围、不与画布四边连通的品红镂空区域。
|
||||
// 仅对独立连通域整体判定,通过 min_pixels 过滤微小噪点。
|
||||
pub detect_internal_holes: bool,
|
||||
pub internal_hole_min_pixels: usize,
|
||||
}
|
||||
|
||||
impl GeneratedAssetSheetAlphaOptions {
|
||||
@@ -46,6 +50,8 @@ impl GeneratedAssetSheetAlphaOptions {
|
||||
key_color: GeneratedAssetSheetKeyColor::GREEN_SCREEN,
|
||||
remove_near_white_background: true,
|
||||
remove_disconnected_hard_key_background: true,
|
||||
detect_internal_holes: false,
|
||||
internal_hole_min_pixels: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +60,8 @@ impl GeneratedAssetSheetAlphaOptions {
|
||||
key_color: GeneratedAssetSheetKeyColor::MAGENTA_SCREEN,
|
||||
remove_near_white_background: false,
|
||||
remove_disconnected_hard_key_background: false,
|
||||
detect_internal_holes: true,
|
||||
internal_hole_min_pixels: 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,6 +224,66 @@ fn remove_generated_asset_sheet_green_screen_background(
|
||||
}
|
||||
}
|
||||
|
||||
// 中文注释:内部镂空洞检测——寻找与四边不连通、被主体包围的品红区域。
|
||||
// 必须在软 matte 扩展之前执行,避免软扩展跨越窄前景通道误判。
|
||||
if options.detect_internal_holes && options.internal_hole_min_pixels > 0 {
|
||||
let mut hole_visited = vec![false; pixel_count];
|
||||
let mut hole_queue = Vec::<usize>::new();
|
||||
|
||||
for start_index in 0..pixel_count {
|
||||
if background_mask[start_index] != 0
|
||||
|| key_scores[start_index] < GENERATED_ASSET_SHEET_GREEN_SCREEN_MIN_SCORE
|
||||
|| hole_visited[start_index]
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 中文注释:BFS 收集当前候选背景连通域
|
||||
hole_queue.clear();
|
||||
hole_queue.push(start_index);
|
||||
hole_visited[start_index] = true;
|
||||
let mut component = Vec::<usize>::new();
|
||||
let mut touches_border = false;
|
||||
let mut queue_cursor = 0usize;
|
||||
|
||||
while queue_cursor < hole_queue.len() {
|
||||
let pixel_index = hole_queue[queue_cursor];
|
||||
queue_cursor += 1;
|
||||
component.push(pixel_index);
|
||||
|
||||
let x = pixel_index % width;
|
||||
let y = pixel_index / width;
|
||||
if x == 0 || x == width.saturating_sub(1) || y == 0 || y == height.saturating_sub(1) {
|
||||
touches_border = true;
|
||||
}
|
||||
|
||||
let neighbors = [
|
||||
if x > 0 { Some(pixel_index - 1) } else { None },
|
||||
if x + 1 < width { Some(pixel_index + 1) } else { None },
|
||||
if y > 0 { Some(pixel_index - width) } else { None },
|
||||
if y + 1 < height { Some(pixel_index + width) } else { None },
|
||||
];
|
||||
|
||||
for next in neighbors.into_iter().flatten() {
|
||||
if background_mask[next] != 0 || hole_visited[next] {
|
||||
continue;
|
||||
}
|
||||
if key_scores[next] < GENERATED_ASSET_SHEET_GREEN_SCREEN_MIN_SCORE {
|
||||
continue;
|
||||
}
|
||||
hole_visited[next] = true;
|
||||
hole_queue.push(next);
|
||||
}
|
||||
}
|
||||
|
||||
if !touches_border && component.len() >= options.internal_hole_min_pixels {
|
||||
for pixel_index in component {
|
||||
background_mask[pixel_index] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let soft_green_cleanup_rounds = (width.min(height) / 40).clamp(4, 14);
|
||||
for _ in 0..soft_green_cleanup_rounds {
|
||||
let mut expanded_mask = background_mask.clone();
|
||||
|
||||
Reference in New Issue
Block a user