微信小程序开发〖二〗垃圾分类的图片识别与Springboot

最近心血来潮,搞一个垃圾分类玩玩

但是简单的垃圾分类怎么能满足我,我要加一点好玩的,刺激的,没玩过的~~

当然是图像识别啦,虽然我这个菜鸡没学过图像识别这种高难度的,但是我可以调用科大讯飞的接口,直接获取信息就OK啦

首先我找到了科大讯飞的图像识别api,一下就看到了物体识别!
物体识别,采用全球领先的通用物体检测算法,有效检测图像中的动物、交通工具、生活家具等2万多种生活常见物体。
该能力是通过HTTP API的方式给开发者提供一个通用的接口,适用于一次性交互数据传输的AI服务场景,块式传输。相较于SDK,API具有轻量、跨语言的特点,不过请注意该接口使用的HTTP API协议不支持跨域。
在这里插入图片描述
科大讯飞物体识别链接

一下子能识别2w多种物体,这一下子就满足我的需求了,所以我就仔细看了一下怎么调用它

参数
在这里插入图片描述
调用它的接口很复杂,规则一大堆,看的很烦,物体识别文档,所以我直接看它的demo怎么写

我这边是用的java,我就封装了自己的工具类跟对象,为我所用

二.上代码(后端)

封装的对象类

@Data
public class ImagesDO {

	// 请求地址
    private   String URL = "http://tupapi.xfyun.cn/v1/currency";
    // 应用ID
    private   String APPID = "5db8d5";
    // 接口密钥
    private   String API_KEY = "456de4716e02bd589d450a";
    // 图片名称
    public  String IMAGE_NAME ;
    // 图片路径
    private String PATH ;
}

  • URL : 请求的地址,固定的为物体识别的请求地址
  • APPID : 在你的科大讯飞创建应用里获取
  • API_KEY : 在你的科大讯飞创建应用里获取
  • IMAGE_NAME : 图片的名字(跟格式)
  • PATH : 图片的本地路径

处理图片的工具类

package com.fehead.testproject.controller.utils;

import java.io.*;

/**
 * 文件操作工具类
 */
public class FileUtil {
	/**
	 * 读取文件内容为二进制数组
	 * 
	 * @param filePath
	 * @return
	 * @throws IOException
	 */
	public static byte[] read(String filePath) throws IOException {

		InputStream in = new FileInputStream(filePath);
		byte[] data = inputStream2ByteArray(in);
		in.close();

		return data;
	}

