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 key_color: GeneratedAssetSheetKeyColor,
|
||||||
pub remove_near_white_background: bool,
|
pub remove_near_white_background: bool,
|
||||||
pub remove_disconnected_hard_key_background: bool,
|
pub remove_disconnected_hard_key_background: bool,
|
||||||
|
// 中文注释:检测并清除被主体包围、不与画布四边连通的品红镂空区域。
|
||||||
|
// 仅对独立连通域整体判定,通过 min_pixels 过滤微小噪点。
|
||||||
|
pub detect_internal_holes: bool,
|
||||||
|
pub internal_hole_min_pixels: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeneratedAssetSheetAlphaOptions {
|
impl GeneratedAssetSheetAlphaOptions {
|
||||||
@@ -46,6 +50,8 @@ impl GeneratedAssetSheetAlphaOptions {
|
|||||||
key_color: GeneratedAssetSheetKeyColor::GREEN_SCREEN,
|
key_color: GeneratedAssetSheetKeyColor::GREEN_SCREEN,
|
||||||
remove_near_white_background: true,
|
remove_near_white_background: true,
|
||||||
remove_disconnected_hard_key_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,
|
key_color: GeneratedAssetSheetKeyColor::MAGENTA_SCREEN,
|
||||||
remove_near_white_background: false,
|
remove_near_white_background: false,
|
||||||
remove_disconnected_hard_key_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);
|
let soft_green_cleanup_rounds = (width.min(height) / 40).clamp(4, 14);
|
||||||
for _ in 0..soft_green_cleanup_rounds {
|
for _ in 0..soft_green_cleanup_rounds {
|
||||||
let mut expanded_mask = background_mask.clone();
|
let mut expanded_mask = background_mask.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user