Streaming rasp CCTV Video into a Label in TKInter

Viewed 124

I've got a Raspberry Pi Display screen project working, displaying 2 CCTV feeds via rtsp into a couple of Tkinter labels, problem is its so slow and up to 10s behind the live feed. After doing research I now know I have to separate out the actual capture of frames away from the main thread to speed things up but even after reading several tutorials I can't get it to work.

This works but is slow, clearly its blocking which is where the delay is introduced

def garden1():
  cap2 = cv2.VideoCapture("LOCAL URL")
  cap2.set(cv2.CAP_PROP_BUFFERSIZE, 3)
  while True:
    try:
      if cap2.isOpened():
         status, frame = cap2.read()
         if status:
           frame = cv2.resize(frame, (350,200)) 
           cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
           img = Image.fromarray(cv2image)
           imgtk = ImageTk.PhotoImage(image=img)
           gardenlbl.imgtk = imgtk
           gardenlbl.configure(image=imgtk)
         else:
           t_stamp = error_timestamp()
           logging.info(t_stamp +"  Garden Videostream restarted")
           cap2 = cv2.VideoCapture("LOCAL URL")
           continue
    except cv2.error as e:
       print ("Something went wrong with garden video")
       pass

I know I have to go down this route, so setting up a class I can use for each feed and then a separate thread to read the frames and place them into labels - Code snippet below:

def garden():
  while True:
    try:
      frame = video_stream2.read()
      cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
      img = Image.fromarray(cv2image)
      imgtk = ImageTk.PhotoImage(image=img)
      gardenlbl.imgtk = imgtk
      gardenlbl.configure(image=imgtk)
      time.sleep(1)
    except cv2.error as e:
      print (str(e)  + "Something went wrong with garden video")
      pass

class streamvideo(object):
  def __init__(self, src=0):
        self.capture = cv2.VideoCapture(src)
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()
        print ("thread started")

  def update(self):
        print ("Update started")
        while True:
          if self.capture.isOpened():
            (self.status, self.frame) = self.capture.read()

  def read(self):
        if self.status:
          self.frame = self.resize_frame(self.frame, width=350)
          return self.frame

  def resize_frame(self, image, width=None, height=None, inter=cv2.INTER_AREA):
        dim = None
        (h, w) = image.shape[:2]
        if width is None and height is None:
            return image
        if width is None:
            r = height / float(h)
            dim = (int(w * r), height)
        else:
            r = width / float(w)
            dim = (width, int(h * r))
        return cv2.resize(image, dim, interpolation=inter)

stream_garden = local url
video_stream2 = streamvideo(stream_garden)
t_e = threading.Thread(target=garden, name="Garden", daemon=True)
t_e.start()

The error I'm currently getting is:

Update started
thread started
Exception in thread Garden:
Traceback (most recent call last):
  File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "monitor2.py", line 422, in garden
    frame = video_stream2.read()
  File "monitor2.py", line 448, in read
    if self.status:
AttributeError: 'streamvideo' object has no attribute 'status'

I've always avoided classes as I always find myself tripping up - Can anyone suggest any improvements?

0 Answers
Related