从零开始:使用 Cython + JNI 在 Android 上运行 Python 算法
1. 引言
在 Android 设备上运行 Python 代码通常面临性能、兼容性和封装等挑战。尤其是当你希望在 Android 应用中使用 Python 编写的计算密集型算法时,直接运行 Python 代码可能导致较高的 CPU 占用和较差的性能。为了解决这个问题,我们可以使用 Cython 将 Python 代码编译成 C 扩展,并通过 JNI(Java Native Interface) 在 Android 上调用这些 C 代码,从而实现高效的 Python 代码执行。
本教程将介绍如何在 Android 设备上使用 Cython 和 JNI,将 Python 代码转换为 Android 可用的本地库,并通过 Java 代码调用它。我们将以一个简单的 手势识别 算法为例,展示完整的实现过程。
2. 项目概述
本教程的目标是:
- 使用 Cython 将 Python 代码转换为 C 语言扩展,提高执行效率。
- 使用 JNI 将 C 语言扩展封装成 Android 可调用的库。
- 在 Android App 中集成 并调用这个 Python 代码转换的本地库。
我们假设你的 Python 代码是一个 基于 MediaPipe 的手部关键点检测算法,并希望它在 Android 设备上运行并返回检测结果。
3. 环境准备
在开始之前,确保你已经安装了以下工具和软件:
- Android Studio(用于 Android 开发)
- NDK(Native Development Kit)(用于编译 JNI 代码)
- Python 3.x
- Cython
- Linux 或 Windows 环境
- 一个 Python 代码库(包含手势识别算法)
如果你使用的是 Windows,建议安装 WSL(Windows Subsystem for Linux) 或者使用 MSYS2 进行交叉编译。
4. 准备 Python 代码
首先,我们假设你已经有一个 Python 代码 hand_tracking.py
,该代码使用 MediaPipe 识别手部关键点,并返回关键点坐标。
hand_tracking.py
import mediapipe as mp
import cv2
import numpy as npmp_hands = mp.solutions.hands
hands = mp_hands.Hands()def detect_hand(image):image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)results = hands.process(image)if results.multi_hand_landmarks:return [(lm.x, lm.y) for lm in results.multi_hand_landmarks[0].landmark]return []
该函数接收 OpenCV 读取的 image
,然后使用 MediaPipe 进行手部关键点检测,并返回关键点的 (x, y) 坐标。
5. 使用 Cython 将 Python 代码转换为 C 语言
5.1 编写 Cython 代码
Cython 允许我们将 Python 代码编译为 C 语言模块,从而提高执行效率。我们需要创建 hand_tracking.pyx
并将 hand_tracking.py
代码迁移到 Cython 代码中。
hand_tracking.pyx
from libc.stdlib cimport malloc, free
import mediapipe as mp
import cv2
import numpy as np
cimport numpy as npmp_hands = mp.solutions.hands
hands = mp_hands.Hands()def detect_hand(unsigned char[:] image_data, int width, int height):cdef np.ndarray[np.uint8_t, ndim=3] image = np.array(image_data).reshape((height, width, 3))image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)results = hands.process(image)if results.multi_hand_landmarks:return [(lm.x, lm.y) for lm in results.multi_hand_landmarks[0].landmark]return []
这里的 detect_hand
现在使用了 Cython 的类型注解,从而提高执行效率。
5.2 创建 setup.py
编译 Cython 代码
from setuptools import setup
from Cython.Build import cythonize
import numpysetup(ext_modules=cythonize("hand_tracking.pyx"),include_dirs=[numpy.get_include()]
)
运行以下命令进行编译:
python setup.py build_ext --inplace
成功后会生成一个 .so
或 .pyd
文件,这是我们的 C 语言扩展。
6. 使用 JNI 调用 Cython 生成的 C 代码
6.1 创建 JNI C 代码
在 jni/
目录下创建 hand_tracking_jni.c
:
#include <jni.h>
#include <stdio.h>JNIEXPORT jstring JNICALL
Java_com_example_myapp_HandTracking_detectHand(JNIEnv *env, jobject thiz, jbyteArray imageData, jint width, jint height) {// 这里调用 Cython 生成的 C 代码return (*env)->NewStringUTF(env, "手势检测结果");
}
6.2 配置 Android.mk
和 Application.mk
Android.mk
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
LOCAL_MODULE := hand_tracking
LOCAL_SRC_FILES := hand_tracking_jni.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := armeabi-v7a arm64-v8a
APP_PLATFORM := android-21
然后使用 NDK 编译:
ndk-build
7. 在 Android App 中调用本地库
在 MainActivity.java
中调用 JNI 代码:
package com.example.myapp;public class HandTracking {static {System.loadLibrary("hand_tracking");}public native String detectHand(byte[] imageData, int width, int height);
}
在 MainActivity.java
里调用:
HandTracking handTracking = new HandTracking();
String result = handTracking.detectHand(imageData, width, height);
Log.d("HandTracking", "检测结果: " + result);
8. 运行和调试
-
构建 Cython 代码:
python setup.py build_ext --inplace
-
使用 NDK 编译 JNI 代码:
ndk-build
-
运行 Android Studio 并在真机上测试。
如果运行成功,你应该能看到 Java 代码成功调用了 detect_hand
,并返回了手势检测的结果。
9. 结论
本教程展示了如何 使用 Cython + JNI 在 Android 上运行 Python 代码,实现高效的 Python 计算逻辑封装到 Android 应用中。你可以使用相同的方法,将 机器学习、图像处理、语音识别等 Python 代码迁移到 Android,大大提升 Android 设备上的 AI 处理能力。
如果你想进一步优化,可以考虑:
- 使用 TensorFlow Lite 替代 MediaPipe
- 使用 OpenCL / Vulkan 进行 GPU 加速
- 封装多个 Python 模块 到动态库
希望本教程对你有所帮助!🚀
相关文章:
从零开始:使用 Cython + JNI 在 Android 上运行 Python 算法
1. 引言 在 Android 设备上运行 Python 代码通常面临性能、兼容性和封装等挑战。尤其是当你希望在 Android 应用中使用 Python 编写的计算密集型算法时,直接运行 Python 代码可能导致较高的 CPU 占用和较差的性能。为了解决这个问题,我们可以使用 Cytho…...
开源软件许可证冲突的原因和解决方法
1、什么是开源许可证以及许可证冲突产生的问题 开源软件许可证是一种法律文件,它规定了软件用户、分发者和修改者使用、复制、修改和分发开源软件的权利和义务。开源许可证是由软件的版权所有者(通常是开发者或开发团队)发布的,它…...
stratis,容器podman
一、stratis 1.stratis可以实现动态的在线扩容,lvm虽然也可以实现在线扩容,但是是需要人为的手动扩容。 2.stratis不需要手动格式化,自动会创建文件系统(默认是xfs) 1. 安装stratis软件包 yum list | grep stratis…...
解决用three.js展示n个叠加的stl模型文件错位的问题
加载stl时可以明显看到下面有一部分模型是错位的。 将stl文件格式转化为glb 使用免费将 STL 转换为 GLB - ImageToStl 模型就没有错位了 代码如下 <template><div ref"threeContainer" class"three-container"></div></template&…...
从零开始实现 C++ TinyWebServer 数据库连接池 SqlConnectPool详解
文章目录 数据库连接池是什么?Web Server 中为什么需要数据库连接池?SqlConnectPool 成员变量实现 Init() 函数实现 ClosePool() 函数SqlConnectRAII 类SqlConnectPool 代码SqlConnectPool 测试 从零开始实现 C TinyWebServer 项目总览 项目源码 数据库连…...
利用ffmpeg库实现音频AAC编解码
AAC(Advanced Audio Coding)是一种音频编码技术,出现于1997年,基于MPEG-2的音频编码技术。AAC具有高效的数据压缩能力和较高的音质,适用于各种音频应用场景。例如,在智能设备中,AAC技术被广泛…...
Vue + CSS实现渐变栅格进度条
进度条作为可视化大屏系统中展示数据状态的关键元素,其视觉效果直接影响用户的使用体验,而传统的进度条往往呈现出固定的样式,缺乏视觉吸引力。在这种场景下,一种基于Vue和CSS实现渐变栅格进度条的方法应运而生,该方法…...
算法模型从入门到起飞系列——背包问题(探索最大价值的掘金之旅)
文章目录 前言一、背包问题溯源(动态规划)1.1 动态规划的概念1.2 动态规划的基本步骤1.3 动态规划的实际应用 二、背包问题2.1 背包问题衍生2.2 0-1背包2.2.1 0-1背包描述2.2.2 0-1背包图解2.2.3 0-1背包代码刨析 2.3 完全背包2.3.1 完全背包描述2.3.2 完…...
蓝桥杯—迷宫(bfs)
一.题目 分析:最短路径问题,给定一个迷宫,从左上角走到右下角,要求路径最短,并且要求字典序最小,也就是按照D,L,R,U,的搜索顺序去搜索,否则路径不是唯一的&am…...
【Android】安卓 Java下载ZIP文件并解压(笔记)
写在前面的话 在这篇文章中,我们将详细讲解如何在 Android 中通过 Java 下载 ZIP 文件并解压,同时处理下载进度、错误处理以及优化方案。 以下正文 1.权限配置 在 AndroidManifest.xml 中,我们需要添加相应的权限来确保应用能够访问网络和设…...
清晰易懂的 PHP 安装与配置教程
初学者也能看懂的 PHP 安装与配置教程 本教程将手把手教你如何在 Windows 系统上安装 PHP,并配置 Composer(PHP 的依赖管理工具)的缓存位置,即使你是零基础小白,也能轻松完成! 一、准备工作 操作系统&…...
Ceph集群2025(Squid版)快速对接K8S cephFS文件存储
ceph的块存储太简单了。所以不做演示 查看集群 创建一个 CephFS 文件系统 # ceph fs volume create cephfs01 需要创建一个子卷# ceph fs subvolume create cephfs01 my-subvol -----------------#以下全部自动创建好 # ceph fs ls name: cephfs01, metadata pool: c…...
Linux进程控制(四)之进程程序替换
文章目录 进程程序替换单进程版程序替换替换原理多进程版程序替换替换函数函数解释小知识 命名理解 进程程序替换 如果要让子进程执行与父进程完全不同的代码,就要进行进程程序替换。 单进程版程序替换 执行一个可执行文件 makefile mycommand:mycommand.cgcc -…...
python-selenium 爬虫 由易到难
本质 python第三方库 selenium 空值 浏览器驱动 浏览器驱动控制浏览器 推荐 edge 浏览器驱动(不容易遇到版本或者兼容性的问题) 驱动下载网址:链接: link 1、实战1 (1)安装 selenium 库 pip install selenium&#…...
希尔排序
希尔排序是一种改进的插入排序算法,它通过将原始数据分成多个子序列来改善插入排序的性能,每个子序列的元素间隔为 d(增量)。随着算法的进行,d 逐渐减小,最终减为 1,此时整个序列就被排序好了。…...
Pydantic Mixin:构建可组合的验证系统体系
title: Pydantic Mixin:构建可组合的验证系统体系 date: 2025/3/22 updated: 2025/3/22 author: cmdragon excerpt: Pydantic的Mixin模式通过继承组合实现校验逻辑复用,遵循以Mixin后缀命名、不定义初始化方法等设计原则。支持基础校验模块化封装与多策略组合,如电话号码…...
策略模式 vs. 工厂模式:对比与分析
相同点 解耦思想 两者都通过接口/抽象类将实现与调用方解耦,降低模块间的直接依赖。 符合开闭原则 新增策略或产品时,只需扩展新类,无需修改已有代码。 封装变化 策略模式封装算法的变化,工厂模式封装对象创建的变化。 不同…...
RK3568 I2C底层驱动详解
前提须知:I2C协议不懂的话就去看之前的内容吧,这个文章需要读者一定的基础。 RK3568 I2C 简介 RK3568 支持 6 个独立 I2C: I2C0、I2C1、I2C2、I2C3、I2C4、I2C5。I2C 控制器支持以下特性: ① 兼容 i2c 总线 ② AMBA APB 从接口 ③ 支持 I2C 总线主模式…...
【大语言模型_8】vllm启动的模型通过fastapi封装增加api-key验证
背景: vllm推理框架启动模型不具备api-key验证。需借助fastapi可以实现该功能 代码实现: rom fastapi import FastAPI, Header, HTTPException, Request,Response import httpx import logging# 创建 FastAPI 应用 app FastAPI() logging.basicConfig(…...
hadoop-HDFS操作
1. 使用的是hadoop的用户登录到系统,那么 cd ~ 是跳转到/home/hadoop下。 2. 在操作hdfs时,需要在hadoop用户下的/usr/local/hadoop,此时是在根目录下。 cd /usr/local/hadoop或者cd / cd usr/local/hadoop 3. 回到Linux的操作目录 我们把…...
Mysql 安装教程和Workbench的安装教程以及workbench的菜单栏汉化
Mysql 安装教程和Workbench的安装教程 详细请参考我的文件 Mysql 安装教程和Workbench的安装教程 或者下载我的资源Mysql 安装教程和Workbench的安装教程 汉化菜单 英文版菜单文件:下载链接 汉化版菜单文件:下载链接 默认情况下,安…...
失物招领|校园失物招领系统|基于Springboot的校园失物招领系统设计与实现(源码+数据库+文档)
校园失物招领系统目录 目录 基于Springboot的校园失物招领系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、 管理员功能实现 (1) 失物招领管理 (2) 寻物启事管理 (3) 公告管理 (4) 公告类型管理 2、用户功能实现 (1) 失物招领 (2) 寻物启事 (3) 公告 …...
一条不太简单的TEX学习之路
目录 rule raisebox \includegraphics newenviro 、\vspace \stretch \setlength 解释: 总结: 、\linespread newcommand \par 小四 \small simple 、mutiput画网格 解释: 图案解释: xetex pdelatex etc index 报…...
如何为AI开发选择合适的服务器?
选择适合的服务器可以为您的AI项目带来更高的效率,确保最佳性能、可扩展性和可靠性,从而实现无缝的开发与部署。 选择适合的AI开发服务器可能并不容易。您需要一台能够处理大量计算和大型数据集的服务器,同时它还需要符合您的预算并易于管理…...
doris:审计日志
Doris 提供了对于数据库操作的审计能力,可以记录用户对数据库的登陆、查询、修改操作。在 Doris 中,可以直接通过内置系统表查询审计日志,也可以直接查看 Doris 的审计日志文件。 开启审计日志 通过全局变量 enable_audit_plugin 可以随时…...
CSS中的transition与渐变
目录 一、CSS transition 1. 核心属性 简写语法 2. 子属性详解 2.1 transition-property 2.2 transition-duration 2.3 transition-timing-function 2.4 transition-delay 3. 使用场景示例 3.1 悬停效果(Hover) 3.2 展开/收起动画 3.3 动态移…...
AI + 医疗 Qwq大模型离线本地应用
通义千问Qwq-32b-FP16可用于社区医院、乡镇卫生院、诊所等小型医疗机构,替代专业合理用药系统,作为药品知识库,实现以下功能: 药品信息智能查询:检索药品的详细说明书、适应症、禁忌症、不良反应及药物相互作用等关键信…...
大数据环境搭建
目录 一:虚拟机:VirtualBox 二:Shell工具:MobaXterm 三:安装脚本 四:JDK和Hadoop 4.1:安装 4.2:启动 4.3:Hadoop可视化访问 4.4:关机 一:虚拟机:VirtualBox Virt…...
七天免登录 为什么不能用seesion,客户端的http请求自动携带cookei的机制(比较重要)涉及HTTP规范
如果是七天免登录,和session肯定没关系,因为session不能持久化,主要是客户端一旦关闭,seesion就失效了/// 所以必须是能持久化的,这就清晰了,要莫在的服务器保存,要摸在客户端设置 cook机制 1. 使用Cookie实现七天免登录 前端(登…...
从PGC到AIGC:海螺AI多模态内容生成系统的技术革命
一、内容生产的范式迁移:从PGC到AIGC的进化之路 在数字内容生产的历史长河中,人类经历了三次重大范式转变:专业生成内容(PGC)的工业化生产、用户生成内容(UGC)的全民创作浪潮,以及当…...
常考计算机操作系统面试习题(三上)
目录 1. 为何要引入与设备的无关性?如何实现设备的独立性? 2. 页面置换先进先出算法 3. 页面置换先进先出算法,4个页框 4. 进程优先级调度算法 5. 短作业优先调度策略 6. 平均内存访问时间计算 7. 页式存储和段式存储的物理地址计算 …...
数据结构之双向链表-初始化链表-头插法-遍历链表-获取尾部结点-尾插法-指定位置插入-删除节点-释放链表——完整代码
数据结构之双向链表-初始化链表-头插法-遍历链表-获取尾部结点-尾插法-指定位置插入-删除节点-释放链表——完整代码 #include <stdio.h> #include <stdlib.h>typedef int ElemType;typedef struct node{ElemType data;struct node *next, *prev; }Node;//初化链表…...
一键部署 GPU Kind 集群,体验 vLLM 极速推理
随着 Kubernetes 在大模型训练和推理领域的广泛应用,越来越多的开发者需要在本地环境中搭建支持 GPU 的 Kubernetes 集群,以便进行测试和开发。大家都知道,本地搭建 Kubernetes 集群通常可以使用 Kind(Kubernetes IN Docker&#…...
C/C++蓝桥杯算法真题打卡(Day6)
一、P8615 [蓝桥杯 2014 国 C] 拼接平方数 - 洛谷 方法一:算法代码(字符串分割法) #include<bits/stdc.h> // 包含标准库中的所有头文件,方便编程 using namespace std; // 使用标准命名空间,避免每次调用…...
【C++】入门
1.命名空间 1.1 namespace的价值 在C/C中,变量,函数和后面要学到的类都是大量存在的,这些变量,函数和类的名称将存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,…...
CUDA 学习(2)——CUDA 介绍
GeForce 256 是英伟达 1999 年开发的第一个 GPU,最初用作显示器上渲染高端图形,只用于像素计算。 在早期,OpenGL 和 DirectX 等图形 API 是与 GPU 唯一的交互方式。后来,人们意识到 GPU 除了用于渲染图形图像外,还可以…...
构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据
构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据 概述 本文将指导开发者构建一个MCP(Model Control Protocol)天气服务器,通过暴露get-alerts和get-forecast工具,为Claude for Desktop等客户端提供实时天气数据支持。该方案解决了传统LLM无法直接获取天气…...
[Lc_2 二叉树dfs] 布尔二叉树的值 | 根节点到叶节点数字之和 | 二叉树剪枝
目录 1.计算布尔二叉树的值 题解 2.求根节点到叶节点数字之和 3. 二叉树剪枝 题解 1.计算布尔二叉树的值 链接:2331. 计算布尔二叉树的值 给你一棵 完整二叉树 的根,这棵树有以下特征: 叶子节点 要么值为 0 要么值为 1 ,其…...
搜广推校招面经五十六
字节推荐算法 一、Attention的复杂度是多少? 见【搜广推校招面经三十八】 二、如何对普适性强的物品(如新华字典)设计指标进行降权 2.1. 问题背景 普适性强的物品(如新华字典)在推荐系统或搜索排序中可能频繁出现…...
ZYNQ的cache原理与一致性操作
在Xilinx Zynq SoC中,Cache管理是确保处理器与外部设备(如FPGA逻辑、DMA控制器)之间数据一致性的关键。Zynq的ARM Cortex-A9处理器包含L1 Cache(指令/数据)和L2 Cache,其刷新(Flush/Invalidate&…...
安装React开发者工具
我们在说组件之前,需要先安装一下React官方推出的开发者工具,首先我们分享在线安装方式 首先打开谷歌网上应用商店(针对谷歌浏览器),在输入框内搜索react,安装如下插件: 注意安装提供方为Facebook的插件,这…...
多层感知机
多层感知机(Multilayer Perceptron,简称 MLP)是一种基于前馈神经网络(Feedforward Neural Network)的深度学习模型,由多个神经元层组成,每一层与前一层全连接。它包括至少一个隐藏层(…...
2025年渗透测试面试题总结- PingCAP安全工程师(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 PingCAP安全工程师 一、SQL注入判断数据库类型技术分析 1. 常规判断方法 2. 盲注场景下的判断 3. 补…...
CAD模型导入Geant4
CADMesh是一个开源项目,专门用于将STL格式的CAD模型导入Geant4。以下是使用CADMesh操作STL模型的步骤: 准备工作 下载CADMesh开源代码:可以从GitHub或Gitee下载CADMesh的开源代码。 将CAD模型转换为STL格式:在CAD软件中创建几何…...
DeepSORT 目标追踪算法详解
DeepSORT(Deep Simple Online and Realtime Tracking)是 多目标追踪(MOT) 领域的经典算法,通过结合目标检测、运动预测和外观特征匹配,实现了高效、稳定的实时追踪。其核心思想是通过 检测驱动追踪…...
mne溯源后的数据初步处理方法
文章目录 导入库 Yeo2011_7Networks_N1000绘制一些圆球来代表区域大小和强度 单网络绘制和扩展的方式AI补充一下背景知识📚 **背景与研究来源**🧠 **7 个功能网络的定义**📂 **标签数据获取**🔍 **标签文件内容解析**🛠…...
基于STM32进行FFT滤波并计算插值DA输出
文章目录 一、前言背景二、项目构思1. 确定FFT点数、采样率、采样点数2. 双缓存设计 三、代码实现1. STM32CubeMX配置和HAL库初始化2. 核心代码 四、效果展示和后话五、项目联想与扩展1. 倍频2. 降频3. 插值3.1 线性插值3.2 样条插值 一、前言背景 STM32 对 AD 采样信号进行快…...
【用 Trace读源码】PlanAgent 执行流程
前提条件 在 Trae 中打开 OpenManus 工程,使用 build 模式,模型选择 claude-sonnet-3.7 提示词 分析 agent/planning.py 中 main 方法及相关类的执行流程,以流程图的方式展示PlanningAgent 执行流程图 以下流程图展示了 PlanningAgent 类…...
AI代码编辑器:Cursor和Trae
Cursor 定义:Cursor 是一款基于AI的代码编辑器,它继承了VS Code的核心功能,并在此基础上增加了深度AI支持。它支持代码生成、优化、重构以及调试等功能,提供直观的Diff视图和自动补全功能,是一款功能强大的编程工具。…...
LSM-Tree(Log-Structured Merge-Tree)详解
1. 什么是 LSM-Tree? LSM-Tree(Log-Structured Merge-Tree)是一种 针对写优化的存储结构,广泛用于 NoSQL 数据库(如 LevelDB、RocksDB、HBase、Cassandra)等系统。 它的核心思想是: 写入时只追加写(Append-Only),将数据先写入内存缓冲区(MemTable)。内存数据满后…...