我使用Kivy在android上运行一个客户端,该客户端将相机帧发送到服务器PC。在计算机上本地测试两个脚本时,服务器和客户端的整个代码都运行良好。当使用buildozer为android构建应用程序时,问题就来了。
在使用buildozer成功将Kivy应用程序构建到android后,该应用程序在手机上运行时崩溃。
在android上运行时,回溯显示以下错误:
ModuleNotFoundError: No module named 'zmq'
附带说明:android perms是在调试之前请求的
此错误仅在android上测试时出现,即使buildozer在buildozer.spec
文件中包含zmq
和imagezmq
时也是如此。
在我看来,buildozer在尝试创建apk时似乎无法获取imagezmq
的依赖项。
下面是我用于客户端、服务器和buildozer.spec
文件的代码。
(Kivy客户端;适用于PC,但不适用于android。(主.py
import time
# MUST >> import the android permission before building
# from android.permissions import request_permissions, Permission
# request_permissions([
# Permission.CAMERA,
# Permission.WRITE_EXTERNAL_STORAGE,
# Permission.READ_EXTERNAL_STORAGE,
# Permission.INTERNET,
# Permission.ACCESS_NETWORK_STATE
# ])
time.sleep(1)
from kivy import *
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.camera import Camera
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
import imagezmq
import cv2
import numpy as np
server_ip = '10.42.0.1' #PC server local IP
port = 5555
sender = imagezmq.ImageSender(connect_to=f"tcp://{server_ip}:{port}")
class TestCamera(App):
def sendFrame(self, *args):
height, width = self.cam.texture.height, self.cam.texture.width
#get kivy image in form of numpy ndarray.
frame = np.frombuffer(self.cam.texture.pixels, 'uint8')
frame = frame.reshape(height, width, 4)
frame = cv2.cvtColor(frame, cv2.COLOR_RGBA2BGR)
#Frame Res
#webcam is 640*360
fw,fh = 640,360
frame= cv2.resize(frame,(fw,fh),fx=0,fy=0, interpolation = cv2.INTER_AREA)
#SEND TO SERVER HERE
sender.send_image(server_ip, frame)
#Display Image on Screen
buffer = cv2.flip(frame,-1).tostring()
texture = Texture.create(size=(fw, fh), colorfmt='bgr')
texture.blit_buffer(buffer,colorfmt='bgr',bufferfmt='ubyte')
self.image.texture = texture
Clock.schedule_once(self.sendFrame, 1.0/60.0)
def build(self):
layout = BoxLayout(orientation= 'vertical')
#webcam is 640*480
self.cam = Camera(index=-1,play = True)
self.image = Image( allow_stretch=True)
layout.add_widget(self.image)
return layout
def on_start(self):
Clock.schedule_once(self.sendFrame, 5)
app = TestCamera()
app.run()
(PC服务器(Server.py
# This code is for the server
# import the libraries
import socket, cv2, pickle,struct,time
from imutils import build_montages
from datetime import datetime
import numpy as np
import imagezmq
# initialize the ImageHub object
imageHub = imagezmq.ImageHub()
ip = '10.42.0.1' #Host IP
port = 5555
lastActive = {}
lastActiveCheck = datetime.now()
ESTIMATED_NUM_PIS = 1
ACTIVE_CHECK_PERIOD = 10
ACTIVE_CHECK_SECONDS = ESTIMATED_NUM_PIS * ACTIVE_CHECK_PERIOD
print("LISTENING AT:",ip)
while True:
# receive host name and frame from phone and acknowledge
# the receipt
(host_ip, frame) = imageHub.recv_image()
imageHub.send_reply(b'OK')
# if a device is not in the last active dictionary then it means
# that its a newly connected device
if host_ip not in lastActive.keys():
print("[INFO] receiving data from {}...".format(host_ip))
# record the last active time for the device from which we just
# received a frame
lastActive[host_ip] = datetime.now()
#Show frames on a window
cv2.imshow('Received Frame',frame)
if cv2.waitKey(1) == '13':
break
用于构建到android的buildozer.spec
文件配置如下。
[app]
# (list) Permissions
android.permissions = INTERNET, ACCESS_NETWORK_STATE,CAMERA, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE
# (int) Target Android API, should be as high as possible.
#android.api = 26
# (int) Minimum API your APK will support.
android.minapi = 24
# (int) Android SDK version to use
#android.sdk = 20
# (str) Android NDK version to use
android.ndk = 19c
# (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.
android.ndk_api = 24
[buildozer]
# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
log_level = 2
# (int) Display warning if buildozer is run as root (0 = False, 1 = True)
warn_on_root = 1
我将通过提供对我有效的解决方案来尴尬地回答我发布的问题。
在buildozer.spec
文件内的需求中,必须在zmq
和imagezmq
之前添加pyzmq
。
# (list) Application requirements
# comma separated e.g. requirements = sqlite3,kivy
requirements = python3,kivy,numpy,pyzmq,zmq,opencv==4.5.4,imagezmq==1.1.1
该应用程序现在在安卓系统上运行。