從零開始:使用 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. 項目概述

本教程的目標是:

  1. 使用 Cython 將 Python 代碼轉換為 C 語言擴展,提高執行效率。
  2. 使用 JNI 將 C 語言擴展封裝成 Android 可調用的庫。
  3. 在 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.mkApplication.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. 運行和調試

  1. 構建 Cython 代碼

    python setup.py build_ext --inplace
    
  2. 使用 NDK 編譯 JNI 代碼

    ndk-build
    
  3. 運行 Android Studio 并在真機上測試

如果運行成功,你應該能看到 Java 代碼成功調用了 detect_hand,并返回了手勢檢測的結果。


9. 結論

本教程展示了如何 使用 Cython + JNI 在 Android 上運行 Python 代碼,實現高效的 Python 計算邏輯封裝到 Android 應用中。你可以使用相同的方法,將 機器學習、圖像處理、語音識別等 Python 代碼遷移到 Android,大大提升 Android 設備上的 AI 處理能力。

如果你想進一步優化,可以考慮:

  • 使用 TensorFlow Lite 替代 MediaPipe
  • 使用 OpenCL / Vulkan 進行 GPU 加速
  • 封裝多個 Python 模塊 到動態庫

希望本教程對你有所幫助!🚀

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898859.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898859.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898859.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

請為下面的html添加一個修改按鈕,以便對書名、價格進行修改

下面的HTML段落&#xff0c;在書名和價格輸入錯誤的情況下&#xff0c;無法進行修改。添加一個按鈕&#xff0c;對已經輸入的信息進行修改。 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></…

FFmpeg + ?Qt? 簡單視頻播放器代碼

一個基于 ?FFmpeg 4.x? 和 ?Qt? 的簡單視頻播放器代碼示例&#xff0c;實現視頻解碼和渲染到 Qt 窗口的功能。 1&#xff09;ffmpeg庫界面&#xff0c;視頻解碼支持軟解和硬解方式。 2&#xff09;QImage/QPixmap顯示視頻圖片。 ?1. Qt 項目配置&#xff08;.pro 文件&…

如何在百度搜索上刪除與自己名字相關的資料

個人信息的網絡足跡如同一張無形的網&#xff0c;將我們與世界的每一個角落緊密相連。然而&#xff0c;當某些與自己名字相關的資料不再希望被公眾輕易檢索到時&#xff0c;如何在百度搜索中有效“隱身”&#xff0c;成為了一個亟待解決的問題。面對復雜多變的網絡環境&#xf…

WebSocket:現代實時通信協議的深度解析與實踐

一、背景與演進歷程 1.1 傳統實時通信的困境 // 典型的HTTP輪詢偽代碼 while(true) {auto response http_client.get("/messages");if(response.has_data()) process(response);std::this_thread::sleep_for(1s); // 固定間隔輪詢 } 高延遲&#xff1a;輪詢間隔導…

[貪心算法]最長回文串 增減字符串匹配 分發餅干

1.最長回文串 我們可以存下每個字母的個數&#xff0c;然后分類討論 如果是奇數就減一加到結果中如果是偶數就直接加入即可 最后判斷長度跟原字符串的差距&#xff0c;如果小于原數組說明有奇數結果1 class Solution { public:int longestPalindrome(string s) {int ret0;//1.計…

STM32 的tf卡驅動

基于STM32的TF卡驅動的基本實現步驟和相關代碼示例,主要使用SPI接口來與TF卡進行通信。 硬件連接 將TF卡的SPI接口與STM32的SPI引腳連接,通常需要連接SCK(時鐘)、MOSI(主出從入)、MISO(主入從出)和CS(片選)引腳。 軟件實現 初始化SPI 配置SPI的工作模式、時鐘頻率…

目標檢測中的非極大值抑制(NMS)原理與實現解析

一、技術背景 在目標檢測任務中&#xff0c;模型通常會對同一目標生成多個重疊的候選框&#xff08;如錨框或預測框&#xff09;。非極大值抑制&#xff08;Non-Maximum Suppression, NMS&#xff09; 是一種關鍵的后處理技術&#xff0c;用于去除冗余的檢測結果&#xff0c;保…

探秘鴻蒙 HarmonyOS NEXT:鴻蒙存儲核心技術全解析

引言 本文章基于HarmonyOS NEXT操作系統&#xff0c;API12以上的版本。 在 ArkTS (ArkUI 框架) 中&#xff0c;用戶首選項 (Preferences) 和 持久化存儲 (PersistentStorage) 都用于數據存儲&#xff0c;但它們有不同的應用場景和特點。 1. 用戶首選項 (Preferences) 概念&a…

Leetcode—15. 三數之和(哈希表—基礎算法)

