Kivy+OpenCV打包APK遇cv2模块缺失错误求助
Kivy+OpenCV APK开发:修改代码后出现
cv2模块找不到的问题 问题描述
使用Kivy和OpenCV开发具备拍照及Canny边缘检测功能的APK,初始代码可正常运行。添加图片点击画红点功能后,出现ModuleNotFoundError: No module named 'cv2'错误;即使回退到初始代码,错误仍持续存在,仅执行buildozer android clean后重新构建才能让初始代码恢复正常。
初始可正常运行的代码
from kivy.app import App from kivy.lang import Builder from kivy.uix.boxlayout import BoxLayout from kivy.uix.popup import Popup from kivy.uix.image import Image from kivy.properties import StringProperty from kivy.utils import platform from android.permissions import request_permissions, Permission from android.storage import app_storage_path import time import cv2 request_permissions([ Permission.CAMERA, Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE ]) Builder.load_string(''' <CameraClick>: orientation: 'vertical' Camera: index: 0 id: camera resolution: (1920,1080) play: True allow_stretch: True canvas.before: PushMatrix Rotate: angle: -90 origin: self.center canvas.after: PopMatrix Button: text: 'Capture' size_hint_y: None height: '48dp' on_press: root.capture() <DisplayImagePopup>: image_source: '' BoxLayout: orientation: 'vertical' Image: source: root.image_source Button: text: 'Process Image' size_hint_y: None height: 50 on_press: root.process_image() ''') class CameraClick(BoxLayout): def capture(self): camera = self.ids['camera'] storage_path = app_storage_path() # Get the safe storage path for the app timestr = time.strftime("%Y%m%d_%H%M%S") filename = "{}/IMG_{}.png".format(storage_path, timestr) camera.export_to_png(filename) self.show_image(filename) def show_image(self, filename): popup = DisplayImagePopup(title='Captured Image', image_source=filename) popup.open() class DisplayImagePopup(Popup): image_source = StringProperty('') def process_image(self): image = cv2.imread(self.image_source) imgGray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) imgBlur = cv2.bilateralFilter(imgGray, 10, 10, 10) imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) adaptive_thresh = cv2.adaptiveThreshold(imgBlur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 3) imgCanny = cv2.Canny(adaptive_thresh, 100, 150) processed_filename = self.image_source.replace('.png', '_processed.png') cv2.imwrite(processed_filename, imgCanny) self.image_source = processed_filename # Update the image displayed in the popup class TestCamera(App): def build(self): return CameraClick() if __name__ == '__main__': TestCamera().run()
添加点击画红点功能后的代码
from kivy.app import App from kivy.lang import Builder from kivy.uix.boxlayout import BoxLayout from kivy.uix.popup import Popup from kivy.uix.image import Image from kivy.graphics import Color, Ellipse from kivy.properties import StringProperty, ListProperty import cv2 from android.permissions import request_permissions, Permission from android.storage import app_storage_path import time request_permissions([ Permission.CAMERA, Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE ]) Builder.load_string(''' <CameraClick>: orientation: 'vertical' Camera: index: 0 id: camera resolution: (1920,1080) play: True allow_stretch: True canvas.before: PushMatrix Rotate: angle: -90 origin: self.center canvas.after: PopMatrix Button: text: 'Capture' size_hint_y: None height: '48dp' on_press: root.capture() <DisplayImagePopup>: image_source: '' BoxLayout: orientation: 'vertical' InteractiveImage: source: root.image_source on_touch_down: root.on_image_touch(*args) Button: text: 'Process Image' size_hint_y: None height: 50 on_press: root.process_image() ''') class CameraClick(BoxLayout): def capture(self): camera = self.ids['camera'] storage_path = app_storage_path() timestr = time.strftime("%Y%m%d_%H%M%S") filename = "{}/IMG_{}.png".format(storage_path, timestr) camera.export_to_png(filename) self.show_image(filename) def show_image(self, filename): popup = DisplayImagePopup(title='Captured Image', image_source=filename) popup.open() class InteractiveImage(Image): def on_touch_down(self, touch): if self.collide_point(*touch.pos): with self.canvas: Color(1, 0, 0) d = 10 # diameter of the ellipse Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d)) return True return super(InteractiveImage, self).on_touch_down(touch) class DisplayImagePopup(Popup): image_source = StringProperty('') def process_image(self): image = cv2.imread(self.image_source) imgGray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) imgBlur = cv2.bilateralFilter(imgGray, 10, 10, 10) imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) adaptive_thresh = cv2.adaptiveThreshold(imgBlur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 3) imgCanny = cv2.Canny(adaptive_thresh, 100, 150) processed_filename = self.image_source.replace('.png', '_processed.png') cv2.imwrite(processed_filename, imgCanny) self.image_source = processed_filename # Update the image displayed in the popup class TestCamera(App): def build(self): return CameraClick() if __name__ == '__main__': TestCamera().run()
错误日志
HWCDY:/ $ run-as org.test.myapt HWCDY:/data/data/org.test.myapt $ cd files/app/.kivy/logs/ HWCDY:/data/data/org.test.myapt/files/app/.kivy/logs $ ls kivy_24-04-22_0.txt HWCDY:/data/data/org.test.myapt/files/app/.kivy/logs $ cat kivy_24-04-22_0.txt [INFO ] Logger: Record log in /data/user/0/org.test.myapt/files/app/.kivy/logs/kivy_24-04-22_0.txt [DEBUG ] Config: Upgrading from 0 to 1 [WARNING] Config: Upgrading configuration in progress. [WARNING] Config: Older configuration version detected (0 instead of 27) [INFO ] Kivy: v2.2.0 [INFO ] Kivy: Installed at "/data/user/0/org.test.myapt/files/app/_python_bundle/site-packages/kivy/__init__.pyc" [INFO ] Python: v3.10.10 (main, Apr 21 2024, 22:32:18) [Clang 14.0.6 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0 [INFO ] Python: Interpreter at "" [INFO ] Logger: Purge log fired. Processing... [INFO ] Logger: Purge finished! [INFO ] Factory: 190 symbols loaded [INFO ] Image: Providers: img_tex, img_dds, img_sdl2 (img_pil, img_ffpyplayer ignored) [INFO ] Text: Provider: sdl2 [WARNING] stderr: Traceback (most recent call last): [WARNING] stderr: File "/home/wuqx1999/packing/.buildozer/android/app/main.py", line 8, in <module> [WARNING] stderr: ModuleNotFoundError: No module named 'cv2'
解决方案
1. 确保Buildozer配置文件依赖正确
打开buildozer.spec,检查requirements字段,确保包含opencv(kivy-for-android的官方recipe名称是opencv,而非opencv-python):
requirements = python3,kivy,opencv
如果需要指定版本,可写为opencv==4.5.5(选择与Kivy、Python版本兼容的OpenCV版本)。
2. 彻底清理Buildozer缓存
仅执行buildozer android clean可能不够,需彻底清理缓存后重新构建:
# 清理Android构建缓存 buildozer android clean # 删除整个.buildozer目录(彻底重置构建环境) rm -rf .buildozer # 重新初始化并构建 buildozer android debug deploy run
3. 修复代码中的额外错误
修改后的代码存在一个隐藏问题:kv文件中InteractiveImage绑定了root.on_image_touch(*args),但DisplayImagePopup类并未实现该方法,会导致点击图片时触发新的错误。需删除该绑定:
将kv中的这一行:
on_touch_down: root.on_image_touch(*args)
删除,因为InteractiveImage类已经自己实现了on_touch_down方法来处理画红点逻辑。
4. 构建环境检查
- 确保构建时网络稳定,Buildozer需要下载OpenCV的预编译库或源码
- 若出现源码编译错误,可在
buildozer.spec中指定兼容的NDK版本:
android.ndk = 25b
内容的提问来源于stack exchange,提问作者xwss
相关产品推荐
相关产品推荐

