fix: preserve subject aspect in scale adjust
This commit is contained in:
parent
e22b6f11b9
commit
1ddb7928c6
@ -292,7 +292,15 @@ function scaleRectAroundCenter(
|
||||
rect: NormalizedLocalEditRegion["rect"],
|
||||
scalePercent: ScaleAdjustPercent
|
||||
) {
|
||||
const scale = Math.max(0.1, 1 + scalePercent / 100);
|
||||
const requestedScale = Math.max(0.1, 1 + scalePercent / 100);
|
||||
const maxUniformScale = Math.max(
|
||||
0.1,
|
||||
Math.min(
|
||||
rect.width > 0 ? 1 / rect.width : requestedScale,
|
||||
rect.height > 0 ? 1 / rect.height : requestedScale
|
||||
)
|
||||
);
|
||||
const scale = Math.min(requestedScale, maxUniformScale);
|
||||
const targetWidth = Math.min(1, rect.width * scale);
|
||||
const targetHeight = Math.min(1, rect.height * scale);
|
||||
const centerX = rect.x + rect.width / 2;
|
||||
@ -512,7 +520,7 @@ function buildScaleAdjustAnnotationSvg(params: {
|
||||
<text x="${clamp(source.left, badgeSize / 2 + 6, width - badgeSize / 2 - 6)}" y="${clamp(source.top, badgeSize / 2 + 6, height - badgeSize / 2 - 6) + smallFontSize * 0.38}" text-anchor="middle" fill="#ffffff" font-size="${smallFontSize}" font-family="Arial, Helvetica, sans-serif" font-weight="800">${region.index}</text>
|
||||
<rect x="${labelX}" y="${labelY}" width="${labelWidth}" height="${labelHeight}" rx="${Math.round(fontSize * 0.55)}" fill="#061017" opacity="0.86" stroke="${targetColor}" stroke-width="${Math.max(2, Math.round(strokeWidth * 0.5))}" />
|
||||
<text x="${labelX + Math.round(fontSize * 0.7)}" y="${labelY + Math.round(fontSize * 1.03)}" fill="#ffffff" font-size="${fontSize}" font-family="Arial, Helvetica, sans-serif" font-weight="800">目标:${escapeXml(actionLabel)},主体约 ${escapeXml(targetLabel)}</text>
|
||||
<text x="${labelX + Math.round(fontSize * 0.7)}" y="${labelY + Math.round(fontSize * 2.03)}" fill="${targetColor}" font-size="${smallFontSize}" font-family="Arial, Helvetica, sans-serif" font-weight="700">让主体轮廓接近虚线框,不要保持原红框大小</text>
|
||||
<text x="${labelX + Math.round(fontSize * 0.7)}" y="${labelY + Math.round(fontSize * 2.03)}" fill="${targetColor}" font-size="${smallFontSize}" font-family="Arial, Helvetica, sans-serif" font-weight="700">按主体原始宽高比等比变化,禁止拉伸变形</text>
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
@ -594,13 +602,13 @@ function buildScaleAdjustPrompt(
|
||||
const bottom = pixel.top + pixel.height;
|
||||
const centerX = pixel.left + Math.round(pixel.width / 2);
|
||||
const centerY = pixel.top + Math.round(pixel.height / 2);
|
||||
return `区域 ${region.index}(原始红色实线框:x=${left}%,y=${top}%,w=${width}%,h=${height}%;目标虚线框:x=${targetLeft}%,y=${targetTop}%,w=${targetWidth}%,h=${targetHeight}%;像素范围 left=${pixel.left}, top=${pixel.top}, right=${right}, bottom=${bottom}, center=(${centerX}, ${centerY})):红色实线框只是“寻找目标主体”的范围,不是要缩放或贴回的矩形补丁。请识别此范围内最主要的商品/物体主体,以主体自身轮廓和视觉中心为准,执行整体等比${actionLabel},目标主体最终外接轮廓必须接近第 1 张图中的青绿色/绿色虚线目标框,视觉尺寸约为原主体的 ${targetLabel}。如果框中只覆盖到主体的一部分,请根据连接关系推断该主体的完整可见结构,只调整该主体,不调整矩形框内背景。`;
|
||||
return `区域 ${region.index}(原始红色实线框:x=${left}%,y=${top}%,w=${width}%,h=${height}%;目标虚线框:x=${targetLeft}%,y=${targetTop}%,w=${targetWidth}%,h=${targetHeight}%;像素范围 left=${pixel.left}, top=${pixel.top}, right=${right}, bottom=${bottom}, center=(${centerX}, ${centerY})):红色实线框只是“寻找目标主体”的范围,不是要缩放或贴回的矩形补丁;目标虚线框只是表达目标尺寸范围,不是要求主体填满矩形或变成矩形比例。请识别此范围内最主要的商品/物体主体,以主体自身轮廓、原始宽高比和视觉中心为准,执行整体等比${actionLabel},宽度与高度必须使用同一个缩放倍率,目标主体视觉尺寸约为原主体的 ${targetLabel}。严禁宽度变窄但高度变高,严禁横向挤压、纵向拉伸或改变主体透视形体。如果框中只覆盖到主体的一部分,请根据连接关系推断该主体的完整可见结构,只调整该主体,不调整矩形框内背景。`;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
return [
|
||||
"输入图片1是定位参考图:它只用于告诉你用户框选的目标主体位置。输入图片1里的彩色框、编号、标签、半透明遮罩、文字和 UI 只是定位标记,绝不能出现在最终画面中。",
|
||||
"输入图片1中的红色实线框表示目标主体当前大致位置;青绿色或绿色虚线框表示比例调整后的目标视觉轮廓。最终画面不得出现这些框线,但目标主体大小必须接近虚线框所表达的新尺寸。",
|
||||
"输入图片1中的红色实线框表示目标主体当前大致位置;青绿色或绿色虚线框只表示比例调整后的安全尺寸范围。最终画面不得出现这些框线,主体也不需要填满虚线矩形;必须保持主体自身原始宽高比和透视形体。",
|
||||
"输入图片2是原始干净图,也是最终输出必须继承的唯一画面基底。如果系统或模型只能读取一张参考图,则必须使用输入图片1中的框选位置定位目标,同时主动去除所有定位标记并恢复干净画面。",
|
||||
"系统已根据用户框选区域计算出下方每个区域的原图坐标;框选区域只是定位目标主体的搜索范围,不是最终画面的裁切块、贴片或蒙版边界。",
|
||||
"最终结果必须保持原始干净图的画幅比例、构图边界、镜头透视、光线、色温、材质质感和清晰度。",
|
||||
@ -610,14 +618,15 @@ function buildScaleAdjustPrompt(
|
||||
regionLines,
|
||||
"",
|
||||
"关键要求:",
|
||||
`1. 只调整目标主体物体本身的整体视觉比例,必须等比缩放到约 ${targetLabel},不得保留原尺寸;请把主体轮廓宽度和高度都调整到约 ${targetLabel},并尽量贴近第 1 张图的虚线目标框,而不是仅改变亮度、清晰度、颜色或画面裁切。`,
|
||||
`1. 只调整目标主体物体本身的整体视觉比例,必须等比缩放到约 ${targetLabel},不得保留原尺寸;主体轮廓宽度和高度必须使用同一个倍率同步变化,宽高比必须与原主体一致,不能为了贴合虚线框而拉宽、压窄、拉高或压扁。`,
|
||||
"2. 严禁把整个矩形框选区域当成图片块整体缩放、平移、复制、裁切或贴回;最终画面不得出现矩形拼接边缘、色差硬边、补丁感、裁切线或局部贴片痕迹。",
|
||||
`3. 缩小时,目标主体应围绕原位置视觉中心自然变小到约 ${targetLabel};主体缩小后,原来被遮挡的背景、桌面、墙面、阴影、纹理和透视必须被重新生成并无缝补全,选区内应出现明显新增留白或背景。`,
|
||||
`4. 放大时,目标主体应围绕原位置视觉中心自然变大到约 ${targetLabel};主体边缘应越过原始红框并接近虚线目标框,边缘与遮挡关系要合理,不能变形,也不能产生突兀裁切。`,
|
||||
"5. 框选区域内非目标主体的背景、墙面、桌面、植物、文字和其它物体应保持原场景逻辑,不要跟着主体一起缩放。",
|
||||
"6. 未受比例调整影响的其它画面区域必须尽量保持原图不变,不允许整体重绘、改色、补光、移动物体或改变背景细节。",
|
||||
"7. 最终输出必须是一张完整、干净、无缝的照片,不得出现任何选区框、说明文字、对比线、比例数字或 UI 元素。",
|
||||
"8. 输出前自检:如果目标主体大小与原图相比没有明显变化,必须重新生成;禁止返回看起来和原图相同的结果。",
|
||||
`4. 放大时,目标主体应围绕原位置视觉中心自然变大到约 ${targetLabel};宽度和高度都要同步变大,不能出现“高度变高但宽度变窄”的非等比变形;主体边缘与遮挡关系要合理,不能产生突兀裁切。`,
|
||||
"5. 如果主体靠近画布边界导致目标尺寸空间不足,请用能完整放入画面的最大统一倍率整体缩放;绝不能为了塞进画面而只压缩宽度或只拉伸高度。",
|
||||
"6. 框选区域内非目标主体的背景、墙面、桌面、植物、文字和其它物体应保持原场景逻辑,不要跟着主体一起缩放。",
|
||||
"7. 未受比例调整影响的其它画面区域必须尽量保持原图不变,不允许整体重绘、改色、补光、移动物体或改变背景细节。",
|
||||
"8. 最终输出必须是一张完整、干净、无缝的照片,不得出现任何选区框、说明文字、对比线、比例数字或 UI 元素。",
|
||||
"9. 输出前自检:如果目标主体大小与原图相比没有明显变化,或者主体宽高比发生非等比变形,必须重新生成;禁止返回看起来和原图相同或被拉伸的结果。",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
@ -775,7 +784,7 @@ export async function POST(request: NextRequest) {
|
||||
: undefined,
|
||||
negativePrompt:
|
||||
isScaleAdjustOperation
|
||||
? "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、选区边框、白边、画幅压扁、画面拉伸、矩形贴片、硬边、拼接线、补丁感、局部裁切、色差边缘、背景断裂、主体未缩放、整块框选区域缩放"
|
||||
? "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、选区边框、白边、画幅压扁、画面拉伸、主体拉伸、主体压扁、主体变窄、主体变高但变窄、横向挤压、纵向拉伸、透视变形、矩形贴片、硬边、拼接线、补丁感、局部裁切、色差边缘、背景断裂、主体未缩放、整块框选区域缩放"
|
||||
: "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、选区边框、白边、画幅压扁、画面拉伸、主体截断、动物截断、缺头、缺尾巴、缺四肢、贴边裁切、矩形贴片、硬边、拼接线、补丁感、色差边缘、背景错位、地面纹理断裂、椅脚错位",
|
||||
prompt,
|
||||
promptExtend: false,
|
||||
|
||||
@ -859,6 +859,7 @@ function getDetailScaleAdjustRegionPrompt(scalePercent: DetailResultScalePercent
|
||||
const scaleVerb = scalePercent > 0 ? "放大" : "缩小";
|
||||
return [
|
||||
`对框选范围内的主物体执行等比${actionLabel},调整后主体视觉尺寸必须约为原来的 ${targetLabel},需要肉眼明显看出已经${scaleVerb}。`,
|
||||
"必须锁定主体自身原始宽高比和透视形体,宽度与高度用同一个倍率同步变化;严禁宽度变窄但高度变高、严禁横向挤压或纵向拉伸。",
|
||||
"只改变目标主体的尺寸,不改变主体外观、颜色、材质、图案和文字内容;不要把整个框选矩形当成图片块缩放。",
|
||||
scalePercent < 0
|
||||
? "主体缩小后露出的背景、桌面、墙面、阴影和遮挡关系必须自然补全。"
|
||||
|
||||
@ -266,7 +266,15 @@ function scaleRegionAroundCenter(
|
||||
region: CanvasLocalEditCompositeRegion,
|
||||
scalePercent: number
|
||||
): CanvasLocalEditCompositeRegion {
|
||||
const factor = Math.max(0.05, 1 + scalePercent / 100);
|
||||
const requestedFactor = Math.max(0.05, 1 + scalePercent / 100);
|
||||
const maxUniformFactor = Math.max(
|
||||
0.05,
|
||||
Math.min(
|
||||
region.width > 0 ? 1 / region.width : requestedFactor,
|
||||
region.height > 0 ? 1 / region.height : requestedFactor
|
||||
)
|
||||
);
|
||||
const factor = Math.min(requestedFactor, maxUniformFactor);
|
||||
let width = clampRatio(region.width * factor);
|
||||
let height = clampRatio(region.height * factor);
|
||||
const centerX = region.x + region.width / 2;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user