如何使用js进行抠图。识别商品主体

1、抠图api,每月有50次免费的额度的抠图api可以调用。

https://www.remove.bg/zh/api#get-started

效果一般。不建议使用。

2,通过canvas识别颜色边缘。

3、使用gimp

好一点

4、使用模型处理。rembg:Python 库,可以通过 WebAssembly 在前端使用,推荐使用,就是有点慢,精细化处理需要时间。

复制代码
<template>
  <div class="container">
    <div class="upload-section">
      <h2>图片上传与 Canvas 显示</h2>
      <input type="file" ref="fileInput" @change="handleFileUpload" accept="image/*" class="file-input" />
      <button @click="clearCanvas" class="clear-btn">清除画布</button>
    </div>

    <div class="canvas-container" v-if="showCanvas">
      <div class="canvas-wrapper">
        <div class="canvas-item">
          <div class="canvas-label">原图</div>
          <canvas ref="canvas" class="image-canvas"></canvas>
        </div>
        <div class="canvas-item" v-if="showResult">
          <div class="canvas-label">处理后</div>
          <canvas ref="resultCanvas" class="result-canvas"></canvas>
        </div>
      </div>
      
      <div class="controls" v-if="showCanvas">
        <button @click="handleRemoveBackground" class="cutout-btn" :disabled="isProcessing">
          {{ isProcessing ? (modelLoading ? '加载模型中...' : '处理中...') : '智能抠图' }}
        </button>
        <button @click="downloadResult" v-if="showResult" class="download-btn">
          下载结果
        </button>
        <button @click="showResult = false" v-if="showResult" class="hide-result-btn">
          隐藏结果
        </button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, nextTick, onMounted } from 'vue'
import { removeBackground } from '@imgly/background-removal'

const fileInput = ref(null)
const canvas = ref(null)
const resultCanvas = ref(null)
const showCanvas = ref(false)
const showResult = ref(false)
const isProcessing = ref(false)
const modelLoading = ref(false)

const handleFileUpload = (event) => {
  const file = event.target.files[0]
  if (!file) return

  // 先显示 canvas 容器
  showCanvas.value = true

  // 等待 DOM 更新后处理图片
  nextTick(() => {
    const reader = new FileReader()
    reader.onload = (e) => {
      const img = new Image()
      img.onload = () => {
        // 确保 canvas 已经渲染
        if (canvas.value) {
          drawImageToCanvas(img)
        }
      }
      img.onerror = () => {
        console.error('图片加载失败')
        showCanvas.value = false
      }
      img.src = e.target.result
    }
    reader.onerror = () => {
      console.error('文件读取失败')
      showCanvas.value = false
    }
    reader.readAsDataURL(file)
  })
}

const drawImageToCanvas = (img) => {
  if (!canvas.value) {
    console.error('Canvas 元素不存在')
    return
  }

  const ctx = canvas.value.getContext('2d')
  
  // 设置画布尺寸
  const maxWidth = 800
  const maxHeight = 600
  let width = img.width
  let height = img.height

  // 按比例缩放
  if (width > maxWidth || height > maxHeight) {
    const ratio = Math.min(maxWidth / width, maxHeight / height)
    width = width * ratio
    height = height * ratio
  }

  // 设置 canvas 尺寸
  canvas.value.width = width
  canvas.value.height = height

  console.log('Canvas 尺寸:', width, 'x', height)
  console.log('图片尺寸:', img.width, 'x', img.height)

  // 绘制图片
  ctx.drawImage(img, 0, 0, width, height)
  console.log('图片已绘制到 Canvas')
}

const clearCanvas = () => {
  if (canvas.value) {
    const ctx = canvas.value.getContext('2d')
    ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
    showCanvas.value = false
    showResult.value = false
    if (fileInput.value) {
      fileInput.value.value = ''
    }
  }
}

