<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能抠图工具 - 一键去除背景</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
min-height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
color: white;
}
.container {
width: 100%;
max-width: 1200px;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
padding: 20px;
animation: fadeIn 1s ease;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.subtitle {
font-size: 1.2rem;
opacity: 0.9;
max-width: 600px;
margin: 0 auto;
}
.app-container {
display: flex;
flex-wrap: wrap;
gap: 30px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
.upload-section {
flex: 1;
min-width: 300px;
display: flex;
flex-direction: column;
gap: 20px;
}
.preview-section {
flex: 1;
min-width: 300px;
display: flex;
flex-direction: column;
gap: 20px;
}
.section-title {
font-size: 1.3rem;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 10px;
}
.section-title i {
font-size: 1.5rem;
}
.drop-area {
border: 3px dashed rgba(255, 255, 255, 0.5);
border-radius: 15px;
padding: 40px 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.05);
}
.drop-area:hover, .drop-area.active {
border-color: #fff;
background: rgba(255, 255, 255, 0.1);
}
.drop-area i {
font-size: 3rem;
margin-bottom: 15px;
color: rgba(255, 255, 255, 0.7);
}
.drop-area p {
margin: 10px 0;
}
.file-input {
display: none;
}
.btn {
background: linear-gradient(45deg, #ff8a00, #ff2070);
color: white;
border: none;
padding: 12px 25px;
font-size: 1rem;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 600;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
box-shadow: 0 4px 15px rgba(255, 138, 0, 0.3);
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 7px 20px rgba(255, 138, 0, 0.4);
}
.btn:active {
transform: translateY(0);
}
.btn-outline {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.5);
box-shadow: none;
}
.btn-outline:hover {
background: rgba(255, 255, 255, 0.1);
}
.preview-container {
display: flex;
flex-direction: column;
gap: 20px;
}
.preview-box {
position: relative;
width: 100%;
height: 250px;
border-radius: 15px;
overflow: hidden;
background: rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(255, 255, 255, 0.1);
}
.preview-box img, .preview-box canvas {
max-width: 100%;
max-height: 100%;
display: none;
}
.preview-placeholder {
text-align: center;
color: rgba(255, 255, 255, 0.5);
}
.controls {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.tolerance-control {
flex: 1;
min-width: 200px;
}
.tolerance-label {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}
.slider {
width: 100%;
height: 10px;
-webkit-appearance: none;
background: rgba(255, 255, 255, 0.1);
border-radius: 5px;
outline: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #ff8a00;
cursor: pointer;
}
.tolerance-value {
background: rgba(255, 255, 255, 0.1);
padding: 2px 10px;
border-radius: 10px;
min-width: 40px;
text-align: center;
}
.result-actions {
display: flex;
gap: 15px;
margin-top: 10px;
}
.info-box {
background: rgba(0, 0, 0, 0.2);
border-radius: 15px;
padding: 20px;
margin-top: 30px;
font-size: 0.9rem;
}
.info-box h3 {
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 10px;
}
.info-content {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.info-item {
flex: 1;
min-width: 250px;
}
.info-item ul {
padding-left: 20px;
margin-top: 10px;
}
.info-item li {
margin-bottom: 8px;
}
footer {
text-align: center;
margin-top: 40px;
padding: 20px;
color: rgba(255, 255, 255, 0.7);
font-size: 0.9rem;
}
.loading {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
border-radius: 15px;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top: 5px solid #ff8a00;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
.featured-examples {
display: flex;
gap: 20px;
margin-top: 15px;
justify-content: center;
flex-wrap: wrap;
}
.example-item {
width: 80px;
height: 80px;
border-radius: 10px;
overflow: hidden;
cursor: pointer;
border: 2px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
}
.example-item:hover {
transform: scale(1.05);
border-color: white;
}
.example-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
@media (max-width: 768px) {
.app-container {
flex-direction: column;
}
.controls {
flex-direction: column;
}
h1 {
font-size: 2rem;
}
}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<div class="container">
<header>
<h1><i class="fas fa-magic"></i> 智能抠图工具</h1>
<p class="subtitle">上传图片,一键自动去除背景 - 无需复杂操作,快速获得透明背景PNG图片</p>
</header>
<div class="app-container">
<div class="upload-section">
<h2 class="section-title"><i class="fas fa-upload"></i> 上传图片</h2>
<div class="drop-area" id="dropArea">
<i class="fas fa-cloud-upload-alt"></i>
<p>拖放图片到此处或</p>
<button class="btn" id="browseBtn"><i class="fas fa-folder-open"></i> 选择图片</button>
<p class="small">支持 JPG, PNG 格式,最大 5MB</p>
</div>
<input type="file" id="fileInput" class="file-input" accept="image/*">
<div class="featured-examples">
<div class="example-item" data-example="1">
<img src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例1">
</div>
<div class="example-item" data-example="2">
<img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例2">
</div>
<div class="example-item" data-example="3">
<img src="https://images.unsplash.com/photo-1533738363-b7f9aef128ce?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例3">
</div>
<div class="example-item" data-example="4">
<img src="https://images.unsplash.com/photo-1526336024174-e58f5cdd8e13?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例4">
</div>
</div>
</div>
<div class="preview-section">
<h2 class="section-title"><i class="fas fa-image"></i> 预览结果</h2>
<div class="preview-container">
<div class="preview-box">
<div class="preview-placeholder">
<i class="fas fa-image" style="font-size: 3rem; margin-bottom: 15px;"></i>
<p>处理后的图像将显示在这里</p>
</div>
<canvas id="originalCanvas"></canvas>
<canvas id="resultCanvas"></canvas>
<div class="loading" id="loading">
<div class="spinner"></div>
<p>正在处理图像...</p>
</div>
</div>
<div class="controls">
<div class="tolerance-control">
<div class="tolerance-label">
<span>抠图精度调节:</span>
<span class="tolerance-value" id="toleranceValue">30</span>
</div>
<input type="range" min="1" max="100" value="30" class="slider" id="toleranceSlider">
<p style="font-size: 0.8rem; margin-top: 5px; opacity: 0.7;">值越小,抠图越精细(处理时间越长)</p>
</div>
<button class="btn" id="processBtn"><i class="fas fa-cogs"></i> 开始抠图</button>
</div>
<div class="result-actions">
<button class="btn" id="downloadBtn" disabled><i class="fas fa-download"></i> 下载结果</button>
<button class="btn btn-outline" id="resetBtn"><i class="fas fa-redo"></i> 重置</button>
</div>
</div>
</div>
</div>
<div class="info-box">
<h3><i class="fas fa-info-circle"></i> 使用说明</h3>
<div class="info-content">
<div class="info-item">
<h4>如何获得最佳效果:</h4>
<ul>
<li>选择主体与背景对比度高的图片</li>
<li>避免复杂背景或毛发等细节丰富的图像</li>
<li>如果效果不理想,尝试调整抠图精度</li>
<li>对于人像照片效果最佳</li>
</ul>
</div>
<div class="info-item">
<h4>技术说明:</h4>
<ul>
<li>使用HTML5 Canvas实现纯前端处理</li>
<li>基于智能颜色识别算法</li>
<li>处理时间取决于图像大小和复杂度</li>
<li>完全在浏览器中运行 - 不上传服务器</li>
</ul>
</div>
</div>
</div>
</div>
<footer>
<p>© 2023 智能抠图工具 | 纯前端实现 | 无需上传服务器 | 保护您的隐私</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取DOM元素
const dropArea = document.getElementById('dropArea');
const fileInput = document.getElementById('fileInput');
const browseBtn = document.getElementById('browseBtn');
const processBtn = document.getElementById('processBtn');
const downloadBtn = document.getElementById('downloadBtn');
const resetBtn = document.getElementById('resetBtn');
const toleranceSlider = document.getElementById('toleranceSlider');
const toleranceValue = document.getElementById('toleranceValue');
const originalCanvas = document.getElementById('originalCanvas');
const resultCanvas = document.getElementById('resultCanvas');
const loading = document.getElementById('loading');
const previewPlaceholder = document.querySelector('.preview-placeholder');
let originalImage = null;
let processedImage = null;
// 设置事件监听器
browseBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
dropArea.addEventListener('dragover', handleDragOver);
dropArea.addEventListener('dragleave', handleDragLeave);
dropArea.addEventListener('drop', handleDrop);
processBtn.addEventListener('click', processImage);
downloadBtn.addEventListener('click', downloadResult);
resetBtn.addEventListener('click', resetApp);
toleranceSlider.addEventListener('input', updateTolerance);
// 示例图片点击事件
document.querySelectorAll('.example-item').forEach(item => {
item.addEventListener('click', function() {
const exampleNum = this.getAttribute('data-example');
loadExample(exampleNum);
});
});
// 更新容差值显示
function updateTolerance() {
toleranceValue.textContent = toleranceSlider.value;
}
// 处理文件选择
function handleFileSelect(e) {
const file = e.target.files[0];
if (file && file.type.match('image.*')) {
loadImage(file);
}
}
// 处理拖放
function handleDragOver(e) {
e.preventDefault();
e.stopPropagation();
dropArea.classList.add('active');
}
function handleDragLeave(e) {
e.preventDefault();
e.stopPropagation();
dropArea.classList.remove('active');
}
function handleDrop(e) {
e.preventDefault();
e.stopPropagation();
dropArea.classList.remove('active');
const file = e.dataTransfer.files[0];
if (file && file.type.match('image.*')) {
loadImage(file);
}
}
// 加载图片
function loadImage(file) {
const reader = new FileReader();
reader.onload = function(e) {
originalImage = new Image();
originalImage.onload = function() {
// 显示原始图片
displayOriginalImage();
processBtn.disabled = false;
};
originalImage.src = e.target.result;
};
reader.readAsDataURL(file);
}
// 加载示例图片
function loadExample(num) {
const examples = {
'1': 'https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80',
'2': 'https://images.unsplash.com/photo-1543852786-1cf6624b9987?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80',
'3': 'https://images.unsplash.com/photo-1533738363-b7f9aef128ce?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80',
'4': 'https://images.unsplash.com/photo-1526336024174-e58f5cdd8e13?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80'
};
originalImage = new Image();
originalImage.crossOrigin = "Anonymous";
originalImage.onload = function() {
displayOriginalImage();
processBtn.disabled = false;
};
originalImage.src = examples[num];
}
// 显示原始图片
function displayOriginalImage() {
const previewBox = document.querySelector('.preview-box');
previewPlaceholder.style.display = 'none';
// 设置canvas尺寸
const maxWidth = previewBox.clientWidth - 20;
const maxHeight = previewBox.clientHeight - 20;
let width = originalImage.width;
let height = originalImage.height;
if (width > maxWidth) {
height = (maxWidth / width) * height;
width = maxWidth;
}
if (height > maxHeight) {
width = (maxHeight / height) * width;
height = maxHeight;
}
originalCanvas.width = width;
originalCanvas.height = height;
resultCanvas.width = width;
resultCanvas.height = height;
const ctx = originalCanvas.getContext('2d');
ctx.clearRect(0, 0, width, height);
ctx.drawImage(originalImage, 0, 0, width, height);
originalCanvas.style.display = 'block';
}
// 处理图像(抠图)
function processImage() {
if (!originalImage) return;
// 显示加载状态
loading.style.display = 'flex';
downloadBtn.disabled = true;
// 使用setTimeout让UI有机会更新
setTimeout(() => {
try {
const tolerance = parseInt(toleranceSlider.value);
removeBackground(tolerance);
// 显示结果
originalCanvas.style.display = 'none';
resultCanvas.style.display = 'block';
downloadBtn.disabled = false;
} catch (error) {
console.error('Error processing image:', error);
alert('处理图像时出错: ' + error.message);
} finally {
loading.style.display = 'none';
}
}, 100);
}
// 移除背景的核心算法
function removeBackground(tolerance) {
const ctx = originalCanvas.getContext('2d');
const resultCtx = resultCanvas.getContext('2d');
// 获取图像数据
const imageData = ctx.getImageData(0, 0, originalCanvas.width, originalCanvas.height);
const data = imageData.data;
// 创建新图像数据(带透明通道)
const newData = new ImageData(originalCanvas.width, originalCanvas.height);
const newPixels = newData.data;
// 假设图片中心点属于前景
const centerX = Math.floor(originalCanvas.width / 2);
const centerY = Math.floor(originalCanvas.height / 2);
const centerIndex = (centerY * originalCanvas.width + centerX) * 4;
// 获取中心点颜色作为前景参考
const centerR = data[centerIndex];
const centerG = data[centerIndex + 1];
const centerB = data[centerIndex + 2];
// 处理每个像素
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// 计算与中心点的颜色差异
const diff = Math.sqrt(
Math.pow(r - centerR, 2) +
Math.pow(g - centerG, 2) +
Math.pow(b - centerB, 2)
);
// 如果颜色差异在容差范围内,保留像素,否则设为透明
if (diff < tolerance) {
newPixels[i] = r;
newPixels[i + 1] = g;
newPixels[i + 2] = b;
newPixels[i + 3] = 255; // 不透明
} else {
newPixels[i] = 0;
newPixels[i + 1] = 0;
newPixels[i + 2] = 0;
newPixels[i + 3] = 0; // 完全透明
}
}
// 将新图像数据绘制到结果canvas
resultCtx.putImageData(newData, 0, 0);
}
// 下载结果
function downloadResult() {
if (!resultCanvas) return;
const link = document.createElement('a');
link.download = '抠图结果.png';
link.href = resultCanvas.toDataURL('image/png');
link.click();
}
// 重置应用
function resetApp() {
// 重置所有状态
originalImage = null;
processedImage = null;
// 隐藏canvas
originalCanvas.style.display = 'none';
resultCanvas.style.display = 'none';
// 显示占位符
previewPlaceholder.style.display = 'flex';
// 重置按钮状态
processBtn.disabled = true;
downloadBtn.disabled = true;
// 重置文件输入
fileInput.value = '';
}
// 初始化
updateTolerance();
});
</script>
</body>
</html>
版权属于:
wehg489
作品采用:
《
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
》许可协议授权
评论