一个小猪咪🐱品种鉴定小工具

🐱前言

今日突发奇想给自家小猪咪做一个品种血统鉴定小工具看看猪咪继承了哪些血统,毕竟小猪咪到家这么久了都不知道他继承了那只猪咪的基因~~

🤔️技术选择

目前调研了多个图片识别,感觉只有百度的做的最好,所以我们将使用百度的图像识别对小猪咪进行血统鉴定

具体费用如下:

💻百度控制台创建应用

首先创建一个应用,由于我们只使用了动物识别功能所以只需要选择动物识别即可

创建完毕后我们就拥有调用api的接口的key了

🙏调试

之后有需要的话,我们可以在控制台中对接口进行在线调试

✍️代码编写

接下来我们开始编写api接口的代码,用于前端的调用

接口说明

百度接口api限制图片最大只能是4m,所以我们在调用接口的时候需要先对图片进行压缩处理到4M以内,所以我们直接使用下面的SDK即可。

对于SDK使用的话就是直接把图片转为base64然后再调用SDK即可

使用Sharp压缩图片

由于我们使用的是 Nestjs ,所以相对来说简单一点,安装sharp ,推荐使用pnpm安装避免版本出错

复制代码
pnpm install sharp

具体接口逻辑代码如下:

js 复制代码
import { Injectable } from '@nestjs/common';
import { InjectEntityManager } from '@nestjs/typeorm';
import { EntityManager } from 'typeorm';
import { IdentificationDto } from './dto/identification.dto';
import { imageClassify } from 'baidu-aip-sdk';
import fetch from 'node-fetch';
import { Identification } from './entities/identification.entity';
import * as dayjs from 'dayjs';
import { GetIdentificationDto } from './dto/getIdentification.dto';
import * as sharp from 'sharp';

@Injectable()
export class AnimalService {
  constructor() {
    // 设置APPID/AK/SK
    const APP_ID = 'xxxxxxxx';
    const API_KEY = 'xxxxxxxx';
    const SECRET_KEY = 'xxxxxxxx';

    // 新建一个对象,建议只保存一个对象调用服务接口
    this.client = new imageClassify(APP_ID, API_KEY, SECRET_KEY);
  }

  client: any;

  @InjectEntityManager()
  private entityManager: EntityManager;

  // 图片转buffer
  private async getImageBuffer(url: string): Promise<Buffer> {
    const response = await fetch(url);

    const buffer = Buffer.from(await response.arrayBuffer());

    return buffer;
  }

  // 压缩图片
  private async resizeImageIfNeeded(
    buffer: Buffer,
    maxSize: number,
  ): Promise<Buffer> {
    const originalSize = buffer.length;

    // 小于4m
    if (originalSize <= maxSize) {
      return buffer;
    }

    // 压缩图片
    const compressedImageBuffer = await sharp(buffer)
      .resize({
        // 图片宽
        width: 500,
        // 图片
        height: 500,
        // 保留纵横比,将图像大小调整为尽可能大,同时确保其尺寸小于或等于指定的尺寸
        fit: 'inside',
        // 不放大
        withoutEnlargement: true,
      })
      .toBuffer();

    return compressedImageBuffer;
  }

  // url转base64
  async urlToBase64(url: string): Promise<string> {
    const imageBuffer = await this.getImageBuffer(url);

    // 是否需要压缩
    const resizedBuffer = await this.resizeImageIfNeeded(imageBuffer, 2 * 1024);
    const base64String = resizedBuffer.toString('base64');

    return base64String;
  }

