Skip to content

实现 拍照计数 工具

分类:retirement | 标签:拍照、计数、AI识别 智能拍照识别计数工具,支持物品自动计数

2.1 功能说明

智能拍照识别计数工具,支持物品自动计数

2.2 代码实现

2.2.1 组件结构

本工具是一个基于 Vue 3 <script setup> 语法的单文件组件(SFC),统一包裹在 ToolPageShell 组件内,由它提供页面标题、工具 ID、分类与「使用指南」插槽等通用外壳;核心业务逻辑(响应式状态、计算属性、事件处理函数)全部写在 <script setup> 中,输入/输出通过 el-inputel-button 等 Element Plus 组件与用户交互,所有数据均在浏览器本地处理,不会上传服务器。

2.2.2 核心逻辑概览

<script setup> 中定义的主要函数/方法:

  • handleFileSelect()
  • handleCameraCapture()
  • loadImage()
  • handleDetect()
  • handleImageLoad()
  • zoomIn()
  • zoomOut()
  • resetZoom()
  • goBack()

2.2.3 关键实现代码

以下是该工具的完整 <script setup> 实现(核心代码)。模板(<template>)与样式(<style>)已省略。

vue
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { 
  Picture, 
  Camera, 
  Search, 
  View, 
  ZoomIn, 
  ZoomOut, 
  RefreshRight,
  InfoFilled,
  ArrowLeft
} from '@element-plus/icons-vue'
import { BeanCounterApi } from '@/api/BeanCounterApi'
import FeedbackForm from '@/components/FeedbackForm.vue'

const router = useRouter()

// 状态管理
const fileInputRef = ref(null)
const cameraInputRef = ref(null)
const imageWrapperRef = ref(null)
const previewUrl = ref(null)
const count = ref(null)
const isDetecting = ref(false)
const currentScale = ref(1)
const currentSource = ref(null)
const selectedFile = ref(null) // 保存当前选择的文件
const activeTab = ref('counter') // Tab页签状态,默认显示拍照计数

// 计算属性
const hasImage = computed(() => !!previewUrl.value)

// 处理文件选择
const handleFileSelect = (event) => {
  const file = event.target.files?.[0]
  if (file) {
    currentSource.value = 'file'
    selectedFile.value = file // 保存文件引用
    loadImage(file)
  }
}

// 处理相机拍摄
const handleCameraCapture = (event) => {
  const file = event.target.files?.[0]
  if (file) {
    currentSource.value = 'camera'
    selectedFile.value = file // 保存文件引用
    loadImage(file)
  }
}

// 加载图片
const loadImage = (file) => {
  // 验证文件类型
  if (!file.type.startsWith('image/')) {
    ElMessage.error('请选择图片文件')
    return
  }

  // 验证文件大小(限制为10MB)
  if (file.size > 10 * 1024 * 1024) {
    ElMessage.error('图片大小不能超过10MB')
    return
  }

  const reader = new FileReader()
  reader.onload = (e) => {
    previewUrl.value = e.target.result
    count.value = null
    resetZoom()
    ElMessage.success('图片加载成功')
  }
  reader.onerror = () => {
    ElMessage.error('图片加载失败')
  }
  reader.readAsDataURL(file)
}

// 开始检测
const handleDetect = async () => {
  if (!selectedFile.value) {
    ElMessage.warning('请先选择或拍摄图片')
    return
  }

  isDetecting.value = true
  count.value = null

  try {
    // 调用实际的检测API
    const response = await BeanCounterApi.upload(selectedFile.value)
    
    // 处理返回结果(response 已经是 {count, result_img} 对象)
    if (response && response.count !== undefined) {
      count.value = response.count
      
      // 如果有返回标注后的图片,则显示
      if (response.result_img) {
        previewUrl.value = 'data:image/png;base64,' + response.result_img
      }
      
      ElMessage.success(`检测完成,共识别到 ${count.value} 个物品`)
    } else {
      throw new Error('响应数据格式错误')
    }
  } catch (error) {
    console.error('检测失败:', error)
    ElMessage.error(error.msg || error.message || '检测失败,请稍后重试')
    count.value = 0
  } finally {
    isDetecting.value = false
  }
}

// 图片加载完成
const handleImageLoad = () => {
  console.log('图片加载完成')
}

// 缩放控制
const zoomIn = () => {
  currentScale.value = Math.min(currentScale.value * 1.2, 5)
}

const zoomOut = () => {
  currentScale.value = Math.max(currentScale.value / 1.2, 0.1)
}

const resetZoom = () => {
  currentScale.value = 1
}

// 返回板块列表
const goBack = () => {
  router.push('/education')
}

2.3 效果截图

暂未生成该工具的效果截图。

工具访问地址:https://www.i91tools.com/tools/photo-counter