題目&#xff1a; 給你一個整數數組 nums &#xff0c;判斷是否存在三元組 [nums[i], nums[j], nums[k]] 滿足 i ! j、i ! k 且 j ! k &#xff0c;同時還滿足 nums[i] nums[j] nums[k] 0 。請你返回所有和為 0 且不重復的三元組。 注意&#xff1a;答案中不可以包含重復的…

Linux 啟動Jar腳本設置開機自啟【超級詳細】

Linux 啟動Jar腳本&&設置開機自啟【超級詳細】 概要服務器開機自啟服務重啟腳本 概要 最近在Linux服務器中部署了一個項目&#xff08;單機版&#xff09;&#xff0c;每次更新服務的時候需要用到好幾個命令&#xff0c;停止服務&#xff0c;再重啟&#xff0c;并且服…

【第21節】windows sdk編程:網絡編程基礎

目錄 引言&#xff1a;網絡編程基礎 一、socket介紹(套接字) 1.1 Berkeley Socket套接字 1.2 WinSocket套接字 1.3 WSAtartup函數 1.4 socket函數 1.5 字節序轉換 1.6 綁定套接字 1.7 監聽 1.8 連接 1.9 接收數據 1.10 發送數據 1.11 關閉套接字 二、UDP連接流程…

QT 圖表(拆線圖,欄狀圖,餅狀圖 ,動態圖表)

效果 折線圖 // 創建折線數據系列// 創建折線系列QLineSeries *series new QLineSeries;// series->append(0, 6);// series->append(2, 4);// series->append(3, 8);// 創建圖表并添加系列QChart *chart new QChart;chart->addSeries(series);chart->setTit…

vector和list的區別是什么

vector 和 list 都是C 標準模板庫&#xff08;STL&#xff09;中的容器&#xff0c;它們的區別如下&#xff1a; 內存結構 - vector &#xff1a;是連續的內存空間&#xff0c;就像數組一樣&#xff0c;元素在內存中依次排列。 - list &#xff1a;是由節點組成的雙向鏈表…

【AI】【AIGC】降低AIGC檢測率:技術、挑戰與應對策略

引言 隨著生成式人工智能&#xff08;AIGC&#xff09;技術的迅速發展&#xff0c;越來越多的內容開始由人工智能生成。AIGC技術的應用非常廣泛&#xff0c;包括文本生成、圖像生成、音頻生成等。然而&#xff0c;隨著這些技術的普及&#xff0c;如何有效識別并檢測AIGC生成的…

vue3 ts 請求封裝后端接口

一 首頁-廣告區域-小程序 首頁-廣告區域-小程序 GET/home/banner1.1 請求封裝 首頁-廣告區域 home.ts export const getHomeBannerApi (distributionSite 1) > {return http<BannerItem[]>({method: GET,url: /home/banner,data: {distributionSite,},}) }函數定…

響應式CMS架構優化SEO與用戶體驗

內容概要 在數字化內容生態中&#xff0c;響應式CMS架構已成為平衡搜索引擎可見性與終端用戶體驗的核心載體。該系統通過多終端適配技術&#xff0c;確保PC、移動端及平板等設備的內容渲染一致性&#xff0c;直接降低頁面跳出率并延長用戶停留時長。與此同時&#xff0c;智能S…

算法基礎篇(1)(藍橋杯常考點)

算法基礎篇 前言 算法內容還有搜索&#xff0c;數據結構&#xff08;進階&#xff09;&#xff0c;動態規劃和圖論 數學那個的話大家也知道比較難&#xff0c;放在最后講 這期包含的內容可以看目錄 模擬那個算法的話就是題說什么寫什么&#xff0c;就不再分入目錄中了 注意事…

MyBatis一級緩存和二級緩存

介紹 在開發基于 MyBatis 的應用時&#xff0c;緩存是提升性能的關鍵因素之一。MyBatis 提供了一級緩存和二級緩存&#xff0c;合理使用它們可以顯著減少數據庫的訪問次數&#xff0c;提高系統的響應速度和吞吐量。本文將深入探討 MyBatis 一級緩存和二級緩存的工作原理、使用…

C++核心語法快速整理

前言 歡迎來到我的博客 個人主頁:北嶺敲鍵盤的荒漠貓-CSDN博客 本文主要為學過多門語言玩家快速入門C 沒有基礎的就放棄吧。 全部都是精華&#xff0c;看完能直接上手改別人的項目。 輸出內容 std::代表了這里的cout使用的標準庫&#xff0c;避免不同庫中的相同命名導致混亂 …

如何讓自動駕駛汽車“看清”世界?坐標映射與數據融合概述

在自動駕駛領域,多傳感器融合技術是實現車輛環境感知和決策控制的關鍵。其中,坐標系映射和對應是多傳感器融合的重要環節,它涉及到不同傳感器數據在統一坐標系下的轉換和匹配,以實現對車輛周圍環境的準確感知。本文將介紹多傳感器融合中坐標系映射和對應的數學基礎和實際應…