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

Threading相关求助:Kivy GUI更新IP摄像头实时画面出现卡顿

你的问题核心是阻塞了Kivy的主事件循环。Kivy所有GUI渲染、交互事件的处理都依赖主线程的事件循环调度,你在主线程写了带time.sleep的死循环,会直接卡住整个事件循环,只有调整窗口大小这类系统级事件能临时触发事件循环执行重绘,所以才会出现你遇到的现象。

解决步骤

  1. 删掉主线程的死循环逻辑,改用Kivy内置的Clock.schedule_interval定时调度帧更新任务,这个方法会在Kivy事件循环的空闲阶段执行你传入的函数,不会阻塞正常渲染。
  2. 删掉没用的cv2.waitKey调用,这个是OpenCV自有窗口的事件监听函数,和Kivy完全不兼容。
  3. 程序退出时记得主动终止采集线程,避免后台进程残留。

修改后的参考代码

首先导入依赖的调度模块:

from kivy.clock import Clock
# 其他原有导入保持不变

修改你的业务逻辑代码:

def main(self, *args):
    global adjustment_stop_threading
    global adjustment_lock
    global adjustment_frame
    
    # 重置线程停止标志
    adjustment_stop_threading = False
    # 启动采集线程,加daemon标志避免程序退出后线程残留
    threading.Thread(target=self.getimage_livestream, daemon=True).start()
    # 注册定时帧更新任务,设置为30帧/秒,可根据需求调整间隔
    self.frame_update_event = Clock.schedule_interval(self.update_frame, 1/30)

# 新增帧更新函数,由Kivy主线程定时调度
def update_frame(self, dt):
    global adjustment_lock
    global adjustment_frame
    
    my_frame = None
    with adjustment_lock:
        if adjustment_frame is not None:
            my_frame = np.copy(adjustment_frame)
            # 可选:用完清空避免重复处理同一帧,根据业务需求决定是否开启
            # adjustment_frame = None
    
    if my_frame is None:
        return
    
    try:
        buf1 = cv2.flip(my_frame, 0)
        buf = buf1.tobytes()
        image_texture = Texture.create(size=(my_frame.shape[1], my_frame.shape[0]), colorfmt='rgb')
        image_texture.blit_buffer(buf, colorfmt='rgb', bufferfmt='ubyte')
        self.root.ids.liveimageadjustment.texture = image_texture
    except Exception as e:
        print(e)

# 采集线程逻辑基本不变
def getimage_livestream(self, *args):
    global adjustment_stop_threading
    global adjustment_lock
    global adjustment_frame

    stream = urlopen('http://192.168.4.1:81/stream')
    bytes = b''
    while not adjustment_stop_threading:
        try:
            bytes += stream.read(1024) 
            a = bytes.find(b'\xff\xd8') 
            b = bytes.find(b'\xff\xd9')
            if a != -1 and b != -1: 
                jpg = bytes[a:b+2] 
                bytes = bytes[b+2:]
                getliveimage = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
                livestreamrotated1 = cv2.rotate(getliveimage, cv2.ROTATE_90_CLOCKWISE)
                
                with adjustment_lock:
                    adjustment_frame = livestreamrotated1

            time.sleep(0.03)
        except Exception as e:
            print(e)
            print("failed at this point")

# 新增退出清理逻辑,如果你的主类继承自Kivy的App类,关闭窗口时会自动触发这个方法
def on_stop(self):
    global adjustment_stop_threading
    # 停止采集线程
    adjustment_stop_threading = True
    # 取消定时更新任务
    if hasattr(self, 'frame_update_event'):
        self.frame_update_event.cancel()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:45:04