fix(jump-hop): clean magenta cutout fringes
This commit is contained in:
@@ -385,7 +385,13 @@ fn remove_generated_asset_sheet_green_screen_background(
|
||||
let mut red = pixels[offset] as f32;
|
||||
let mut green = pixels[offset + 1] as f32;
|
||||
let mut blue = pixels[offset + 2] as f32;
|
||||
let blend = clamp_generated_asset_sheet_unit(contamination.max(0.22));
|
||||
let blend = if options.key_color.is_green_screen() {
|
||||
clamp_generated_asset_sheet_unit(contamination.max(0.22))
|
||||
} else {
|
||||
// 中文注释:洋红 / 青色等非绿幕 key 的残留更容易表现成彩边,
|
||||
// 需要比绿幕更强地向主体邻近色收敛,避免 PNG 边缘继续带 key 色。
|
||||
clamp_generated_asset_sheet_unit((key_score * 1.35).max(contamination).max(0.28))
|
||||
};
|
||||
|
||||
if let Some((sample_red, sample_green, sample_blue)) = sample {
|
||||
red = lerp_generated_asset_sheet_channel(red, sample_red as f32, blend);
|
||||
@@ -400,6 +406,17 @@ fn remove_generated_asset_sheet_green_screen_background(
|
||||
green = green.min(sample_green as f32 + 26.0);
|
||||
blue = blue.min(sample_blue as f32 + 26.0);
|
||||
}
|
||||
if !options.key_color.is_green_screen() && key_score > 0.04 {
|
||||
let defringed = suppress_generated_asset_sheet_key_color_fringe(
|
||||
[red, green, blue],
|
||||
[sample_red as f32, sample_green as f32, sample_blue as f32],
|
||||
key_score,
|
||||
options.key_color,
|
||||
);
|
||||
red = defringed[0];
|
||||
green = defringed[1];
|
||||
blue = defringed[2];
|
||||
}
|
||||
} else {
|
||||
if options.key_color.is_green_screen() && key_score > 0.04 {
|
||||
let toned_green = (green - (green - red.max(blue)) * 0.78)
|
||||
@@ -417,10 +434,26 @@ fn remove_generated_asset_sheet_green_screen_background(
|
||||
blue = blue.min(toned_value);
|
||||
}
|
||||
}
|
||||
if !options.key_color.is_green_screen() && key_score > 0.04 {
|
||||
let neutral = (red + green + blue) / 3.0;
|
||||
let defringed = suppress_generated_asset_sheet_key_color_fringe(
|
||||
[red, green, blue],
|
||||
[neutral, neutral, neutral],
|
||||
key_score,
|
||||
options.key_color,
|
||||
);
|
||||
red = defringed[0];
|
||||
green = defringed[1];
|
||||
blue = defringed[2];
|
||||
}
|
||||
}
|
||||
|
||||
let mut next_alpha = alpha;
|
||||
let edge_fade = (key_score * 0.35).max(white_score * 0.28);
|
||||
let edge_fade = if options.key_color.is_green_screen() {
|
||||
(key_score * 0.35).max(white_score * 0.28)
|
||||
} else {
|
||||
(key_score * 0.48).max(white_score * 0.28)
|
||||
};
|
||||
if edge_fade > 0.08 {
|
||||
next_alpha = ((alpha as f32) * (1.0 - edge_fade)).round() as u8;
|
||||
if next_alpha < 10 {
|
||||
@@ -448,6 +481,37 @@ fn remove_generated_asset_sheet_green_screen_background(
|
||||
changed
|
||||
}
|
||||
|
||||
pub(super) fn suppress_generated_asset_sheet_key_color_fringe(
|
||||
color: [f32; 3],
|
||||
target: [f32; 3],
|
||||
key_score: f32,
|
||||
key_color: GeneratedAssetSheetKeyColor,
|
||||
) -> [f32; 3] {
|
||||
let strength = clamp_generated_asset_sheet_unit(key_score * 1.18);
|
||||
let key_channels = [
|
||||
key_color.red as f32 / 255.0,
|
||||
key_color.green as f32 / 255.0,
|
||||
key_color.blue as f32 / 255.0,
|
||||
];
|
||||
let mut next = color;
|
||||
|
||||
for index in 0..3 {
|
||||
if key_channels[index] >= 0.66 {
|
||||
let cap = target[index] + 18.0 + (1.0 - strength) * 28.0;
|
||||
next[index] = next[index].min(lerp_generated_asset_sheet_channel(
|
||||
next[index],
|
||||
cap,
|
||||
strength,
|
||||
));
|
||||
} else if key_channels[index] <= 0.34 {
|
||||
next[index] =
|
||||
lerp_generated_asset_sheet_channel(next[index], target[index], strength * 0.72);
|
||||
}
|
||||
}
|
||||
|
||||
next
|
||||
}
|
||||
|
||||
fn compute_generated_asset_sheet_key_score(
|
||||
pixel: [u8; 4],
|
||||
key_color: GeneratedAssetSheetKeyColor,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use super::alpha::{
|
||||
GeneratedAssetSheetAlphaOptions, apply_generated_asset_sheet_green_screen_alpha,
|
||||
suppress_generated_asset_sheet_key_color_fringe,
|
||||
};
|
||||
use super::color::{
|
||||
compute_generated_asset_sheet_key_color_score,
|
||||
clamp_generated_asset_sheet_unit, compute_generated_asset_sheet_key_color_score,
|
||||
compute_generated_asset_sheet_white_screen_score, is_generated_asset_sheet_foreground_pixel,
|
||||
is_generated_asset_sheet_green_contaminated_edge_pixel,
|
||||
is_generated_asset_sheet_soft_edge_pixel, is_generated_asset_sheet_strong_green_contamination,
|
||||
is_generated_asset_sheet_view_background_pixel, is_generated_asset_sheet_visible_pixel,
|
||||
touches_generated_asset_sheet_background_mask,
|
||||
lerp_generated_asset_sheet_channel, touches_generated_asset_sheet_background_mask,
|
||||
};
|
||||
use super::error::GeneratedAssetSheetError;
|
||||
use image::{GenericImageView, ImageFormat};
|
||||
@@ -588,11 +589,54 @@ fn remove_generated_asset_sheet_view_edge_matte(
|
||||
pixels[offset + 1],
|
||||
pixels[offset + 2],
|
||||
));
|
||||
let next_red = replacement.0.max(pixels[offset]);
|
||||
let next_blue = replacement.2.max(pixels[offset + 2]);
|
||||
let next_green = replacement
|
||||
.1
|
||||
.min(next_red.max(next_blue).saturating_add(12));
|
||||
let (next_red, next_green, next_blue) = if options.key_color.is_green_screen() {
|
||||
let next_red = replacement.0.max(pixels[offset]);
|
||||
let next_blue = replacement.2.max(pixels[offset + 2]);
|
||||
let next_green = replacement
|
||||
.1
|
||||
.min(next_red.max(next_blue).saturating_add(12));
|
||||
(next_red, next_green, next_blue)
|
||||
} else {
|
||||
let key_score = compute_generated_asset_sheet_key_color_score(
|
||||
pixel,
|
||||
[
|
||||
options.key_color.red,
|
||||
options.key_color.green,
|
||||
options.key_color.blue,
|
||||
],
|
||||
);
|
||||
let blend = clamp_generated_asset_sheet_unit((key_score * 1.25).max(0.36));
|
||||
let red = lerp_generated_asset_sheet_channel(
|
||||
pixels[offset] as f32,
|
||||
replacement.0 as f32,
|
||||
blend,
|
||||
);
|
||||
let green = lerp_generated_asset_sheet_channel(
|
||||
pixels[offset + 1] as f32,
|
||||
replacement.1 as f32,
|
||||
blend,
|
||||
);
|
||||
let blue = lerp_generated_asset_sheet_channel(
|
||||
pixels[offset + 2] as f32,
|
||||
replacement.2 as f32,
|
||||
blend,
|
||||
);
|
||||
let defringed = suppress_generated_asset_sheet_key_color_fringe(
|
||||
[red, green, blue],
|
||||
[
|
||||
replacement.0 as f32,
|
||||
replacement.1 as f32,
|
||||
replacement.2 as f32,
|
||||
],
|
||||
key_score,
|
||||
options.key_color,
|
||||
);
|
||||
(
|
||||
defringed[0].round().clamp(0.0, 255.0) as u8,
|
||||
defringed[1].round().clamp(0.0, 255.0) as u8,
|
||||
defringed[2].round().clamp(0.0, 255.0) as u8,
|
||||
)
|
||||
};
|
||||
if next_red != pixels[offset]
|
||||
|| next_green != pixels[offset + 1]
|
||||
|| next_blue != pixels[offset + 2]
|
||||
|
||||
Reference in New Issue
Block a user