接口11/12:固定 pushed 遮罩 + multiband 融合,移除其他算法选项
遮罩算法只保留 pushed(发际线外推),融合算法只保留 multiband(多频段金字塔), eroded/closed/feather/alpha_gradient/seamless 等旧选项从接口参数层移除。 - generate_hairline_grow: 删除 mask_type/blend_method/feather_px/color_match 参数, 内部固定 mask_type=pushed、blend_method=multiband - app.py 接口11/12: 删除 mask_type/blend_method/feather_px/color_match Form 参数, 调用处改关键字传参;grow_v2 只传 image+hairline_id 即默认走最新算法 - 前端两个测试页: 删除遮罩/融合下拉选项及相关联动,固定展示 pushed 步骤 - 文档: 更新为"固定 pushed + multiband,移除其他选项"
This commit is contained in:
@@ -113,32 +113,23 @@
|
||||
</div>
|
||||
|
||||
<div class="pf">
|
||||
<label>mask_type <span class="desc">遮罩类型</span></label>
|
||||
<select id="maskType">
|
||||
<option value="eroded">eroded(外缘内缩,默认)</option>
|
||||
<option value="closed">closed(闭合区域,未内缩)</option>
|
||||
<option value="pushed">pushed(发际线外推)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pf">
|
||||
<label>erode_cm <span class="desc">外缘内缩距离(cm)</span></label>
|
||||
<label>erode_cm <span class="desc">baseline参考内缩(cm)</span></label>
|
||||
<div class="row">
|
||||
<input type="number" id="erodeCm" min="0" max="5" step="0.1" value="1.2">
|
||||
<input type="range" id="erodeRange" min="0" max="3" step="0.1" value="1.2">
|
||||
<input type="number" id="erodeCm" min="0" max="5" step="0.1" value="0.6">
|
||||
<input type="range" id="erodeRange" min="0" max="3" step="0.1" value="0.6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pf" data-show="mask:pushed">
|
||||
<label>hairline_push_cm <span class="desc">发际线外推距离(仅pushed)</span></label>
|
||||
<div class="pf">
|
||||
<label>hairline_push_cm <span class="desc">发际线外推距离(cm)</span></label>
|
||||
<div class="row">
|
||||
<input type="number" id="hairlinePushCm" min="0" max="3" step="0.1" value="1.0">
|
||||
<input type="range" id="hairlinePushRange" min="0" max="3" step="0.1" value="1.0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pf" data-show="mask:pushed">
|
||||
<label>hairline_edge <span class="desc">发际线提取方式(仅pushed)</span></label>
|
||||
<div class="pf">
|
||||
<label>hairline_edge <span class="desc">发际线提取方式</span></label>
|
||||
<select id="hairlineEdge">
|
||||
<option value="column">column(逐列最低点,稳定)</option>
|
||||
<option value="contour">contour(形态学轮廓,精确)</option>
|
||||
@@ -146,30 +137,7 @@
|
||||
</div>
|
||||
|
||||
<div class="pf">
|
||||
<label>blend_method <span class="desc">接缝融合算法</span></label>
|
||||
<select id="blendMethod">
|
||||
<option value="feather">feather(高斯羽化,默认)</option>
|
||||
<option value="alpha_gradient">alpha_gradient(距离变换内渐变)</option>
|
||||
<option value="seamless">seamless(泊松无缝克隆)</option>
|
||||
<option value="multiband">multiband(多频段金字塔融合)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pf" data-show="blend:feather,alpha_gradient,multiband">
|
||||
<label>color_match <span class="desc">颜色校正前置</span></label>
|
||||
<div class="chk"><input type="checkbox" id="colorMatch"><span style="font-size:13px">融合前对生成图做 Reinhard 颜色校正(消除整体色差,seamless 自动跳过)</span></div>
|
||||
</div>
|
||||
|
||||
<div class="pf" data-show="blend:feather,alpha_gradient">
|
||||
<label>feather_px <span class="desc">羽化/渐变过渡宽度(px)</span></label>
|
||||
<div class="row">
|
||||
<input type="number" id="featherPx" min="1" max="80" step="1" value="15">
|
||||
<input type="range" id="featherRange" min="1" max="60" step="1" value="15">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pf" data-show="blend:multiband">
|
||||
<label>mb_levels <span class="desc">多频段金字塔层数(仅multiband)</span></label>
|
||||
<label>mb_levels <span class="desc">多频段金字塔层数</span></label>
|
||||
<div class="row">
|
||||
<input type="number" id="mbLevels" min="2" max="6" step="1" value="5">
|
||||
<input type="range" id="mbLevelsRange" min="2" max="6" step="1" value="5">
|
||||
@@ -291,9 +259,8 @@ function renderMetrics(d) {
|
||||
{ label: 'hairline_id', value: d.hairline_id },
|
||||
{ label: 'swap_mode', value: d.swap_mode },
|
||||
{ label: 'seg_model', value: d.seg_model },
|
||||
{ label: 'mask_type', value: d.mask_type },
|
||||
{ label: 'mask', value: d.mask_type },
|
||||
{ label: 'blend', value: d.blend_method },
|
||||
{ label: 'color_match', value: d.color_match },
|
||||
{ label: 'mb_levels', value: d.mb_levels },
|
||||
{ label: 'hairline_push', value: d.hairline_push_cm + 'cm' },
|
||||
{ label: 'hairline_edge', value: d.hairline_edge },
|
||||
@@ -317,12 +284,9 @@ function renderResult(d) {
|
||||
$('finalOut').onclick = function(){ zoom(this.src); };
|
||||
renderMetrics(d);
|
||||
const grid = $('stepsGrid'); grid.innerHTML = '';
|
||||
// 按 mask_type 过滤步骤:pushed 只显示 baseline/upper/头发分割/发际线/外推;
|
||||
// eroded/closed 只显示 baseline/upper/头发分割/填充/闭合,不显示发际线/外推。
|
||||
const mt = d.mask_type;
|
||||
const showKeys = new Set(['baseline_overlay','upper_overlay','hair_seg_overlay','mask_overlay','mask','swap_raw','hard_paste','alpha','final']);
|
||||
if (mt === 'pushed') { showKeys.add('hairline_overlay'); showKeys.add('pushed_overlay'); }
|
||||
else { showKeys.add('top_fill_overlay'); showKeys.add('closed_overlay'); }
|
||||
// 固定 pushed:只展示 pushed 相关步骤(不展示 top_fill/closed)
|
||||
const showKeys = new Set(['baseline_overlay','upper_overlay','hair_seg_overlay',
|
||||
'hairline_overlay','pushed_overlay','mask_overlay','mask','swap_raw','hard_paste','alpha','final']);
|
||||
STEPS.filter(st => showKeys.has(st.key)).forEach(st =>
|
||||
grid.appendChild(stepCard(st.title, st.sub, pick(s, st.key))));
|
||||
}
|
||||
@@ -343,18 +307,13 @@ async function submitTest() {
|
||||
form.append('hairgrow_strength', $('hgStrength').value || '0.75');
|
||||
form.append('is_hr', $('isHr').checked ? 'true' : 'false');
|
||||
form.append('seg_model', $('segModel').value);
|
||||
form.append('mask_type', $('maskType').value);
|
||||
form.append('erode_cm', $('erodeCm').value || '1.2');
|
||||
setStatus('正在请求 mask_type=' + $('maskType').value
|
||||
+ ' hairline_push_cm=' + ($('hairlinePushCm').value||'1.0')
|
||||
form.append('erode_cm', $('erodeCm').value || '0.6');
|
||||
setStatus('正在请求(固定 pushed + multiband) hairline_push_cm=' + ($('hairlinePushCm').value||'1.0')
|
||||
+ ' hairline_edge=' + $('hairlineEdge').value
|
||||
+ '(换发型走 GPU,约 10~15s)...', 'info');
|
||||
form.append('swap_mode', $('swapMode').value);
|
||||
form.append('blend_method', $('blendMethod').value);
|
||||
form.append('feather_px', $('featherPx').value || '15');
|
||||
form.append('edge_erode_px', $('edgeErodePx').value || '3');
|
||||
form.append('denoising_strength', $('denoise').value || '0.6');
|
||||
form.append('color_match', $('colorMatch').checked ? 'true' : 'false');
|
||||
form.append('mb_levels', $('mbLevels').value || '5');
|
||||
form.append('hairline_push_cm', $('hairlinePushCm').value || '1.0');
|
||||
form.append('hairline_edge', $('hairlineEdge').value);
|
||||
@@ -397,7 +356,7 @@ function copyJson() {
|
||||
}
|
||||
|
||||
// ---- 参数持久化 + 联动 ----
|
||||
const FIELDS = ['token','genBackend','hairlineId','swapMode','segModel','maskType','erodeCm','blendMethod','featherPx','edgeErodePx','denoise','hgStrength','mbLevels','hairlinePushCm','hairlineEdge'];
|
||||
const FIELDS = ['token','genBackend','hairlineId','swapMode','segModel','erodeCm','edgeErodePx','denoise','hgStrength','mbLevels','hairlinePushCm','hairlineEdge'];
|
||||
function saveField(id) { try { localStorage.setItem('if11_' + id, $(id).type === 'checkbox' ? ($(id).checked?'1':'0') : $(id).value); } catch(e){} }
|
||||
function linkNumRange(numId, rngId) {
|
||||
const num = $(numId), rng = $(rngId);
|
||||
@@ -419,42 +378,34 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
try { $('isHr').checked = localStorage.getItem('if11_isHr') === '1'; } catch(e){}
|
||||
$('isHr').addEventListener('change', () => saveField('isHr'));
|
||||
try { $('colorMatch').checked = localStorage.getItem('if11_colorMatch') === '1'; } catch(e){}
|
||||
$('colorMatch').addEventListener('change', () => saveField('colorMatch'));
|
||||
linkNumRange('erodeCm','erodeRange');
|
||||
linkNumRange('featherPx','featherRange');
|
||||
linkNumRange('edgeErodePx','edgeErodeRange');
|
||||
linkNumRange('denoise','denoiseRange');
|
||||
linkNumRange('hgStrength','hgStrengthRange');
|
||||
linkNumRange('mbLevels','mbLevelsRange');
|
||||
linkNumRange('hairlinePushCm','hairlinePushRange');
|
||||
// 初始化滑块值
|
||||
$('erodeRange').value = Math.min(3, parseFloat($('erodeCm').value)||1.2);
|
||||
$('featherRange').value = Math.min(60, parseFloat($('featherPx').value)||15);
|
||||
$('erodeRange').value = Math.min(3, parseFloat($('erodeCm').value)||0.6);
|
||||
$('edgeErodeRange').value = Math.min(30, parseFloat($('edgeErodePx').value)||3);
|
||||
$('denoiseRange').value = Math.min(1.0, parseFloat($('denoise').value)||0.6);
|
||||
$('hgStrengthRange').value = Math.min(1.0, parseFloat($('hgStrength').value)||0.75);
|
||||
$('mbLevelsRange').value = Math.min(6, Math.max(2, parseFloat($('mbLevels').value)||5));
|
||||
$('hairlinePushRange').value = Math.min(3, parseFloat($('hairlinePushCm').value)||1.0);
|
||||
|
||||
// 参数联动:按 gen_backend / blend_method 显隐无用参数(data-show 声明)
|
||||
// 参数联动:按 gen_backend 显隐无用参数(data-show 声明,遮罩/融合已固定无选项)
|
||||
function applyVisibility() {
|
||||
const gen = $('genBackend').value, bm = $('blendMethod').value, mt = $('maskType').value;
|
||||
const gen = $('genBackend').value;
|
||||
document.querySelectorAll('.pf[data-show]').forEach(el => {
|
||||
const conds = el.dataset.show.split(',').map(s => s.trim());
|
||||
let vis = true;
|
||||
conds.forEach(c => {
|
||||
const [k, v] = c.split(':');
|
||||
if (k === 'gen' && v !== gen) vis = false;
|
||||
if (k === 'blend' && v !== bm) vis = false;
|
||||
if (k === 'mask' && v !== mt) vis = false;
|
||||
});
|
||||
el.style.display = vis ? '' : 'none';
|
||||
});
|
||||
}
|
||||
$('genBackend').addEventListener('change', applyVisibility);
|
||||
$('blendMethod').addEventListener('change', applyVisibility);
|
||||
$('maskType').addEventListener('change', applyVisibility);
|
||||
applyVisibility();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<h1>接口11 调试页 <span style="font-size:13px;color:#888">(带前后端日志)</span></h1>
|
||||
<div class="subtitle">
|
||||
独立调试页,每一步都记录日志。提交后展开"前端日志"和"后端日志",点按钮可下载。<br>
|
||||
重点排查:mask_type 是否真的传成 pushed、①-f/①-g 是否有图、最终遮罩是否走了新算法。
|
||||
重点排查:遮罩是否走 pushed、①-f/①-g 是否有图、最终遮罩是否正确。遮罩固定 pushed、融合固定 multiband。
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@@ -68,14 +68,6 @@
|
||||
<input type="text" id="token" value="dev-shared-secret-2026" style="flex:1;min-width:200px;padding:8px;border:1px solid #ddd;border-radius:8px">
|
||||
</div>
|
||||
<div class="params">
|
||||
<div class="pf">
|
||||
<label>mask_type <span class="desc">遮罩类型(关键!)</span></label>
|
||||
<select id="maskType">
|
||||
<option value="eroded">eroded(外缘内缩)</option>
|
||||
<option value="closed">closed(闭合区域)</option>
|
||||
<option value="pushed">pushed(发际线外推)★</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pf">
|
||||
<label>发际线类型 ID</label>
|
||||
<select id="hairlineId">
|
||||
@@ -94,30 +86,30 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="pf">
|
||||
<label>erode_cm <span class="desc">外缘内缩(cm)</span></label>
|
||||
<div class="row"><input type="number" id="erodeCm" min="0" max="5" step="0.1" value="1.2"></div>
|
||||
<label>erode_cm <span class="desc">baseline参考内缩(cm)</span></label>
|
||||
<div class="row"><input type="number" id="erodeCm" min="0" max="5" step="0.1" value="0.6"></div>
|
||||
</div>
|
||||
<div class="pf" data-show="mask:pushed">
|
||||
<label>hairline_push_cm <span class="desc">发际线外推(cm,仅pushed)</span></label>
|
||||
<div class="pf">
|
||||
<label>hairline_push_cm <span class="desc">发际线外推(cm)</span></label>
|
||||
<div class="row"><input type="number" id="hairlinePushCm" min="0" max="3" step="0.1" value="1.0"></div>
|
||||
</div>
|
||||
<div class="pf" data-show="mask:pushed">
|
||||
<label>hairline_edge <span class="desc">发际线提取(仅pushed)</span></label>
|
||||
<div class="pf">
|
||||
<label>hairline_edge <span class="desc">发际线提取</span></label>
|
||||
<select id="hairlineEdge">
|
||||
<option value="column">column(逐列最低点)</option>
|
||||
<option value="contour">contour(形态学轮廓)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pf">
|
||||
<label>blend_method <span class="desc">融合算法</span></label>
|
||||
<select id="blendMethod">
|
||||
<option value="feather">feather</option>
|
||||
<option value="alpha_gradient">alpha_gradient</option>
|
||||
<option value="seamless">seamless</option>
|
||||
<option value="multiband">multiband</option>
|
||||
</select>
|
||||
<label>mb_levels <span class="desc">多频段金字塔层数</span></label>
|
||||
<div class="row"><input type="number" id="mbLevels" min="2" max="6" step="1" value="5"></div>
|
||||
</div>
|
||||
<div class="pf">
|
||||
<label>edge_erode_px <span class="desc">贴图前遮罩内缩(px)</span></label>
|
||||
<div class="row"><input type="number" id="edgeErodePx" min="0" max="40" step="1" value="3"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size:12px;color:#888;margin-top:8px">遮罩算法固定 pushed、融合固定 multiband,无需选择。</div>
|
||||
</div>
|
||||
|
||||
<div class="status hidden" id="statusBar"></div>
|
||||
@@ -202,19 +194,17 @@ function stepCard(title, sub, src) {
|
||||
}
|
||||
|
||||
function renderResult(d) {
|
||||
flog('renderResult 开始,mask_type=' + d.mask_type, 'info');
|
||||
flog('renderResult 开始(固定 pushed + multiband)', 'info');
|
||||
const s = d.steps || {};
|
||||
$('finalInput').src = pick(s, 'input') || '';
|
||||
$('finalInput').onclick = function(){ zoom(this.src); };
|
||||
$('finalOut').src = pick(s, 'final') || '';
|
||||
$('finalOut').onclick = function(){ zoom(this.src); };
|
||||
const grid = $('stepsGrid'); grid.innerHTML = '';
|
||||
// 按 mask_type 过滤步骤
|
||||
const mt = d.mask_type;
|
||||
const showKeys = new Set(['baseline_overlay','upper_overlay','hair_seg_overlay','mask_overlay','mask','swap_raw','hard_paste','alpha','final']);
|
||||
if (mt === 'pushed') { showKeys.add('hairline_overlay'); showKeys.add('pushed_overlay'); }
|
||||
else { showKeys.add('top_fill_overlay'); showKeys.add('closed_overlay'); }
|
||||
$('stepsInfo').textContent = '(mask_type=' + mt + ',按此过滤步骤)';
|
||||
// 固定 pushed:只展示 pushed 相关步骤(不展示 top_fill/closed)
|
||||
const showKeys = new Set(['baseline_overlay','upper_overlay','hair_seg_overlay',
|
||||
'hairline_overlay','pushed_overlay','mask_overlay','mask','swap_raw','hard_paste','alpha','final']);
|
||||
$('stepsInfo').textContent = '(固定 pushed + multiband)';
|
||||
STEPS.filter(st => showKeys.has(st.key)).forEach(st => {
|
||||
const src = pick(s, st.key);
|
||||
const hasImg = src && src.length > 50;
|
||||
@@ -229,16 +219,15 @@ async function submitTest() {
|
||||
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
||||
flog('===== 提交测试 =====', 'info');
|
||||
// 记录前端实际读取的每个参数值(关键诊断)
|
||||
const mt = $('maskType').value;
|
||||
flog('前端读取 mask_type=' + mt, 'info');
|
||||
flog('前端读取 hairline_push_cm=' + ($('hairlinePushCm').value || '(默认)'), 'info');
|
||||
flog('前端读取 hairline_edge=' + ($('hairlineEdge').value || '(默认)'), 'info');
|
||||
flog('前端读取 hairline_id=' + $('hairlineId').value, 'info');
|
||||
flog('前端读取 seg_model=' + $('segModel').value, 'info');
|
||||
flog('前端读取 mb_levels=' + ($('mbLevels').value || '(默认)'), 'info');
|
||||
|
||||
const btn = $('submitBtn');
|
||||
btn.disabled = true; btn.textContent = '⏳ 请求中...';
|
||||
setStatus('正在请求 mask_type=' + mt + ' ...', 'info');
|
||||
setStatus('正在请求(固定 pushed + multiband)...', 'info');
|
||||
$('resultsArea').classList.remove('hidden');
|
||||
|
||||
const form = new FormData();
|
||||
@@ -248,15 +237,11 @@ async function submitTest() {
|
||||
form.append('hairgrow_strength', '0.75');
|
||||
form.append('is_hr', 'false');
|
||||
form.append('seg_model', $('segModel').value);
|
||||
form.append('mask_type', mt);
|
||||
form.append('erode_cm', $('erodeCm').value || '1.2');
|
||||
form.append('erode_cm', $('erodeCm').value || '0.6');
|
||||
form.append('swap_mode', 'ext_mask');
|
||||
form.append('blend_method', $('blendMethod').value);
|
||||
form.append('feather_px', '15');
|
||||
form.append('edge_erode_px', '3');
|
||||
form.append('edge_erode_px', $('edgeErodePx').value || '3');
|
||||
form.append('denoising_strength', '0.6');
|
||||
form.append('color_match', 'false');
|
||||
form.append('mb_levels', '5');
|
||||
form.append('mb_levels', $('mbLevels').value || '5');
|
||||
form.append('hairline_push_cm', $('hairlinePushCm').value || '1.0');
|
||||
form.append('hairline_edge', $('hairlineEdge').value);
|
||||
|
||||
@@ -279,7 +264,7 @@ async function submitTest() {
|
||||
|
||||
if (json.code === 0) {
|
||||
const d = json.data;
|
||||
flog('后端返回 mask_type=' + d.mask_type + ' mask_pixels=' + d.mask_pixels, 'info');
|
||||
flog('后端返回 mask_type=' + d.mask_type + ' blend=' + d.blend_method + ' mask_pixels=' + d.mask_pixels, 'info');
|
||||
flog('后端返回 hairline_push_cm=' + d.hairline_push_cm + ' hairline_edge=' + d.hairline_edge, 'info');
|
||||
flog('后端 _rid=' + d._rid, 'info');
|
||||
// 详细记录 steps 每个字段长度
|
||||
@@ -327,20 +312,11 @@ async function downloadBackendLog() {
|
||||
}
|
||||
}
|
||||
|
||||
// 参数联动
|
||||
function applyVisibility() {
|
||||
const mt = $('maskType').value;
|
||||
document.querySelectorAll('.pf[data-show]').forEach(el => {
|
||||
const [k, v] = el.dataset.show.split(':');
|
||||
el.style.display = (k === 'mask' && v === mt) ? '' : 'none';
|
||||
});
|
||||
}
|
||||
$('maskType').addEventListener('change', function(){ flog('mask_type 切换为: ' + this.value, 'info'); applyVisibility(); });
|
||||
// 参数联动(遮罩/融合已固定,无下拉联动)
|
||||
$('imageFile').addEventListener('change', function(){ if(this.files.length) flog('选择图片: ' + this.files[0].name, 'info'); });
|
||||
|
||||
flog('调试页加载完成', 'info');
|
||||
flog('请选择图片,mask_type 切到 pushed,然后点提交', 'info');
|
||||
applyVisibility();
|
||||
flog('遮罩固定 pushed、融合固定 multiband,选好图片直接提交', 'info');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user