Threading相关求助:Kivy GUI更新IP摄像头实时画面出现卡顿
你的问题核心是阻塞了Kivy的主事件循环。Kivy所有GUI渲染、交互事件的处理都依赖主线程的事件循环调度,你在主线程写了带time.sleep的死循环,会直接卡住整个事件循环,只有调整窗口大小这类系统级事件能临时触发事件循环执行重绘,所以才会出现你遇到的现象。
解决步骤
- 删掉主线程的死循环逻辑,改用Kivy内置的
Clock.schedule_interval定时调度帧更新任务,这个方法会在Kivy事件循环的空闲阶段执行你传入的函数,不会阻塞正常渲染。 - 删掉没用的
cv2.waitKey调用,这个是OpenCV自有窗口的事件监听函数,和Kivy完全不兼容。 - 程序退出时记得主动终止采集线程,避免后台进程残留。
修改后的参考代码
首先导入依赖的调度模块:
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
相关产品推荐
相关产品推荐

