You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy按钮调用外部模块报错:NameError: name 'Aruco' is not defined

Kivy按钮调用外部模块方法报错:NameError: name 'Aruco' is not defined

我在单个文件中编写了Kivy代码,尝试将其中一个按钮与外部Python模块(Aruco.py)关联,希望点击按钮时运行该模块的detect()方法。已在main.py中导入Aruco模块,但点击按钮时触发错误:NameError: name 'Aruco' is not defined。

相关代码

main.py

import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang.builder import Builder
import sqlite3
import Aruco

class MainWindow(Screen):
    pass

class InfoWindow(Screen):
    pass

class LocaliseWindow(Screen):
    pass

class WindowManager(ScreenManager):
    pass

kv = Builder.load_string("""
WindowManager:
    MainWindow:
    LocaliseWindow:
    InfoWindow


<MainWindow>:
    name: "main"
    GridLayout:
        padding: 50
        spacing: 20
        cols:1
        size: root.width, root.height
        Camera:
            id: camera
            play: True
        GridLayout:
            cols:2
            spacing: 20
            Button:
                text: "Localise"
                on_release: 
                    app.root.current = "localise"
                    root.manager.transition.direction = "left"
                background_normal: ""
                background_color: "#05b4ff"
            Button:
                text: "Info"
                on_press:
                    app.root.current = "info"
                    root.manager.transition.direction = "left"
                background_normal: ""
                background_color: "#05b4ff"

<LocaliseWIndow>:
    name: "localise"
    BoxLayout:
        padding: 50
        spacing: 10
        orientation: "vertical"
        Label:
            id: choose_destination
            font_size: 24
            text: "Choose Destination"
        Button:
            id:Maths
            text: "Maths"
            on_press: Aruco.detect()
            background_normal: ""
            background_color: "#05b4ff"
        Button:
            id: English
            text: "English"
            on_press: app.submit()
            background_normal: ""
            background_color: "#05b4ff"
        Button:
            id: Science
            text: "Science"
            on_press: app.submit()
            background_normal: ""
            background_color: "#05b4ff"
        Button:
            id: Humanities
            text: "Humanities"
            on_press: app.submit()
            background_normal: ""
            background_color: "#05b4ff"
        Button:
            id: Office
            text: "Office"
            on_press: app.submit()
            background_normal: ""
            background_color: "#05b4ff"
        Button:
            id: Restroom
            text: "Restroom"
            on_press: app.submit()
            background_normal: ""
            background_color: "#05b4ff"
        Button:
            text: "Back"
            on_release: 
                app.root.current = "main"
                root.manager.transition.direction = "right" 
            
<InfoWindow>:
    name:"info"
    BoxLayout:
        padding: 50
        spacing: 10
        orientation: "vertical"
        Label:
            text: "1. Press Localise"
        Label:
            text: "2. Choose Destination"
        Label:
            text: "3. Scan nearest Aruco Marker when prompted"
        Label:
            text: "4. Follow the path to destination"
        Button:
            text: "Back"
            on_release:
                app.root.current = "main"
                root.manager.transition.direction = "right"

            
""")

class MyApp(App):
    def build(self):
        conn = sqlite3.connect("database.db")
        c = conn.cursor()
        c.execute("""CREATE TABLE if not exists locations(
            place text,
            xcoor int,
            ycoor int)
        """)
        conn.commit()
        conn.close()
        return kv

    def submit(self):
        conn = sqlite3.connect("database.db")
        c = conn.cursor()

        c.execute("SELECT * FROM locations")

        print(c.fetchall())

        conn.commit()
        conn.close()
        

if __name__ == "__main__":
    MyApp().run()

Aruco.py

import numpy as np
import time
import cv2