  // 动物识别
  async identification(data: IdentificationDto, userId: number) {
    // url转base64
    const image = await this.urlToBase64(data.url);

    // 如果有可选参数
    const options = {};
    // 返回预测得分top结果数,默认为6,相当于返回多少条结果
    options['top_num'] = '4';
    // 用于控制返回结果是否带有百科信息,若不输入此参数,则默认不返回百科结果;若输入此参数,会根据输入的整数返回相应个数的百科信息
    options['baike_num'] = '1';

    // 带参数调用动物识别
    try {
      const res = await this.client.animalDetect(image, options);

      if (!res.result) {
        return {
          code: -1,
          msg: '上传照片非动物',
        };
      }

      const result = res.result[0];

      if (result.name === '非动物') {
        return {
          code: -1,
          msg: '上传照片非动物',
        };
      }

      return {
        data: {
          list: res.result,
        },
      };
    } catch (error) {
      throw error;
    }
  }

接口入参代码如下:

js 复制代码
import { WINSTON_LOGGER_TOKEN } from 'src/winston/winston.module';
import {
  Controller,
  HttpStatus,
  HttpCode,
  HttpException,
  Inject,
  UseInterceptors,
  Post,
  Body,
  UseGuards,
  Headers,
} from '@nestjs/common';
import { InvokeRecordInterceptor } from 'src/invoke-record.interceptor';
import { AnimalService } from './animal.service';
import { IdentificationDto } from './dto/identification.dto';
import { LoginGuard } from 'src/login.guard';
import { RedisService } from '../redis/redis.service';

@Controller('animal')
@UseInterceptors(InvokeRecordInterceptor)
export class AnimalController {
  constructor(private readonly animalService: AnimalService) {}

  @Inject(WINSTON_LOGGER_TOKEN)
  private logger;

  @Inject(RedisService)
  private redisService: RedisService;

  // 动物识别
  @Post('identification')
  @UseGuards(LoginGuard)
  @HttpCode(HttpStatus.OK)
  async identification(
    @Body() data: IdentificationDto,
    @Headers() headers: Record<string, string>,
  ) {
    try {
      const token = headers.authorization.split(' ')[1];

      const redisToken = await this.redisService.get(token);
      const _redisToken = JSON.parse(redisToken);

      const res = await this.animalService.identification(data, _redisToken.id);

      return {
        data: {},
        ...res,
      };
    } catch (e) {
      this.logger.error(e, '动物识别错误');

      throw new HttpException(`服务器错误`, HttpStatus.BAD_REQUEST);
    }
  }
}

以上代码写完后就可以到前端进行接入了

✍️前端接入

前端直传到腾讯云cos,然后把url传入上面写的Nestjs接口

js 复制代码
 wx.chooseMedia({
    count: 1,
    mediaType: ['image'],
    sourceType: ['album', 'camera'],
    sizeType: ['compressed'],
    camera: 'back',
  }).then(async ({ tempFiles }) => {
    const file = tempFiles[0];

    loading.value = true;

    // uploadFile
    await uploadFile(
      {
        url: file.tempFilePath,
        type: 'animal',
        noMediaCheck: true,
      },
      async (url) => {
        const res = await identification({
          url: url,
        });

        if (res.code === 0) {
          identificationStore.setIdentification({
            cover: url,
            ...res.data,
          });
        }

        loading.value = false;
      },
      () => {
        loading.value = false;
      },
    );
  });

👀效果展示

以上代码写完后,最终的代码效果显示如下:

🧐预览地址

掘友们可扫描一下二维码可进行体验,进入小程序后点击小工具即可使用~~


相关推荐
梦帮科技1 分钟前
Web 漏洞攻防深度:WAF 规则逃逸技术(畸形分块传输、双重编码)与对抗加固
linux·前端·网络安全·ssl·web
兰亭妙微UI设计公司8 分钟前
兰亭妙微软件界面设计公司的解锁按钮设计10大密码
开发语言·前端·javascript
微擎应用市场26 分钟前
多功能预约公众号管理系统介绍
微信小程序·小程序
迪幻31 分钟前
封装自己的 npm 依赖并存储到个人 GitHub
前端·npm·github
u0111026751 小时前
WebP 转成 PNG 后为什么更大?图片格式转换不等于压缩
前端·javascript·vue.js
万少1 小时前
Qoder sonus模型 20分钟,复刻 马斯克 飞天汽车
前端·后端·算法
java1234_小锋1 小时前
【技术专题】HTML5 网页技术 - HTML5 列表标签
前端·html·html5
强二小哥帅1 小时前
Kotlin 协程复习笔记
前端
不可能片场1 小时前
工程实践 原子替换改了 ctime 怎么修
前端·electron
暧暧内含光1 小时前
HTTP 文件传输体系全解:从协议标头、OSS 架构到流媒体分片
前端