基于TensorFlow2.3.0的垃圾分类Android APP设计

一、开发环境

  • Windows 10
  • Python 3.7.3
  • TensorFlow 2.3.0
  • Anaconda 4.12.0
  • CUDA 10.1
  • cuDNN 7.6.5

二、步骤

        2.1 创建一个python 3.7.3的虚拟环境

conda create -n trash_gpu python==3.7.3

        2.2 激活虚拟环境

conda activate trash_gpu

        2.3 安装tensorflow-gpu,提前安装好CUDA 10.1和cuDNN 7.6.5

pip install tensorflow-gpu==2.3.0

        2.4 准备垃圾分类数据集

        2.5 编写训练模型代码,为了使模型文件更加轻量化,使用MobileNetV2来训练模型。

        代码如下:

# 模型加载
def model_load(IMG_SHAPE=(224, 224, 3), class_num=214):
    base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=False, weights='imagenet')
    base_model.trainable = False

    model = tf.keras.models.Sequential([
        tf.keras.layers.experimental.preprocessing.Rescaling(1. / 127.5, offset=-1, input_shape=IMG_SHAPE),
        base_model,
        tf.keras.layers.GlobalAveragePooling2D(),
        tf.keras.layers.Dense(class_num, activation='softmax')
    ])
    
    # 输出模型信息
    model.summary() 
    model.compile(optimizer='adam', loss='categorical_crossentropy',
                  metrics=['accuracy'])
    return model



# 训练模型
def train(epochs):
    # 1. 加载数据集
    train_dataset, validate_dataset, class_names = data_load("E:/trash_image_set/data", 224, 224, 16) 
    # print(class_names)
    print('类别的个数-->')
    print(len(class_names))

    # 2. 加载模型
    model = model_load(class_num=len(class_names))
    # 3. 训练
    history = model.fit(train_dataset, validation_data=validate_dataset, epochs=epochs)

    # 4. 保存模型
    model.save("models/trash_model.h5")  

    # 5. 转换为tflite模型
    h5_model = tf.keras.models.load_model("models/trash_model.h5")
    converter = tf.lite.TFLiteConverter.from_keras_model(h5_model)
    tflite_model = converter.convert()
    open("models/model.tflite", "wb").write(tflite_model)


if __name__ == '__main__':
    train(epochs=30)

        2.6 经过漫长的训练过程后,在models文件夹中得到名称为model.tflite的模型文件,接下来将这个模型文件导入Android Studio工程中。

三、编写Android APP

        3.1 将model.tflite模型文件拷贝到Android工程的assets文件中,如图:

         3.2 同时要在app下build.gradle文件添加如下内容

    aaptOptions {
        noCompress "tflite"
    }

        3.3 编写activity_main.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="0dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="基于TensorFlow的垃圾分类系统设计"
        android:textColor="@color/black"
        android:textSize="22sp" />

    <androidx.cardview.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        app:cardCornerRadius="20dp">

        <ImageView
            android:id="@+id/iv_trash"
            android:layout_width="260dp"
            android:layout_height="260dp"
            android:scaleType="centerCrop"
            android:src="@drawable/cup" />

    </androidx.cardview.widget.CardView>

    <TextView
        android:id="@+id/tv_waste_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        android:text="可回收垃圾_水杯"
        android:textColor="@color/black"
        android:textSize="18sp" />

    <androidx.cardview.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        app:cardCornerRadius="20dp">

        <ScrollView
            android:layout_width="wrap_content"
            android:layout_height="260dp"
            android:layout_margin="10dp"
            android:layout_marginTop="10dp">

            <TextView
                android:id="@+id/tv_trash_detail"
                android:layout_width="360dp"
                android:layout_height="wrap_content"
                android:text="@string/recyclable"
                android:textColor="@color/black"
                android:textSize="18sp" />

        </ScrollView>
    </androidx.cardview.widget.CardView>


    <Button
        android:id="@+id/choose_image"
        android:layout_width="230dp"
        android:layout_height="50dp"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:background="@drawable/angle_button"
        android:onClick="choose_image"
        android:text="选择图片"
        android:textColor="@android:color/white"
        android:textSize="20sp" />


</LinearLayout>

  3.4 编写MainActivity.java代码

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = this.getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.GRAY);

        }
        setContentView(R.layout.activity_main);

        /*
         * 在选择图片的时候,在android 7.0及以上通过FileProvider获取Uri,不需要文件权限
         */
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            List<String> permissionList = new ArrayList<>(Arrays.asList(neededPermissions));
            permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
            neededPermissions = permissionList.toArray(new String[0]);
        }

        initView();

        TFLiteLoader loader = TFLiteLoader.newInstance(this);
        interpreter = loader.get();

        showToast("模型加载成功!");

        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.cup);
    }


    private void initView() {
        tv_trash_detail = findViewById(R.id.tv_trash_detail);
        iv_trash = findViewById(R.id.iv_trash);
        tv_waste_name = findViewById(R.id.tv_waste_name);
    }

    private void showToast(String text) {
        Toast.makeText(this, text, Toast.LENGTH_LONG).show();
    }

    // 更换图片
    public void choose_image(View view) {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(intent, 0);
    }

    private int maxIndex = 0;

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data == null || data.getData() == null) {
            showToast("获取图片失败");
            return;
        }

        try {
            mBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData());
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 识别图片
        detect_image();

        // 更新显示的图片
        iv_trash.setImageBitmap(mBitmap);
        // 更新垃圾分类的名称
        tv_waste_name.setText(class_names[maxIndex]);
        // 更新垃圾分类的介绍
        String text = class_names[maxIndex];
        if (text.contains("厨余垃圾"))
        {
            tv_trash_detail.setText(waste_detail[0]);
        } else if (text.contains("有害垃圾")) {
            tv_trash_detail.setText(waste_detail[1]);
        } else if (text.contains("可回收物")) {
            tv_trash_detail.setText(waste_detail[2]);
        } else if (text.contains("其他垃圾")) {
            tv_trash_detail.setText(waste_detail[3]);
        }

    }

    // 识别图片
    public void detect_image() {
        // bitmap convert to array
        float[][][][] pixels = getScaledMatrix(mBitmap, input);
        interpreter.run(pixels, output);

        for (int j = 0; j < output[0].length; j++) {
            BigDecimal b = new BigDecimal(output[0][j]);
            float f1 = b.setScale(3, BigDecimal.ROUND_HALF_UP).floatValue();
            Log.i("Test", f1 + "--> "+ j);
        }

        float max = output[0][0];

        for(int i = 1; i < output[0].length;i++){
            if(max < output[0][i]){
                max = output[0][i];
                maxIndex = i;
            }
        }

        String text = class_names[maxIndex];
        // 显示Toast
        showToast(text);
    }

        3.5 Android实际效果图       

基于TensorFlow2.3.0的垃圾分类

 

四、资料下载

        APK下载:https://wwi.lanzoup.com/itLZV0a53qni 密码:1a9y

        源码下载(包含数据集、模型文件、APP源码) https://
item.taobao.com/item.htm?ft=t&id=681383960366

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340