def detect():
    ARUCO_DICT = {
        "DICT_4X4_50": cv2.aruco.DICT_4X4_50,
        "DICT_4X4_100": cv2.aruco.DICT_4X4_100,
        "DICT_4X4_250": cv2.aruco.DICT_4X4_250,
        "DICT_4X4_1000": cv2.aruco.DICT_4X4_1000,
        "DICT_5X5_50": cv2.aruco.DICT_5X5_50,
        "DICT_5X5_100": cv2.aruco.DICT_5X5_100,
        "DICT_5X5_250": cv2.aruco.DICT_5X5_250,
        "DICT_5X5_1000": cv2.aruco.DICT_5X5_1000,
        "DICT_6X6_50": cv2.aruco.DICT_6X6_50,
        "DICT_6X6_100": cv2.aruco.DICT_6X6_100,
        "DICT_6X6_250": cv2.aruco.DICT_6X6_250,
        "DICT_6X6_1000": cv2.aruco.DICT_6X6_1000,
        "DICT_7X7_50": cv2.aruco.DICT_7X7_50,
        "DICT_7X7_100": cv2.aruco.DICT_7X7_100,
        "DICT_7X7_250": cv2.aruco.DICT_7X7_250,
        "DICT_7X7_1000": cv2.aruco.DICT_7X7_1000,
        "DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL,
        "DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5,
        "DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9,
        "DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10,
        "DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11
    }


    def aruco_display(corners, ids, rejected, image):
        if len(corners) > 0:

            ids = ids.flatten()

            for (markerCorner, markerID) in zip(corners, ids):
            
                corners = markerCorner.reshape((4, 2))
                (topLeft, topRight, bottomRight, bottomLeft) = corners
            
                topRight = (int(topRight[0]), int(topRight[1]))
                bottomRight = (int(bottomRight[0]), int(bottomRight[1]))
                bottomLeft = (int(bottomLeft[0]), int(bottomLeft[1]))
                topLeft = (int(topLeft[0]), int(topLeft[1]))

                cv2.line(image, topLeft, topRight, (0, 255, 0), 2)
                cv2.line(image, topRight, bottomRight, (0, 255, 0), 2)
                cv2.line(image, bottomRight, bottomLeft, (0, 255, 0), 2)
                cv2.line(image, bottomLeft, topLeft, (0, 255, 0), 2)
            
                cX = int((topLeft[0] + bottomRight[0]) / 2.0)
                cY = int((topLeft[1] + bottomRight[1]) / 2.0)
                cv2.circle(image, (cX, cY), 4, (0, 0, 255), -1)
            
                cv2.putText(image, str(markerID),(topLeft[0], topLeft[1] - 10), cv2.FONT_HERSHEY_SIMPLEX,
                    0.5, (0, 255, 0), 2)
                print("ArUco marker ID: {}".format(markerID))
                return markerID
        return image



    aruco_type = "DICT_5X5_100"

    arucoDict = cv2.aruco.Dictionary_get(ARUCO_DICT[aruco_type])

    arucoParams = cv2.aruco.DetectorParameters_create()


    capture = cv2.VideoCapture(0)

    capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)


    while capture.isOpened():
    
        ret, img = capture.read()

        h, w, _ = img.shape

        width = 1000
        height = int(width*(h/w))
        img = cv2.resize(img, (width, height), interpolation=cv2.INTER_CUBIC)
 
        corners, ids, rejected = cv2.aruco.detectMarkers(img, arucoDict, parameters=arucoParams)

        detected_markers = aruco_display(corners, ids, rejected, img)

        cv2.imshow("Image", detected_markers)

        key = cv2.waitKey(1) & 0xFF
        if key == ord(" "):
            break

    cv2.destroyAllWindows()
    capture.release()
    return markerID

解决方案

1. 修复KV语言的作用域问题

KV语言无法直接访问全局导入的模块,不能直接在按钮on_press事件中写Aruco.detect(),需要通过App实例或屏幕类间接调用:

方法一:通过App类封装调用

修改MyApp类,添加调用Aruco模块的方法:

class MyApp(App):
    # ... 原有代码 ...
    
    def run_aruco_detect(self):
        Aruco.detect()

修改KV中Maths按钮的事件:

Button:
    id:Maths
    text: "Maths"
    on_press: app.run_aruco_detect()
    background_normal: ""
    background_color: "#05b4ff"

方法二:通过LocaliseWindow类封装调用

修改LocaliseWindow类,添加调用方法:

class LocaliseWindow(Screen):
    def detect_aruco(self):
        Aruco.detect()

修改KV中按钮事件:

Button:
    id:Maths
    text: "Maths"
    on_press: root.detect_aruco()
    background_normal: ""
    background_color: "#05b4ff"

2. 修复KV中的拼写错误

KV中定义的屏幕为<LocaliseWIndow>,但Python类名是LocaliseWindow(字母i和l顺序错误),会导致屏幕无法加载,修正为:

<LocaliseWindow>:
    name: "localise"
    # ... 原有内容 ...

3. 修复Aruco.py的变量作用域问题

detect()函数末尾return markerID会报错,因为markerID是aruco_display内部的局部变量,仅在检测到标记时定义。修改如下:

调整aruco_display函数返回值

def aruco_display(corners, ids, rejected, image):
    markerID = None
    if len(corners) > 0:
        ids = ids.flatten()
        for (markerCorner, markerID) in zip(corners, ids):
            # ... 原有绘制标记的代码 ...
            cv2.putText(image, str(markerID),(topLeft[0], topLeft[1] - 10), cv2.FONT_HERSHEY_SIMPLEX,
                0.5, (0, 255, 0), 2)
            print("ArUco marker ID: {}".format(markerID))
    return image, markerID

修改detect函数接收返回值

def detect():
    # ... 原有代码 ...
    markerID = None
    while capture.isOpened():
        # ... 原有代码 ...
        detected_markers, markerID = aruco_display(corners, ids, rejected, img)
        cv2.imshow("Image", detected_markers)
        # ... 原有代码 ...
    
    cv2.destroyAllWindows()
    capture.release()
    return markerID

这样可以避免cv2.imshow接收非图像类型参数导致的报错。

内容的提问来源于stack exchange,提问作者Nigel Mathews

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:52:40