fix: exclude protected people from furniture scale masks
This commit is contained in:
parent
970bd89638
commit
fa7d9d81ff
@ -1356,6 +1356,24 @@ function isScaleAdjustFurnitureProductLikePrompt(prompt: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScaleAdjustProtectedPersonSide = "auto" | "left" | "right";
|
||||||
|
|
||||||
|
function getScaleAdjustProtectedPersonSide(
|
||||||
|
prompt: string
|
||||||
|
): ScaleAdjustProtectedPersonSide | null {
|
||||||
|
const text = normalizeScaleAdjustModelText(prompt);
|
||||||
|
if (
|
||||||
|
!/person|people|human|woman|man|model|girl|boy|face|body|人物|人像|人|模特|女人|男人|女孩|男孩|脸|身体/.test(
|
||||||
|
text
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (/right|右侧|右边|右方|右/.test(text)) return "right";
|
||||||
|
if (/left|左侧|左边|左方|左/.test(text)) return "left";
|
||||||
|
return "auto";
|
||||||
|
}
|
||||||
|
|
||||||
function hasScaleAdjustPersonPixelSignal(params: {
|
function hasScaleAdjustPersonPixelSignal(params: {
|
||||||
box: { left: number; top: number; width: number; height: number };
|
box: { left: number; top: number; width: number; height: number };
|
||||||
raw: Buffer;
|
raw: Buffer;
|
||||||
@ -1550,11 +1568,61 @@ function buildScaleAdjustStructureInitialMask(params: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildScaleAdjustProtectedPersonSeedMask(params: {
|
||||||
|
box: { left: number; top: number; width: number; height: number };
|
||||||
|
raw: Buffer;
|
||||||
|
side: ScaleAdjustProtectedPersonSide;
|
||||||
|
width: number;
|
||||||
|
}) {
|
||||||
|
const { box, raw, side, width } = params;
|
||||||
|
const seed = new Uint8Array(box.width * box.height);
|
||||||
|
let seedCount = 0;
|
||||||
|
const sideAllowsX = (localX: number) => {
|
||||||
|
if (side === "right") return localX >= box.width * 0.52;
|
||||||
|
if (side === "left") return localX <= box.width * 0.48;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let localY = 0; localY < box.height; localY += 1) {
|
||||||
|
const y = box.top + localY;
|
||||||
|
for (let localX = 0; localX < box.width; localX += 1) {
|
||||||
|
if (!sideAllowsX(localX)) continue;
|
||||||
|
const x = box.left + localX;
|
||||||
|
const rawIndex = getScaleAdjustRawPixelIndex(width, x, y);
|
||||||
|
const r = raw[rawIndex] || 0;
|
||||||
|
const g = raw[rawIndex + 1] || 0;
|
||||||
|
const b = raw[rawIndex + 2] || 0;
|
||||||
|
const { luma, saturation } = getScaleAdjustPixelStats(r, g, b);
|
||||||
|
const likelySkin = isScaleAdjustLikelySkinPixel(r, g, b);
|
||||||
|
const likelyWhiteFabric =
|
||||||
|
isScaleAdjustLikelyWhiteFabricPixel(r, g, b, luma, saturation) &&
|
||||||
|
luma < 246 &&
|
||||||
|
saturation < 0.22;
|
||||||
|
if (!likelySkin && !likelyWhiteFabric) continue;
|
||||||
|
seed[localY * box.width + localX] = 255;
|
||||||
|
seedCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const seedRatio = seedCount / Math.max(1, box.width * box.height);
|
||||||
|
if (seedCount < 24 || seedRatio < 0.0006) return null;
|
||||||
|
|
||||||
|
return dilateScaleAdjustStructureMask({
|
||||||
|
height: box.height,
|
||||||
|
mask: seed,
|
||||||
|
radius: Math.max(4, Math.round(Math.min(box.width, box.height) * 0.032)),
|
||||||
|
width: box.width,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function filterScaleAdjustStructureComponents(params: {
|
function filterScaleAdjustStructureComponents(params: {
|
||||||
box: { width: number; height: number };
|
box: { width: number; height: number };
|
||||||
mask: Uint8Array;
|
mask: Uint8Array;
|
||||||
|
protectedPersonMask?: Uint8Array | null;
|
||||||
|
protectedPersonSide?: ScaleAdjustProtectedPersonSide | null;
|
||||||
}) {
|
}) {
|
||||||
const { box, mask } = params;
|
const { box, mask, protectedPersonMask = null, protectedPersonSide = null } =
|
||||||
|
params;
|
||||||
const width = box.width;
|
const width = box.width;
|
||||||
const height = box.height;
|
const height = box.height;
|
||||||
const visited = new Uint8Array(mask.length);
|
const visited = new Uint8Array(mask.length);
|
||||||
@ -1582,6 +1650,7 @@ function filterScaleAdjustStructureComponents(params: {
|
|||||||
let minY = y;
|
let minY = y;
|
||||||
let maxX = x;
|
let maxX = x;
|
||||||
let maxY = y;
|
let maxY = y;
|
||||||
|
let protectedPersonOverlap = 0;
|
||||||
|
|
||||||
while (head < queueX.length) {
|
while (head < queueX.length) {
|
||||||
const cx = queueX[head] || 0;
|
const cx = queueX[head] || 0;
|
||||||
@ -1592,6 +1661,9 @@ function filterScaleAdjustStructureComponents(params: {
|
|||||||
minY = Math.min(minY, cy);
|
minY = Math.min(minY, cy);
|
||||||
maxX = Math.max(maxX, cx);
|
maxX = Math.max(maxX, cx);
|
||||||
maxY = Math.max(maxY, cy);
|
maxY = Math.max(maxY, cy);
|
||||||
|
if (protectedPersonMask?.[cy * width + cx]) {
|
||||||
|
protectedPersonOverlap += 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (let dy = -1; dy <= 1; dy += 1) {
|
for (let dy = -1; dy <= 1; dy += 1) {
|
||||||
for (let dx = -1; dx <= 1; dx += 1) {
|
for (let dx = -1; dx <= 1; dx += 1) {
|
||||||
@ -1616,7 +1688,27 @@ function filterScaleAdjustStructureComponents(params: {
|
|||||||
const centerYRatio = (minY + componentHeight / 2) / height;
|
const centerYRatio = (minY + componentHeight / 2) / height;
|
||||||
const touchesTop = minY <= height * 0.04;
|
const touchesTop = minY <= height * 0.04;
|
||||||
const touchesRight = maxX >= width * 0.88;
|
const touchesRight = maxX >= width * 0.88;
|
||||||
|
const touchesLeft = minX <= width * 0.12;
|
||||||
const edgeSliver = touchesRight && componentWidth < width * 0.18;
|
const edgeSliver = touchesRight && componentWidth < width * 0.18;
|
||||||
|
const touchesProtectedPersonSide =
|
||||||
|
protectedPersonSide === "right"
|
||||||
|
? maxX >= width * 0.68
|
||||||
|
: protectedPersonSide === "left"
|
||||||
|
? minX <= width * 0.32
|
||||||
|
: protectedPersonSide === "auto"
|
||||||
|
? touchesLeft || touchesRight
|
||||||
|
: false;
|
||||||
|
const protectedPersonOverlapRatio =
|
||||||
|
protectedPersonOverlap / Math.max(1, area);
|
||||||
|
const likelyProtectedPersonComponent =
|
||||||
|
Boolean(protectedPersonMask) &&
|
||||||
|
protectedPersonOverlap > 0 &&
|
||||||
|
(protectedPersonOverlapRatio >= 0.012 ||
|
||||||
|
(touchesProtectedPersonSide &&
|
||||||
|
protectedPersonOverlap >= Math.max(6, area * 0.002))) &&
|
||||||
|
(touchesProtectedPersonSide ||
|
||||||
|
componentHeight >= height * 0.16 ||
|
||||||
|
componentWidth >= width * 0.16);
|
||||||
const broadTopBackground =
|
const broadTopBackground =
|
||||||
touchesTop &&
|
touchesTop &&
|
||||||
centerYRatio <= 0.45 &&
|
centerYRatio <= 0.45 &&
|
||||||
@ -1642,7 +1734,8 @@ function filterScaleAdjustStructureComponents(params: {
|
|||||||
likelyStructure &&
|
likelyStructure &&
|
||||||
centeredEnough &&
|
centeredEnough &&
|
||||||
!edgeSliver &&
|
!edgeSliver &&
|
||||||
!broadTopBackground
|
!broadTopBackground &&
|
||||||
|
!likelyProtectedPersonComponent
|
||||||
) {
|
) {
|
||||||
if (fillSurfaceComponent) {
|
if (fillSurfaceComponent) {
|
||||||
for (let fillY = minY; fillY <= maxY; fillY += 1) {
|
for (let fillY = minY; fillY <= maxY; fillY += 1) {
|
||||||
@ -2446,6 +2539,7 @@ async function buildScaleAdjustStructureLockedComposite(params: {
|
|||||||
includePersonPixels?: boolean;
|
includePersonPixels?: boolean;
|
||||||
placement: ReturnType<typeof getScaleAdjustVisualGuidePlacement>;
|
placement: ReturnType<typeof getScaleAdjustVisualGuidePlacement>;
|
||||||
preferPixelStructure?: boolean;
|
preferPixelStructure?: boolean;
|
||||||
|
protectedPersonSide?: ScaleAdjustProtectedPersonSide | null;
|
||||||
raw: Buffer;
|
raw: Buffer;
|
||||||
sourceBuffer: Buffer;
|
sourceBuffer: Buffer;
|
||||||
sourceImageUrl?: string;
|
sourceImageUrl?: string;
|
||||||
@ -2456,6 +2550,7 @@ async function buildScaleAdjustStructureLockedComposite(params: {
|
|||||||
includePersonPixels = false,
|
includePersonPixels = false,
|
||||||
placement,
|
placement,
|
||||||
preferPixelStructure = false,
|
preferPixelStructure = false,
|
||||||
|
protectedPersonSide = null,
|
||||||
raw,
|
raw,
|
||||||
sourceBuffer,
|
sourceBuffer,
|
||||||
sourceImageUrl,
|
sourceImageUrl,
|
||||||
@ -2487,9 +2582,20 @@ async function buildScaleAdjustStructureLockedComposite(params: {
|
|||||||
raw,
|
raw,
|
||||||
width: sourceWidth,
|
width: sourceWidth,
|
||||||
});
|
});
|
||||||
|
const protectedPersonMask =
|
||||||
|
preferPixelStructure && protectedPersonSide
|
||||||
|
? buildScaleAdjustProtectedPersonSeedMask({
|
||||||
|
box: placement.sourceBox,
|
||||||
|
raw,
|
||||||
|
side: protectedPersonSide,
|
||||||
|
width: sourceWidth,
|
||||||
|
})
|
||||||
|
: null;
|
||||||
const mask = filterScaleAdjustStructureComponents({
|
const mask = filterScaleAdjustStructureComponents({
|
||||||
box: placement.sourceBox,
|
box: placement.sourceBox,
|
||||||
mask: initialMask,
|
mask: initialMask,
|
||||||
|
protectedPersonMask,
|
||||||
|
protectedPersonSide,
|
||||||
});
|
});
|
||||||
const structureBbox = getScaleAdjustMaskBoundingBox({
|
const structureBbox = getScaleAdjustMaskBoundingBox({
|
||||||
height: placement.sourceBox.height,
|
height: placement.sourceBox.height,
|
||||||
@ -2781,6 +2887,9 @@ async function buildScaleAdjustVisualLayoutGuideBuffer(params: {
|
|||||||
const preferPixelStructure = isScaleAdjustFurnitureProductLikePrompt(
|
const preferPixelStructure = isScaleAdjustFurnitureProductLikePrompt(
|
||||||
region.prompt
|
region.prompt
|
||||||
);
|
);
|
||||||
|
const protectedPersonSide = preferPixelStructure
|
||||||
|
? getScaleAdjustProtectedPersonSide(region.prompt)
|
||||||
|
: null;
|
||||||
const hasPersonPixels =
|
const hasPersonPixels =
|
||||||
!preferPixelStructure &&
|
!preferPixelStructure &&
|
||||||
!!sourceRaw &&
|
!!sourceRaw &&
|
||||||
@ -2797,6 +2906,7 @@ async function buildScaleAdjustVisualLayoutGuideBuffer(params: {
|
|||||||
includePersonPixels,
|
includePersonPixels,
|
||||||
placement,
|
placement,
|
||||||
preferPixelStructure,
|
preferPixelStructure,
|
||||||
|
protectedPersonSide,
|
||||||
raw: sourceRaw,
|
raw: sourceRaw,
|
||||||
sourceBuffer,
|
sourceBuffer,
|
||||||
sourceImageUrl,
|
sourceImageUrl,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user