Kivy应用在使用cv.VideoCapture()时无法检测到触摸事件。

huangapple go评论135阅读模式
英文:

Kivy app not detecting touch events when using cv.VideoCapture()

问题

我正在开发一个Kivy应用程序。在某一点上,用户将不得不触摸屏幕以指示网球场的角落在哪里。我想获取此触摸的坐标,并创建一个感兴趣区域(ROI)。我很容易使用OpenCV实现了这一点:

  1. import numpy as np
  2. import cv2 as cv
  3. from matplotlib import pyplot as plt
  4. cap = cv.VideoCapture('partido/06_centro.mp4')
  5. cv.namedWindow("Video")
  6. def get_roi(frame, x, y):
  7. roi_corners = np.array([[x-50, y-50], [x+50, y-50], [x+50, y+50], [x-50, y+50]])
  8. mask = np.zeros(frame.shape[:2], np.uint8)
  9. cv.drawContours(mask, [roi_corners], 0, (255, 255, 255), -1)
  10. return cv.bitwise_and(frame, frame, mask=mask)
  11. def mouse_callback(event, x, y, flags, param):
  12. if event == cv.EVENT_LBUTTONDOWN:
  13. roi_frame = get_roi(frame, x, y)
  14. cv.imshow("ROI Frame", roi_frame)
  15. cv.setMouseCallback("Video", mouse_callback)
  16. while True:
  17. ret, frame = cap.read()
  18. cv.imshow("Video", frame)
  19. key = cv.waitKey(1) & 0xFF
  20. if key == ord('q'):
  21. break
  22. cap.release()
  23. cv.destroyAllWindows()

这段代码有效,但是当我尝试在Kivy中执行相同操作时,我可以显示视频,但它不识别触摸事件(print语句不执行):

  1. import cv2
  2. from kivy.app import App
  3. from kivy.uix.image import Image
  4. from kivy.graphics.texture import Texture
  5. from kivy.clock import Clock
  6. import numpy as np
  7. # 程序的其余部分没有翻译
  8. if __name__ == '__main__':
  9. app = VideoPlayerApp().run()

你仍然在使用OpenCV的VideoCapture()方法,并使用schedule_interval来更新Image组件。由于我无法提供更多Kivy代码,你可能需要检查Kivy部分的代码以确保触摸事件正确处理。你可以阅读Kivy的文档或寻求Kivy社区的支持以解决触摸事件未触发的问题。

英文:

I am working on a Kivy app. At some point, the user will have to touch the screen to indicate where the corners of a tennis court are. I want to take the coordinates of this touch, and create a ROI. I did this using OpenCV easily:

  1. import numpy as np
  2. import cv2 as cv
  3. from matplotlib import pyplot as plt
  4. cap = cv.VideoCapture('partido/06_centro.mp4')
  5. cv.namedWindow("Video")
  6. def get_roi(frame, x, y):
  7. roi_corners = np.array([[x-50, y-50], [x+50, y-50], [x+50, y+50], [x-50, y+50]])
  8. mask = np.zeros(frame.shape[:2], np.uint8)
  9. cv.drawContours(mask, [roi_corners], 0, (255, 255, 255), -1)
  10. return cv.bitwise_and(frame, frame, mask=mask)
  11. def mouse_callback(event, x, y, flags, param):
  12. if event == cv.EVENT_LBUTTONDOWN:
  13. roi_frame = get_roi(frame, x, y)
  14. cv.imshow("ROI Frame", roi_frame)
  15. cv.setMouseCallback("Video", mouse_callback)
  16. while True:
  17. ret, frame = cap.read()
  18. cv.imshow("Video", frame)
  19. key = cv.waitKey(1) & 0xFF
  20. if key == ord('q'):
  21. break
  22. cap.release()
  23. cv.destroyAllWindows()

This code works, but now when I try to do the same with Kivy I can show the video but it doesn't recognize the touch event (the print statement is not executed):

  1. import cv2
  2. from kivy.app import App
  3. from kivy.uix.image import Image
  4. from kivy.graphics.texture import Texture
  5. from kivy.clock import Clock
  6. import numpy as np
  7. def get_roi(frame, x, y):
  8. roi_corners = np.array([[x-50, y-50], [x+50, y-50], [x+50, y+50], [x-50, y+50]])
  9. mask = np.zeros(frame.shape[:2], np.uint8)
  10. cv2.drawContours(mask, [roi_corners], 0, (255, 255, 255), -1)
  11. return cv2.bitwise_and(frame, frame, mask=mask)
  12. class VideoPlayerApp(App):
  13. def build(self):
  14. self.image = Image(allow_stretch=True, keep_ratio=False)
  15. Clock.schedule_interval(self.update, 1.0/30.0)
  16. self.cap = cv2.VideoCapture("./partido/06_centro.mp4")
  17. return self.image
  18. def on_touch_down(self, touch):
  19. print("Touch down")
  20. if self.image.collide_point(*touch.pos):
  21. x, y = touch.pos
  22. x = int(x / self.image.width * self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  23. y = int(y / self.image.height * self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  24. ret, frame = self.cap.read()
  25. if ret:
  26. roi_frame = get_roi(frame, x, y)
  27. cv2.imshow("ROI Frame", roi_frame)
  28. def update(self, dt):
  29. ret, frame = self.cap.read()
  30. if ret:
  31. buf = cv2.flip(frame, 0).tobytes()
  32. image_texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
  33. image_texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')
  34. self.image.texture = image_texture
  35. def on_stop(self):
  36. self.cap.release()
  37. cv2.destroyAllWindows()
  38. if __name__ == '__main__':
  39. app = VideoPlayerApp().run()

I'm still using the method VideoCapture() from OpenCV, and I'm updating the Image component using schedule_interval. I started using Kivy recently, so I can't find the error. Can you help me?

答案1

得分: 2

App 类不处理 on_touch_down 事件,因此您的 on_touch_down() 方法将永远不会被调用。然而,Image 类处理 on_touch_down 事件(所有的 Widgets 都处理)。因此,您可以在 build() 方法中使用您的 Image 绑定到该事件,像这样:

  1. self.image.bind(on_touch_down=self.on_touch_down)

并修改 on_touch_down() 方法以接受正确的参数:

  1. def on_touch_down(self, image, touch):
  2. print("Touch down")
  3. if image.collide_point(*touch.pos):
  4. x, y = touch.pos
  5. x = int(x / image.width * self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  6. y = int(y / image.height * self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  7. ret, frame = self.cap.read()
  8. if ret:
  9. roi_frame = get_roi(frame, x, y)
  10. cv2.imshow("ROI Frame", roi_frame)

请注意,在这个方法中,您可以用 image 替换 self.image,因为它是传递给方法的参数。

英文:

The App class does not handle on_touch_down events, so your on_touch_down() method will never be called. The Image class, however, does handle on_touch_down events (all Widgets do). So you can bind to that event using your Image in your build() method, like this:

  1. self.image.bind(on_touch_down=self.on_touch_down)

And modify that on_touch_down() method to accept the correct arguments:

  1. def on_touch_down(self, image, touch):
  2. print("Touch down")
  3. if image.collide_point(*touch.pos):
  4. x, y = touch.pos
  5. x = int(x / image.width * self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  6. y = int(y / image.height * self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  7. ret, frame = self.cap.read()
  8. if ret:
  9. roi_frame = get_roi(frame, x, y)
  10. cv2.imshow("ROI Frame", roi_frame)

Note that in this method you can replace self.image with just image since it is an argument passed to the method.

huangapple
  • 本文由 发表于 2023年3月12日 06:46:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75710048.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定