手把手教你搭建第一个Android手机AI图像识别项目
在计算机视觉领域,把训练好的模型搬到移动端,是一件既让人兴奋又有点棘手的事。这里整理了从数据集准备、模型训练、Web部署、API封装,到最终在Android手机上调用API的全链路流程。整个过程不走捷径,但每一步都有清晰的代码和注释,希望能帮到正在做类似项目的你。 一、准备数据集,训练AI模型 搭建
在计算机视觉领域,把训练好的模型搬到移动端,是一件既让人兴奋又有点棘手的事。这里整理了从数据集准备、模型训练、Web部署、API封装,到最终在Android手机上调用API的全链路流程。整个过程不走捷径,但每一步都有清晰的代码和注释,希望能帮到正在做类似项目的你。
一、准备数据集,训练AI模型
搭建深度学习环境这件事就不展开说了,Python生态里该装的库一个都不能少。工程的目录结构和数据集组织方式如下图所示。


数据读取与预处理是模型训练的第一步,read_data.py 把杂乱的文件转化为模型能消化的张量。来看这段代码:
import os
from PIL import Image
import numpy as np
from sklearn.model_selection import train_test_split
from keras.utils import np_utils
import random
class_num = 8 # 类别数
def preprocess(x):
Max = np.max(x)
Min = np.min(x)
x = (x - Min) / (Max - Min)
return x * 2 - 1
def read_img(img_name, size, c):
im = Image.open(img_name)
im = im.resize((size, size))
im = im.convert("L") if c == 1 else im.convert("RGB")
data = np.array(im)
return data
def read_label(img_name):
basename = os.path.basename(img_name)
label = basename.split('_')[0]
return label
def get_data(pt, size=64, c=1, shuffle=True, test_size=0.2):
images, labels = [], []
i = 0
for x in os.listdir(pt):
d = os.path.join(pt, x)
images.append(read_img(d, size=size, c=c))
labels.append(read_label(d)[0])
i += 1
if shuffle == True:
imgs, lbs = [], []
index = [x for x in range(len(labels))]
random.shuffle(index)
for i in index:
imgs.append(images[i])
lbs.append(labels[i])
images, labels = imgs, lbs
y = np.array(list(map(int, labels)))
x = np.array(images)
x = x.reshape(len(x), size, size, c)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=test_size, random_state=0)
y_train = np_utils.to_categorical(y_train, class_num)
y_test = np_utils.to_categorical(y_test, class_num)
x_train = preprocess(x_train).astype('float32')
x_test = preprocess(x_test).astype('float32')
print(len(x_train), len(y_train))
print(len(x_test), len(y_test))
return (x_train, y_train, x_test, y_test)
接着是CNN模型的构建与训练,cnn01.py 里定义了一个多层卷积网络,加上批标准化、Dropout防止过拟合,最终用Softmax输出8个类别的概率。
from keras import Input, Model
from keras.layers import Conv2D, MaxPool2D, BatchNormalization
from keras.layers import Dropout, Flatten, Dense
import matplotlib.pyplot as plt
from read_data import get_data
pt = "data"
size = 64
classes = 8
c = 3
batch_size = 128
epochs = 20
name = './result/cnn01C64'
def model_():
inputs = Input((size, size, c))
x = BatchNormalization(axis=-1)(inputs)
x = Conv2D(128, (3, 3), activation='relu')(x)
x = Conv2D(64, (3, 3), activation='relu')(x)
x = MaxPool2D((2, 2))(x)
x = Dropout(0.6)(x)
x = Conv2D(64, (3, 3), activation='relu')(x)
x = MaxPool2D((2, 2))(x)
x = Dropout(0.65)(x)
x = Flatten()(x)
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dropout(0.6)(x)
outputs = Dense(classes, activation='softmax')(x)
model = Model(inputs=inputs, outputs=outputs)
return model
def train_model(epochs):
model = model_()
model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
x_train, y_train, x_test, y_test = get_data(pt=pt, size=size, c=c)
result = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=epochs)
model.sa ve(name + '.h5')
return result
def result_curve(result):
# 绘制训练曲线
# 略……(与原文一致)
执行 cnn01.py 后,训练好的模型会保存为 result/cnn01C64.h5。
移动端不能直接跑h5格式,得转成轻量的 .tflite。 h5_2_tflite.py 完成转换并顺便做个测试。
import tensorflow as tf
import numpy as np
from PIL import Image
from read_data import preprocess
def h5_to_tflite(in_f, out_f):
model = tf.keras.models.load_model(in_f)
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
with open(out_f, 'wb') as f:
f.write(tflite_model)
def test(model_path, img_file, size, c):
img = Image.open(img_file)
im = img.resize((size, size))
im = im.convert("L") if c == 1 else im.convert("RGB")
x = np.array(im)
x = np.reshape(x, (1, size, size, c))
x = preprocess(x)
x = x.astype(np.float32)
interpreter = tf.lite.Interpreter(model_path)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
interpreter.set_tensor(input_details[0]['index'], x)
interpreter.invoke()
output = interpreter.get_tensor(output_details[0]['index'])
y = np.argmax(output, axis=1)[0]
print(y)
转换完成后,就能在边缘设备上愉快地推理了。
二、Web服务器部署测试及API封装
光有模型不够,得把它变成一个能对外提供服务的接口。前端页面 templates/index.html 提供了一个简单的文件上传表单,后端 app.py 用Flask搭建,同时提供了网页端和API端两种请求方式。
from flask import Flask, render_template, request, jsonify
import tensorflow as tf
import numpy as np
from PIL import Image
import os
app = Flask(__name__)
model = tf.keras.models.load_model("./result/cnn01C64.h5")
img_size = 64
img_channel = 3
dct = {0: '苹果', 1: '香蕉', 2: '樱桃', 3: '火龙果', 4: '芒果', 5: '橘子', 6: '木瓜', 7: '菠萝'}
def preprocess(filepath):
img = Image.open(filepath)
img = img.convert("RGB")
img = img.resize((img_size, img_size))
img = np.array(img) / 255.0
img = img.reshape(1, img_size, img_size, img_channel)
return img
def predict(filepath):
img = preprocess(filepath)
pred = model.predict(img)
result = np.argmax(pred)
result = dct.get(result)
confidence = np.max(pred)
return result, confidence
# ... 路由和API接口代码(与原文一致)
记得把 host 改成你自己的IP地址。下面是Web端的运行效果。

API接口测试脚本 api_test.py 用 requests 发送图片,返回JSON结果。
import requests
url = "http://192.168.1.5:8086/api/predict"
files = {"file": open("test.jpg", "rb")}
response = requests.post(url, files=files)
results = response.json()
result = results.get('result')
confidence = results.get('confidence')
print(f"识别结果:{result} 置信度:{round(confidence,3)}")
测试结果如图。

三、Android手机端调用API
移动端的部署往往是最容易出问题的一环,不过有了前面的API,Android这边只需要做一件事:把图片发过去,把结果拿回来。
先搭建Android开发环境,选择“Empty Views Activity”模板,语言用Ja va。记得换国内镜像源——这一步能省下不少等待编译的时间。
修改 gradle/wrapper/gradle-wrapper.properties

distributionUrl=https://mirrors.aliyun.com/macports/distfiles/gradle/gradle-9.2.1-bin.zip
修改 settings.gradle.kts

ma ven { setUrl("https://ma ven.aliyun.com/repository/central") }
ma ven { setUrl("https://ma ven.aliyun.com/repository/jcenter") }
ma ven { setUrl("https://ma ven.aliyun.com/repository/google") }
ma ven { setUrl("https://ma ven.aliyun.com/repository/gradle-plugin") }
ma ven { setUrl("https://ma ven.aliyun.com/repository/public") }
ma ven { setUrl("https://jitpack.io") }
google()
界面设计都在 activity_main.xml 里,一个ImageView显示图片,三个按钮(选择、拍照、API识别),还有两个TextView显示结果和置信度。
网络请求用了 OkHttp,封装了一个 ApiCaller 类,处理异步回调。别忘了在 app/build.gradle.kts 中添加依赖。
implementation("com.squareup.okhttp3:okhttp:4.12.0")
接着是 MainActivity.ja va,处理相册选择、拍照、点击识别三个事件。识别时调用 ApiCaller.uploadBitmap,在回调中解析JSON,更新UI。
// 代码与原文一致
Android 9+ 默认禁止明文HTTP,需要配置网络安全策略。在 res/xml/network_security_config.xml 中放行。
同时在 AndroidManifest.xml 中声明网络权限并引用该配置。
最后,APP的测试效果如图所示。

整个流程走下来,你会发现从数据到手机其实只隔了几层皮。关键在于每一步的衔接要清晰,代码要可复用。希望这份记录能给你带来一些启发。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
跨境物流AI Agent感知决策全链路自动化技术拆解
2026年,跨境物流领域正迎来一场根本性变革——从“被动记录”全面迈向“主动执行”,AI智能体正在重塑整个行业格局。 你可能已经深有体会:每天一到岗,光是后台处理货件创建、物流追踪等重复操作,就要耗费数小时之久。行业调研数据显示,超过60%的运营人员每天至少花费2小时在这些机械性劳动上,而手动操作引
天学会AI应用开发第十二课:从PDF、Word和网页构建RAG
上一篇文章介绍了如何从TXT文件中读取文本内容,但在日常办公场景中,纯文本文件的使用频率并不高。更常见的需求是处理PDF、Word等文档格式,同时还需要从网页中提取知识信息。 因此,本篇文章将重点讲解如何从PDF、Word以及网页中提取内容,并将其应用于RAG(检索增强生成)系统。 一、从PDF文件
Hy3+WorkBuddy组合国产顶级Agent附完整提示词
五个 Case 跑完,总结一下整体体验。工具使用能力:能不能自己开网页、找信息、标出处。规划能力:能不能把多约束需求拆成可执行步骤。长程执行能力:跨多步任务时会不会丢状态。复杂推理能力:能不能先推导、再写代码、再执行验证。WorkBuddy+Hy3 的表现完全符合预期。趁着 WorkBuddy 里的
AI Agent是什么?一文理解大语言模型、记忆、技能、工具、MCP、工作流与上下文
智能体并非单一模型,而是由大语言模型、记忆、工具、工作流等模块协同构成的自主系统。它通过理解目标、检索记忆、调用工具、构建上下文、推理决策,并基于反馈闭环持续迭代,最终自主完成复杂任务。
DeepSeek决定自研芯片打造人工智能全新算力芯脏
被“逼”出来的第三条路。 一直以模型技术见长的DeepSeek,这次在算力供应链上迈出了让所有人侧目的一步。 2026年7月7日,路透社援引三位知情人士消息,DeepSeek正在悄然开发自有AI芯片。值得玩味的是,这颗芯片的定位非常精准——专攻推理,不涉足训练。消息人士称,项目大约启动于一年前,目前
- 热门数据榜
相关攻略
2026-07-11 16:50
2026-07-11 16:50
2026-07-11 16:50
2026-07-11 16:50
2026-07-11 16:28
2026-07-11 16:28
2026-07-11 14:38
2026-07-11 14:38
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