	/**
	 * 流转二进制数组
	 * 
	 * @param in
	 * @return
	 * @throws IOException
	 */
	private static byte[] inputStream2ByteArray(InputStream in) throws IOException {

		ByteArrayOutputStream out = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024 * 4];
		int n = 0;
		while ((n = in.read(buffer)) != -1) {
			out.write(buffer, 0, n);
		}
		return out.toByteArray();
	}

	/**
	 * 保存文件
	 * 
	 * @param filePath
	 * @param fileName
	 * @param content
	 */
	public static void save(String filePath, String fileName, byte[] content) {
		try {
			File filedir = new File(filePath);
			if (!filedir.exists()) {
				filedir.mkdirs();
			}
			File file = new File(filedir, fileName);
			OutputStream os = new FileOutputStream(file);
			os.write(content, 0, content.length);
			os.flush();
			os.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

http请求工具类

package com.fehead.testproject.controller.utils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;

/**
 * Http Client 工具类
 */
public class HttpUtil {
	
	

	
	/**
	 * 发送post请求
	 * 
	 * @param url
	 * @param header
	 * @param body
	 * @return
	 */
	public static String doPost1(String url, Map<String, String> header, byte[] body) {
		String result = "";
		BufferedReader in = null;
		try {
			// 设置 url
			URL realUrl = new URL(url);
			URLConnection connection = realUrl.openConnection();
			HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
			// 设置 header
			for (String key : header.keySet()) {
				httpURLConnection.setRequestProperty(key, header.get(key));
			}
			// 设置请求 body
			httpURLConnection.setDoOutput(true);
			httpURLConnection.setDoInput(true);
			httpURLConnection.setRequestProperty("Content-Type", "binary/octet-stream");
						
			OutputStream out = httpURLConnection.getOutputStream();
			out.write(body);
			out.flush();
			out.close();
			if (HttpURLConnection.HTTP_OK != httpURLConnection.getResponseCode()) {
				System.out.println("Http 请求失败,状态码:" + httpURLConnection.getResponseCode());
				return null;
			}

			// 获取响应body
			in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			return null;
		}
		return result;
	}

	
}

三.调用接口

 @PostMapping("/upload")
    public List<LabelDO> identityAudit(HttpServletResponse response, HttpServletRequest request) throws IOException {
        System.out.println("进入get方法!");

        MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
        MultipartFile multipartFile = req.getFile("file"); //对应前端页面的name值

//        String path = request.getSession().getServletContext().getRealPath("/image");

        String realPath = "E:/image"; //这里选取本地e盘下的路径作为图片保存路径

        File dir = new File(realPath);//若不存在这个路径,则创建这个文件夹
        if (!dir.exists()) {
            dir.mkdir();
        }
        //生成一个新的文件名fileName
        String n = UUID.randomUUID().toString().substring(0, 11);
        String picName = n + "." + "jpg";
        String d = realPath+"/"+ picName;
        File file = new File(realPath, picName);
        multipartFile.transferTo(file);
        .........未完
      }
  • 这里我用的serverlet,会返回一个DO类的list,封装返回的五组数据
  • 这里我会把上传的图片重新统一命名,命名规则为图片路径+图片名称
  • 最后写入真实路径的文件

这里获取的图片路径是因为,之后调用物体识别接口会需要图片路径

调用接口实现

扫描二维码关注公众号,回复: 9146740 查看本文章
 Map<String, String> bulider=imageService.choseImage(picName,d);
        byte[] imageByteArray = FileUtil.read(d); //图片的二进制形式
        String result = HttpUtil.doPost1("http://tupapi.xfyun.cn/v1/currency", bulider, imageByteArray);
        System.out.println("接口调用结果:" + result);
  • 首先把图片的图片名,路径封装到map里面
  • 并且调用之前写好的文件的工具类,把本地图片变成二进制的形式
  • 最后调用http工具类,填好参数,第一个是参数就是物体识别的请求的接口地址

返回结果

{"code":0,"data":{"fileList":[{"label":161,"labels":[161,6385,1729,9545,15938],"name":"3efa1937-0b.jpg","rate":0.15478475391864777,"rates":[0.15478475391864777,0.11142700910568237,0.11099418252706528,0.09142182022333145,0.07964999973773956],"review":true}],"reviewCount":1,"topNStatistic":[{"count":1,"label":161}]},"desc":"success","sid":"tup00002c04@dx0a061118c73a1aba00"}
{
	"code":"0",
	"data":[
		{
			"label":19015,
			"labels":[
				19015,
				18927,
				18929,
				698,
				5588
			],
			"name":"img.jpg",
			"rate":0.10702908039093018,
			"rates":[
				0.10702908039093018,
				0.08567219227552414,
				0.0592394582927227,
				0.04257886856794357,
				0.04108942672610283
			],
			"review":true,
			"tag":"Local Image"
		}
	],
	"desc":"success",
	"sid":"tup00000005@ch2ee40efd592d6a6b00"
}

返回的字符串很复杂,但也算是成功了

  • labels 代表识别的物体的序列,一共有五组,相当于给你了最接近的五个物体
  • name 你上传图片的名字
  • rates 代表各个识别物体的相似概率

四.处理数据

既然成功的调用了接口,那我们现在开始来处理数据了

首先,我们把他转化成json来处理数据,这里我们用到了阿里的FastJson来处理,
详情可看我之前的博客FastJson处理数据
这里直接上代码

  JSONObject jsonObject = JSON.parseObject(result);

  JSONArray jsonArray=jsonObject.getJSONObject("data").getJSONArray("fileList").getJSONObject(0).getJSONArray("labels");

返回的jsonArray数据如下,我们直接获取了labels里的数据了,因为我们需要返回识别物体的label,其他的暂时不需要.
在这里插入图片描述
这里一长串代码肯定是看不懂的,我们需要在后台处理数据!
首先来看一下官方给的返回数据识别的物体label2w个太多了,但是很容易处理的

先给它封装成list,后面要用

      List<Integer> list = new ArrayList<>();//获取五个最接近的物体的label
        for(Object jstr:jsonArray){
            list.add(Integer.parseInt(String.valueOf(jstr)));
        }

导入数据库

下载了之前的的表,我们来导入自己的数据库里,我用的是mysql,可以直接用excel表的格式导入数据库,利用navicat的可视界面导入向导就可以导入到数据库中
在这里插入图片描述
这样的导入成功了
在这里插入图片描述


Mybatis-Plus登场

mp作为非常好用的mybatis的增强版,非常的强,详细学习可以参照我之前写的Mybatis-Plus学习来学习一下

D

@Data
@TableName("images")
public class LabelDO {

    private Integer id;

    private String englishName;

    private String name;

    private String classes;

    private Integer label;

}

dao层

package com.fehead.testproject.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fehead.testproject.dataobject.LabelDO;

public interface LabelDOMapper extends BaseMapper<LabelDO> {

}

service层

@Service
public class LabelServiceImpl {

    @Autowired
    private LabelDOMapper labelDOMapper;

    public List<LabelDO> selectLabel(List<Integer> list){
        List<LabelDO> labelDOS=new ArrayList<>();
        for (Integer integer:list) {
            QueryWrapper<LabelDO> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("label",integer);
            LabelDO labelDO=labelDOMapper.selectOne(queryWrapper);
            String[] result=labelDO.getName().split(",");
            String[] result1=result[0].split(";");
            labelDO.setName(result1[0]);
            labelDOS.add(labelDO);
        }
        return labelDOS;
    }
}
  • 首先利用了mp自带的方法查询每一个label对应的DO
  • String[] result=labelDO.getName().split(",") 由于数据库会查到打蛋器,打蛋机 或长者; 长辈; 元老,这样的词语不能方便我们查询,所以各个词语相似,我们只取第一个词,这里用到了字符串的split方法,取出","前的第一个词
  • String[] result1=result[0].split(";") 我们再来筛选";",上一步筛选了",",现在我们来在上一步的基础下筛选,这样我们取出的字符串就符合我们的要求了
  • 最终返回的是一个对象list

最后一步,调用service层的方法就可以啦,我太懒了就没写处理异常的,你们可以加

   List<LabelDO> labelDOS=labelService.selectLabel(list);

        return labelDOS;

我们来看一下最终返回的数据
在这里插入图片描述

五.前端部分(微信小程序)

这里用作演示,就简单的写一个小程序的前端看看,代码先放出来,下一篇博客好好做前端
在这里插入图片描述
差不多这种,凑活的看一下啦

页面的js

// pages/images/images.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    InputBottom: "",
    imagesfindName:'',
    garbageName:[],
    tempFilePaths1:''

  },

  ViewImage(e) {
    wx.previewImage({
      urls: this.data.imgList,
      current: e.currentTarget.dataset.url
    });
  },

  ChooseImage() {
    var that=this
    wx.chooseImage({
      count: 1, //默认9
      sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
      sourceType: ['album', 'camera'], //从相册选择
      success: (res) => {
        console.log(res)
        var tempFilePaths = res.tempFilePaths;
        that.setData({
          tempFilePaths1: tempFilePaths
        })
        // wx.showToast({
        //   title: '正在上传...',
        //   icon: 'loading',
        //   mask: true,
        //   duration: 10000
        // })
      
        // url: 'http://127.0.0.1:8091/images/upload', //仅为示例,非真实的接口地址

        // http://api.choviwu.top/garbage/uploadFile

        wx.uploadFile({
          url: 'http://127.0.0.1:8091/images/upload', //仅为示例,非真实的接口地址
          filePath: tempFilePaths[0],
          name: 'file',
          header: {
            "Content-Type": "multipart/form-data",
            'accept': 'application/json',
          },
          formData: {
          },
          success(res) {
            var json = JSON.parse(res.data) 
            console.log(json)
            that.setData({
              imagesfindName: json
            })
            for(var i=0;i<that.data.imagesfindName.length;i++){
              that.searchgarbage(that.data.imagesfindName[i]);
            }
          }
        })
      }
    });
  },

  searchgarbage:function(e){
    var that=this
    wx.request({
      url: 'https://service.xiaoyuan.net.cn/garbage/index/search',
      method:"GET",
      data:{
      kw : e.name
      },
      success: function(res){
          console.log(res.data.data[0])
          that.setData({
            garbageName: that.data.garbageName.concat(res.data.data[0])
          })
      }
    })
  },

  InputFocus(e) {
    this.setData({
      InputBottom: e.detail.height
    })
  },
  InputBlur(e) {
    this.setData({
      InputBottom: 0
    })
  },


  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

wxml代码

<view>
  <button bindtap="ChooseImage">选图片</button>
</view>

  <view class="cu-form-group">
		<view class="grid col-4 grid-square flex-sub">
			<view class="bg-img" wx:for="{{tempFilePaths1}}" wx:key="{{index}}" bindtap="ViewImage" data-url="{{tempFilePaths1[index]}}">
				<image src='{{tempFilePaths1[index]}}' mode='aspectFill' ></image>
				<view class="cu-tag bg-red" catchtap="DelImg" data-index="{{index}}">
					<text class="cuIcon-close"></text>
				</view>
			</view>
		</view>
	</view>

  <view wx:for="{{garbageName}}">
    <view>{{item.name}}------{{item.category}}</view>
  </view>

制作不易,转载请标注~~

发布了69 篇原创文章 · 获赞 54 · 访问量 9583

猜你喜欢

转载自blog.csdn.net/kingtok/article/details/102875738
今日推荐