ai人物抠图与压扁特效实现如果你看扁我我就扁扁的走开
禁止任何形式的转载或商业使用html!DOCTYPE htmlhtml langzh-CNheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0, user-scalablenotitle如果你看扁我 · 我就扁扁的走开/title!-- 使用 xenova/transformers 的抠图模型 (通过 CDN) --script srchttps://cdn.jsdelivr.net/npm/xenova/transformers2.5.0/dist/transformers.min.js/scriptstyle* {margin: 0;padding: 0;box-sizing: border-box;}body {background: linear-gradient(145deg, #1a1e2c 0%, #2d3349 100%);min-height: 100vh;display: flex;justify-content: center;align-items: center;font-family: Segoe UI, PingFang SC, Roboto, system-ui, sans-serif;padding: 20px;}.card {max-width: 700px;width: 100%;background: rgba(255, 255, 255, 0.08);backdrop-filter: blur(4px);border-radius: 48px;padding: 30px 24px 40px;box-shadow: 0 25px 40px -12px rgba(0, 0, 0, 0.7);border: 1px solid rgba(255, 255, 255, 0.06);transition: all 0.2s;}h1 {text-align: center;font-weight: 600;font-size: 2.1rem;letter-spacing: 2px;color: #f2e9d0;text-shadow: 0 4px 12px rgba(0,0,0,0.5);margin-bottom: 12px;word-break: break-word;}.sub {text-align: center;color: #b5bdd6;margin-bottom: 28px;font-size: 0.95rem;opacity: 0.8;border-bottom: 1px dashed rgba(255,215,150,0.2);padding-bottom: 14px;}.upload-area {background: rgba(20, 24, 40, 0.6);border-radius: 36px;padding: 18px 20px;margin-bottom: 28px;border: 1px solid #4a516b;display: flex;align-items: center;justify-content: center;gap: 16px;flex-wrap: wrap;backdrop-filter: blur(2px);}.upload-area label {background: #5d6b8f;padding: 12px 28px;border-radius: 60px;color: white;font-weight: 500;cursor: pointer;transition: 0.2s;box-shadow: 0 6px 0 #343c54;border: 1px solid #8794b9;letter-spacing: 0.5px;display: inline-flex;align-items: center;gap: 8px;}.upload-area label:hover {background: #7384ae;transform: scale(0.97);box-shadow: 0 3px 0 #343c54;}.upload-area input[typefile] {display: none;}.status-badge {background: #2b3147;padding: 8px 22px;border-radius: 60px;color: #cfd7f0;font-size: 0.9rem;border: 1px solid #57607e;min-width: 120px;text-align: center;}.canvas-wrapper {background: #121624;border-radius: 40px;padding: 12px;box-shadow: inset 0 8px 18px rgba(0,0,0,0.7), 0 12px 24px rgba(0,0,0,0.5);margin: 16px 0 22px;border: 1px solid #3b425b;}#resultCanvas {display: block;width: 100%;height: auto;aspect-ratio: 1 / 1;background: #1e2335;border-radius: 32px;object-fit: contain;image-rendering: auto;box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.03);transition: 0.2s;}.action-bar {display: flex;justify-content: center;align-items: center;gap: 20px;flex-wrap: wrap;margin-top: 18px;}.btn {background: #3b4460;border: none;color: white;padding: 14px 32px;border-radius: 80px;font-weight: 600;font-size: 1rem;cursor: pointer;transition: 0.15s;box-shadow: 0 6px 0 #222838;border: 1px solid #5f6b8f;display: inline-flex;align-items: center;gap: 10px;letter-spacing: 0.8px;flex: 1 1 auto;justify-content: center;}.btn-primary {background: #b48b5a;border-color: #dbb57c;box-shadow: 0 6px 0 #765f3b;color: #1d1b16;}.btn-primary:hover {background: #cba16d;transform: scale(0.97);box-shadow: 0 3px 0 #765f3b;}.btn:active {transform: translateY(4px);box-shadow: 0 2px 0 #222838;}.btn:disabled {opacity: 0.5;transform: scale(0.96);pointer-events: none;filter: grayscale(0.4);}.footnote {text-align: center;margin-top: 28px;color: #8f98b6;font-size: 0.85rem;letter-spacing: 0.3px;border-top: 1px solid #2d344b;padding-top: 22px;}.footnote span {background: #282f47;padding: 4px 16px;border-radius: 60px;display: inline-block;border: 1px solid #3f4866;}media (max-width: 480px) {.card { padding: 20px 16px; }h1 { font-size: 1.8rem; }.upload-area { flex-direction: column; }}/style/headbodydiv classcardh1 如果你看扁我br我就扁扁的走开/h1div classsub上传图片 · 抠出人物 · 压扁特效/divdiv classupload-arealabel forimageInput 选择图片/labelinput typefile idimageInput acceptimage/*span classstatus-badge idstatusBadge⚪ 等待上传/span/divdiv classcanvas-wrappercanvas idresultCanvas width600 height600/canvas/divdiv classaction-barbutton classbtn btn-primary idprocessBtn✨ 看扁 TA/buttonbutton classbtn idresetBtn↺ 重置/button/divdiv classfootnotespan 上传后点击 “看扁 TA” · 人物压扁 扁扁走开/span/div/divscript(function() {// ---------- DOM 引用 ----------const canvas document.getElementById(resultCanvas);const ctx canvas.getContext(2d);const fileInput document.getElementById(imageInput);const statusBadge document.getElementById(statusBadge);const processBtn document.getElementById(processBtn);const resetBtn document.getElementById(resetBtn);// ---------- 状态 ----------let originalImage null; // 原始图片 (ImageData 或 Image 对象)let currentImageData null; // 当前显示的 ImageData (用于重置)let isProcessing false;// 默认占位图形 (显示提示)function drawPlaceholder() {ctx.clearRect(0, 0, 600, 600);// 暗色渐变背景const grad ctx.createRadialGradient(300, 300, 40, 300, 300, 380);grad.addColorStop(0, #39405e);grad.addColorStop(1, #1a1f2f);ctx.fillStyle grad;ctx.fillRect(0, 0, 600, 600);ctx.fillStyle #8c96b5;ctx.font 20px Segoe UI, system-ui, sans-serif;ctx.textAlign center;ctx.textBaseline middle;ctx.fillText( 上传一张带人物的图片, 300, 260);ctx.fillStyle #5d6890;ctx.font 15px sans-serif;ctx.fillText(然后点击 “看扁 TA”, 300, 330);// 画几个小扁人装饰ctx.fillStyle #b48b5a;ctx.beginPath();ctx.ellipse(120, 480, 26, 12, 0, 0, Math.PI * 2);ctx.fill();ctx.fillStyle #a0774a;ctx.beginPath();ctx.ellipse(500, 460, 32, 14, 0.2, 0, Math.PI * 2);ctx.fill();ctx.fillStyle #9e7a4e;ctx.beginPath();ctx.ellipse(340, 520, 20, 10, -0.1, 0, Math.PI * 2);ctx.fill();}drawPlaceholder();// ---------- 辅助: 读取图片为 ImageData ----------function loadImageToDataURL(file) {return new Promise((resolve, reject) {const reader new FileReader();reader.onload (e) resolve(e.target.result);reader.onerror reject;reader.readAsDataURL(file);});}function imageDataFromURL(url) {return new Promise((resolve, reject) {const img new Image();img.crossOrigin anonymous;img.onload () {// 缩放至 canvas 尺寸 (600x600)const tempCanvas document.createElement(canvas);tempCanvas.width 600;tempCanvas.height 600;const tempCtx tempCanvas.getContext(2d);// 保持比例居中裁剪const aspect img.width / img.height;let drawWidth, drawHeight, offsetX, offsetY;if (aspect 1) {drawHeight 600;drawWidth 600 * aspect;offsetX (drawWidth - 600) / -2;offsetY 0;} else {drawWidth 600;drawHeight 600 / aspect;offsetX 0;offsetY (drawHeight - 600) / -2;}tempCtx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight);const imageData tempCtx.getImageData(0, 0, 600, 600);resolve(imageData);};img.onerror reject;img.src url;});}// ---------- 抠图 压扁特效 (核心) ----------// 使用 xenova/transformers 的 rembg (u2net) 模型async function extractPersonAndSquash(imageData) {if (!imageData) throw new Error(没有图片数据);// 1. 使用 transformers 抠图 (人物分割)const pipeline await transformers.pipeline(image-segmentation, Xenova/rembg, {device: wasm,dtype: fp32,});// 将 ImageData 转为 blob URL 以输入 pipelineconst tempCanvas document.createElement(canvas);tempCanvas.width 600;tempCanvas.height 600;const tempCtx tempCanvas.getContext(2d);tempCtx.putImageData(imageData, 0, 0);const blob await new Promise(resolve tempCanvas.toBlob(resolve, image/png));const url URL.createObjectURL(blob);// 执行分割 (返回 mask)const segmentation await pipeline(url, { threshold: 0.5 });URL.revokeObjectURL(url);// segmentation 是一个数组, 取第一个 mask (背景/人物)const mask segmentation[0]?.mask;if (!mask) throw new Error(未检测到人物, 请换一张图片试试);// 2. 获得掩码数据 (像素级 0/1)const maskData mask.data; // Uint8Array, 0或1const width 600, height 600;const srcData imageData.data;// 3. 创建抠图结果 (保留人物, 背景透明)const outputData new Uint8ClampedArray(srcData.length);for (let i 0; i srcData.length; i 4) {const alpha maskData[i / 4] * 255; // 0或255outputData[i] srcData[i];outputData[i1] srcData[i1];outputData[i2] srcData[i2];outputData[i3] alpha;}// 4. 压扁特效 扁扁走开 (横向压扁 轻微位移)// 将人物压扁至原来的 60% 高度并稍微左右偏移 (模拟走开)const squashFactor 0.60; // 压扁比例const offsetX 40; // 向右扁扁走开 (可以调整为负值左移)// 创建新画布用于压扁const flatCanvas document.createElement(canvas);flatCanvas.width 600;flatCanvas.height 600;const flatCtx flatCanvas.getContext(2d);// 临时 ImageData 包含抠图结果const tempImageData new ImageData(outputData, width, height);const tempCanvas2 document.createElement(canvas);tempCanvas2.width width;tempCanvas2.height height;const tempCtx2 tempCanvas2.getContext(2d);tempCtx2.putImageData(tempImageData, 0, 0);// 清空 flatCanvasflatCtx.clearRect(0, 0, 600, 600);// 绘制压扁从原图提取人物缩放高度为 squashFactor宽度不变// 为了保证人物居中计算绘制位置 y 偏移 (压扁后垂直居中)const drawHeight 600 * squashFactor;const yOffset (600 - drawHeight) / 2;const xOffset offsetX; // 向右扁扁走// 绘制压扁的人物 (使用源图像)flatCtx.drawImage(tempCanvas2, 0, 0, 600, 600,xOffset, yOffset, 600, drawHeight);// 5. 将结果放回 canvas (带透明背景)const resultImageData flatCtx.getImageData(0, 0, 600, 600);return resultImageData;}// ---------- 更新 UI ----------function updateCanvasWithImageData(imageData) {if (!imageData) {drawPlaceholder();return;}ctx.putImageData(imageData, 0, 0);currentImageData imageData;}// 重置为原始图片 (如果存在)function resetToOriginal() {if (originalImage) {ctx.putImageData(originalImage, 0, 0);currentImageData originalImage;statusBadge.innerHTML 已重置;} else {drawPlaceholder();currentImageData null;statusBadge.innerHTML ⚪ 无图片;}}// ---------- 处理主流程 ----------async function handleProcess() {if (isProcessing) return;if (!originalImage) {statusBadge.innerHTML ⚠️ 请先上传图片;return;}isProcessing true;processBtn.disabled true;statusBadge.innerHTML ⏳ 抠图中... 请稍候 (AI 模型加载);try {// 执行抠图 压扁const result await extractPersonAndSquash(originalImage);ctx.putImageData(result, 0, 0);currentImageData result;statusBadge.innerHTML ✅ 扁扁的走开 ~ 压扁成功!;} catch (error) {console.error(error);statusBadge.innerHTML ❌ 错误: error.message;// 恢复原始if (originalImage) {ctx.putImageData(originalImage, 0, 0);currentImageData originalImage;} else {drawPlaceholder();}} finally {isProcessing false;processBtn.disabled false;}}// ---------- 上传处理 ----------fileInput.addEventListener(change, async (e) {const file e.target.files[0];if (!file) return;statusBadge.innerHTML 读取图片...;try {const dataURL await loadImageToDataURL(file);const imageData await imageDataFromURL(dataURL);// 保存原始originalImage imageData;currentImageData imageData;ctx.putImageData(imageData, 0, 0);statusBadge.innerHTML ✅ 已上传点击 “看扁 TA”;} catch (err) {console.error(err);statusBadge.innerHTML ⚠️ 图片加载失败;drawPlaceholder();originalImage null;currentImageData null;}// 清空 input 以便重复上传同一文件fileInput.value ;});// ---------- 按钮事件 ----------processBtn.addEventListener(click, handleProcess);resetBtn.addEventListener(click, () {if (isProcessing) return;resetToOriginal();statusBadge.innerHTML originalImage ? 已重置 : ⚪ 无图片;});// ---------- 额外: 拖拽上传支持 (可选) ----------// 简单防误触, 无拖拽// 预置演示: 画一个提示 (已画)})();/script/body/html核心功能一键抠图与压扁特效您只需上传图片点击按钮即可体验完整的处理流程。1. 图片上传与抠图点击“选择图片”上传您想处理的照片。代码会调用AI模型基于xenova/transformers库自动识别并抠出图片中的人物。2. 压扁与动画特效点击“看扁 TA”按钮程序会执行“压扁”操作将人物高度压缩至原来的60%并同时向右水平移动实现“扁扁的走开”的趣味效果。3. 状态提示与重置界面顶部的状态徽章会清晰显示当前操作进度如“抠图中。.。”。您随时可以点击“重置”按钮将图片恢复至原始状态。

相关新闻

最新新闻

日新闻

周新闻

月新闻