// 智能抠图功能 - 使用 rembg
const handleRemoveBackground = async () => {
  if (!canvas.value) return
  
  isProcessing.value = true
  modelLoading.value = true
  
  try {
    await nextTick()
    
    // 获取原始 canvas 的图像数据
    const imageData = canvas.value.toDataURL('image/png')
    
    // 使用 rembg 进行背景移除
    const blob = await removeBackground(imageData)
    
    // 创建结果 canvas
    showResult.value = true
    await nextTick()
    
    if (resultCanvas.value) {
      // 将结果显示在 canvas 上
      const url = URL.createObjectURL(blob)
      const ctx = resultCanvas.value.getContext('2d')
      const img = new Image()
      
      img.onload = () => {
        resultCanvas.value.width = img.width
        resultCanvas.value.height = img.height
        ctx.drawImage(img, 0, 0)
        URL.revokeObjectURL(url)
      }
      
      img.src = url
    }
  } catch (error) {
    console.error('抠图失败:', error)
    alert('抠图失败: ' + error.message)
  } finally {
    isProcessing.value = false
    modelLoading.value = false
  }
}

// 下载抠图结果
const downloadResult = () => {
  if (resultCanvas.value) {
    const link = document.createElement('a')
    link.download = 'removed_background.png'
    link.href = resultCanvas.value.toDataURL('image/png')
    link.click()
  }
}
</script>

<style scoped>
.container {
  text-align: center;
  padding: 30px 20px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.upload-section {
  margin-top: 50px;
  padding: 30px;
  background-color: #f5f5f5;
  border-radius: 10px;
}

.upload-section h2 {
  color: #35495e;
  font-size: 24px;
  margin-bottom: 20px;
}

.file-input {
  margin-right: 10px;
  padding: 8px;
  border: 2px solid #42b883;
  border-radius: 4px;
  background-color: white;
}

button {
  padding: 12px 24px;
  background-color: #42b883;
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #3aa876;
}

.clear-btn {
  background-color: #ff6b6b;
  margin-left: 10px;
  margin-top: 0;
}

.clear-btn:hover {
  background-color: #ff5252;
}

.canvas-container {
  margin-top: 30px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

.canvas-wrapper {
  display: flex;
  gap: 30px;
  flex-wrap: wrap;
  justify-content: center;
  width: 100%;
  max-width: 1400px;
}

.canvas-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.canvas-label {
  font-size: 18px;
  font-weight: bold;
  color: #35495e;
  margin-bottom: 5px;
}

.image-canvas,
.result-canvas {
  border: 3px solid #42b883;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  max-width: 600px;
  max-height: 500px;
  width: auto;
  height: auto;
  object-fit: contain;
}

.result-canvas {
  border-color: #ff6b6b;
  background: linear-gradient(45deg, #ccc 25%, transparent 25%),
              linear-gradient(-45deg, #ccc 25%, transparent 25%),
              linear-gradient(45deg, transparent 75%, #ccc 75%),
              linear-gradient(-45deg, transparent 75%, #ccc 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
}

.controls {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

.cutout-btn {
  background-color: #9c27b0;
}

.cutout-btn:hover {
  background-color: #7b1fa2;
}

.cutout-btn:disabled {
  background-color: #bdbdbd;
  cursor: not-allowed;
}

.download-btn {
  background-color: #2196f3;
}

.download-btn:hover {
  background-color: #1976d2;
}

.hide-result-btn {
  background-color: #ff9800;
}

.hide-result-btn:hover {
  background-color: #f57c00;
}
</style>
相关推荐
不会写DN2 小时前
Vue3中的computed 与 watch 的区别
javascript·面试·vue
Dxy12393102162 小时前
Python使用PyEnchant详解:打造高效拼写检查工具
开发语言·python
qq_381338502 小时前
TypeScript 类型安全与类型体操实战:从入门到精通
javascript·安全·typescript
网域小星球2 小时前
C 语言从 0 入门(十五)|综合小项目:菜单交互与简易功能实现
c语言·开发语言·交互
网域小星球2 小时前
C 语言从 0 入门(十六)|动态内存管理:malloc /free/calloc /realloc 精讲
c语言·开发语言·free·malloc·动态内存
柳杉2 小时前
HTML-in-Canvas:让 Canvas 完美渲染 HTML 的 Web 新标准
前端·javascript
雪的季节2 小时前
qt信号槽跨线程使用时候的坑
java·开发语言·qt
cTz6FE7gA2 小时前
WebGL实战:用Three.js创建3D场景,实现沉浸式Web体验
前端·javascript·webgl
AI应用实战 | RE2 小时前
011、向量数据库入门:Embeddings原理与ChromaDB实战
开发语言·数据库·langchain·php