mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
✨ feat(figgos): clean peg-hole artifact from RMBG background removal
After RMBG + trim, apply white-threshold cleanup to the top 12% middle 50% of the card image to remove the hang-tab hole that RMBG sometimes preserves. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
072c37ae30
commit
3dd97a0e81
1 changed files with 42 additions and 3 deletions
|
|
@ -82,15 +82,54 @@ export class ImageProcessingService implements OnModuleInit {
|
||||||
await writeFile(tmpPath, inputBuffer);
|
await writeFile(tmpPath, inputBuffer);
|
||||||
const result = await this.segmenter(tmpPath);
|
const result = await this.segmenter(tmpPath);
|
||||||
const img = Array.isArray(result) ? result[0] : result;
|
const img = Array.isArray(result) ? result[0] : result;
|
||||||
const { data, width, height, channels } = img;
|
|
||||||
const buf = Buffer.from(data);
|
|
||||||
|
|
||||||
return sharp(buf, { raw: { width, height, channels } })
|
// Trim transparent borders first so peg-hole coordinates are accurate
|
||||||
|
const trimmed = await sharp(Buffer.from(img.data), {
|
||||||
|
raw: { width: img.width, height: img.height, channels: img.channels },
|
||||||
|
})
|
||||||
.trim()
|
.trim()
|
||||||
|
.ensureAlpha()
|
||||||
|
.raw()
|
||||||
|
.toBuffer({ resolveWithObject: true });
|
||||||
|
|
||||||
|
// RMBG sometimes keeps the peg hole (hang tab) at the top of the card.
|
||||||
|
// Apply white-threshold cleanup to the top 12%, middle 50% of the trimmed image.
|
||||||
|
this.cleanPegHole(trimmed.data, trimmed.info.width, trimmed.info.height);
|
||||||
|
|
||||||
|
return sharp(trimmed.data, {
|
||||||
|
raw: { width: trimmed.info.width, height: trimmed.info.height, channels: 4 },
|
||||||
|
})
|
||||||
.webp({ quality: 85 })
|
.webp({ quality: 85 })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
} finally {
|
} finally {
|
||||||
await unlink(tmpPath).catch(() => {});
|
await unlink(tmpPath).catch(() => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove leftover white pixels in the peg-hole region (top 12%, middle 50%).
|
||||||
|
* Same threshold logic as feathered method but scoped to that zone only.
|
||||||
|
*/
|
||||||
|
private cleanPegHole(data: Buffer, width: number, height: number): void {
|
||||||
|
const T = 240;
|
||||||
|
const F = 10;
|
||||||
|
const low = T - F;
|
||||||
|
|
||||||
|
const yEnd = Math.round(height * 0.12);
|
||||||
|
const xStart = Math.round(width * 0.25);
|
||||||
|
const xEnd = Math.round(width * 0.75);
|
||||||
|
|
||||||
|
for (let y = 0; y < yEnd; y++) {
|
||||||
|
for (let x = xStart; x < xEnd; x++) {
|
||||||
|
const i = (y * width + x) * 4;
|
||||||
|
if (data[i + 3] === 0) continue; // already transparent
|
||||||
|
const m = Math.min(data[i], data[i + 1], data[i + 2]);
|
||||||
|
if (m > T) {
|
||||||
|
data[i + 3] = 0;
|
||||||
|
} else if (m > low) {
|
||||||
|
data[i + 3] = Math.min(data[i + 3], Math.round((255 * (T - m)) / F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue