React-Native制作一个通过照片和视频识别鸟类的安卓app

前言

首先简单介绍一下这个app是干啥的,实际上我的标题已经差不多说完了.....就是用户可以上传带有鸟类的图片或者视频,然后就可以得到相应的识别效果,这个app的需求是来自于我的一位朋友,所以我就做出来了

正文

讲一下基本用到的技术栈吧,前端用的react-native,后端用的是flask,识别算法部分用的是yolov5,接下来我会从三个大方面讲一下学到的东西,也就是前端后端和识别算法这三个大方面.

前端

前端实际上是我第二次使用rn,算是有点经验了其实,这次我就直接用原生的rn框架创建了,而不是使用上次坑了我一次的expo框架.....,然后这次我又新学了一些东西

图标的使用

原先我想用图标总是傻傻的去用npm下载下来的库里的icon,然而这样非常的麻烦,经常出现失败的情况,而且搞不好要不去Android那个文件夹改一堆链接,于是我直接去例如iconfont-阿里巴巴矢量图标库这样的网站去下载png图标资源,然后用img标签展示就行,这样简单多了,唯一需要注意的大概就是记得把图片的名称改成英文的就成,不然打包的时候似乎会出问题....

redux的使用

有一说一,这是我第一次用redux,这里简单说一下redux的用法:

Redux是JavaScript的一个状态管理库,通常与React一起使用

它通过 centerX 全局单一的状态树[state tree]来存储整个应用的状态。改变状态的唯一方式就是触发动作[action],动作是一个描述发生了什么的纯对象。

Redux 的主要组成部分包括:

  1. Store:存储应用的完整状态。想象它就像你应用的"数据库"。

  2. Actions:表示一种对状态做出改变的方式。在Redux中,所有的改变都被明确化为动作。它们是一个带有 `type`属性和额外数据的简单JavaScript对象。

  3. Reducers: 是改变状态的唯一方式,其是纯函数,接收旧的 state 和一个 action,然后返回新的 state。 关于Redux的基本使用步骤如下:

Step 1:创建 Actions

javascript 复制代码
export const SOME_ACTION = 'SOME_ACTION';

export function doSomething()

{ return { type: SOME_ACTION, payload: "Action data" } }

Step 2:创建 Reducers

javascript 复制代码
import { SOME_ACTION } from '../actions/sampleActions';

export default function sampleReducer(state = initialState, action)

{ switch (action.type) { case SOME_ACTION: return Object.assign({}, state, action.payload); default: return state; } }

Step 3:创建 Store

javascript 复制代码
 import { createStore } from 'redux';

import rootReducer from './reducers';

let store = createStore(rootReducer);

Step 4:使用 Store

javascript 复制代码
import { Provider } from 'react-redux';

import { createStore } from 'redux';

import rootReducer from './reducers';

import App from './components/App';

let store = createStore(rootReducer);

render(

<Provider store={store}>

<App />

</Provider>,

document.getElementById('root') );

Step 5:在你的组件中使用 Redux Actions

javascript 复制代码
import { connect } from 'react-redux';

import { doSomething } from './actions/sampleActions';

function mapStateToProps(state){ return { stateProp: state.stateProp }; }

function mapDispatchToProps(dispatch){

return { doSomething: () => dispatch(doSomething())

}; }

class MyComponent extends React.Component{ componentDidMount(){ this.props.doSomething(); } render(){ // Render using this.props.stateProp and this.props.doSomething } }

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent); 

一些小吐槽

rn在很多方面挺方便的,但是我用下来总有些隔靴搔痒之感....或许之后我会转向原生的安卓开发()

后端

后端我是第一次用flask,所以先学了一下,大概了解了一下基本接口怎么写和怎么连接数据库就开写了,毕竟我本质上是crud,感觉基本需要说的就大概是怎么调用脚本

脚本调用

这里因为我用了python的虚拟环境,所以不能直接用python驱动脚本,而是要用特定的虚拟环境下的python文件来驱动,这里是一点需要注意的.然后

python 复制代码
@app.route('/video', methods=['POST'])
def video():
    print("Video route started.")
    
    if 'video' not in request.files:
        return 'No video file part', 400

    file = request.files['video']
    if file.filename == '':
        return 'No video file selected', 400
    
    temp_dir = tempfile.TemporaryDirectory() 
    input_video_path = os.path.join(temp_dir.name, 'input.mp4')

    file.save(input_video_path) 
    print(f"Saved video file to {input_video_path}")

    result = run_yolo_video(input_video_path) 

    temp_dir.cleanup()
    
    return jsonify({"data": result}), 200

def run_yolo_video(input_video_path): 
    print("YOLO video function started.")
    model_path = "/etc/nginx/code/birdsearch/yolov5/weights/best.pt"
    command = f"python ../yolov5/detect.py --weights {model_path} --source {input_video_path}"
    print(f"Running command {command}")
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    output = stderr.decode("utf-8")
    print(f"Received output: {output}")

    return output

然后需要讲一下大概就是我这边读取控制台输出的操作:

这个函数 `run_yolo_video(input_video_path)` 是用来通过 YOLO (You Only Look Once) 模型对输入路径下的视频进行对象检测的。

解读这个函数:

  1. `print("YOLO video function started.")`: 输出提示信息,表示 YOLO 视频函数已经开始运行。

  2. `model_path = "/etc/nginx/code/birdsearch/yolov5/weights/best.pt"`: 这一行定义了模型路径。也就是说,YOLO 模型权重文件被存储在 "/etc/nginx/code/birdsearch/yolov5/weights/best.pt" 路径下。

  3. `command = f"python ../yolov5/detect.py --weights {model_path} --source {input_video_path}"`: 通过 Python 运行 YOLO 定位脚本 `detect.py`。`--weights {model_path}`选项指定了模型权重文件的路径。`--source {input_video_path}`选项则定义了要处理的输入视频的路径。

  4. `print(f"Running command {command}")`: 打印将要运行的命令。

  5. `process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)`: 使用 `subprocess` 模块运行上面定义的命令。`Popen` 函数创建一个新的进程来运行这个命令,`shell=True` 参数表示通过 shell 运行该命令,`stdout=subprocess.PIPE` 和 `stderr=subprocess.PIPE` 则表示我们想要捕获命令的标准输出和错误输出。

  6. `stdout, stderr = process.communicate()`: `communicate` 方法等待进程结束,然后返回一个元组,包含进程的标准输出和错误输出。

  7. `output = stderr.decode("utf-8")`: `decode` 函数将错误输出(该输出以字节形式存在)转换为字符串。

  8. `print(f"Received output: {output}")`: 打印从 `detect.py` 脚本收到的输出。

yolov5算法

这个其实没啥好说的,就是找开源数据集然后设置好参数,用yolov5train就完事了,很简单,我还租了一个4090服务器进行训练,这样快一点()

结语

总之这个项目顺利完结了,最终打包的apk也给我的那位朋友了,总之差不多就是这样!!!!

相关推荐
le1616164 分钟前
Android 依赖种类及区别:远程仓库依赖、打包依赖、模块依赖、本地仓库依赖
android
lxysbly4 分钟前
psp模拟器安卓版带金手指
android
q_302381955633 分钟前
Atlas200DK 部署 yolov11 调用海康威视摄像头实现实时目标检测
人工智能·yolo·目标检测
云上凯歌1 小时前
02 Spring Boot企业级配置详解
android·spring boot·后端
hqiangtai1 小时前
Android 高级专家技术能力图谱
android·职场和发展
aqi001 小时前
FFmpeg开发笔记(九十七)国产的开源视频剪辑工具AndroidVideoEditor
android·ffmpeg·音视频·直播·流媒体
stevenzqzq1 小时前
Android Koin 注入入门教程
android·kotlin
小二·2 小时前
Python Web 全栈开发实战教程:基于 Flask 与 Layui 的待办事项系统
前端·python·flask
炼金术2 小时前
SkyPlayer v1.1.0 - 在线视频播放功能更新
android·ffmpeg
用户276038157812 小时前
鲲鹏+昇腾:开启 AI for Science 新范式——基于PINN的流体仿真加速实践
android