Python using methods from other classes with threads - python

Before posting I checked a lot of topics already on the net and I tried to implement them, but I quite can't wrap my head around it...
Basically, I want to implement threading in order to use efficiently the Raspberry Pi camera and other USB camera. Then using other threads for the image processing.
So one thread to get the video stream, another to detect AruCo marker and a last one with face tracking (both using the video stream from the first thread). I want to test first with ArUco markers before going further..
So far I came up with the following:
#-------------------------------------------------
# Imports
import math
import sys
import os
import time
import cv2
import cv2.aruco as aruco
import numpy as np
#from picamera.array import PiRGBArray
#from picamera import PiCamera
#from imutils.video.pivideostream import PiVideoStream
import thread
from threading import Thread
#----------------------------------------------------------------------------------------------
class CamVideoStream:
def __init__(self):
self.capture = cv2.VideoCapture(0)
self.frame = None
self.stopped = False
def start(self):
# start the thread to read frames from the video stream
Thread(target=self.update, args=()).start()
return self
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
time.sleep(.01)
def show_frame(self):
# Display frames in main program
cv2.imshow("CamVideoStream", self.frame)
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
cv2.destroyAllWindows()
exit(1)
def read(self):
# return the frame most recently read
return self.frame
def stop(self):
# indicate that the thread should be stopped
self.stopped = True
#----------------------------------------------------------------------------------------------
class ArUcoMarker:
def __init__(self):
self.thread = Thread(target=self.tracking, args=())
self.thread.daemon = False
self.thread.start()
def show_vid(self, CamVideoStream):
cv2.imshow("ArUcoMarker", CamVideoStream.frame)
def tracking(self, CamVideoStream):
time.sleep(.05)
self.stream = CamVideoStream.frame
gray = cv2.cvtColor(self.stream, cv2.COLOR_BGR2GRAY)
aruco_dict = aruco.Dictionary_get(aruco.DICT_4X4_250)
arucoParameters = aruco.DetectorParameters_create()
corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, aruco_dict, parameters=arucoParameters)
if np.all(ids != None):
self.stream = aruco.drawDetectedMarkers(self.stream, corners)
cv2.imshow('ArUcoMarker', self.stream)
else:
cv2.imshow('ArUcoMarker', self.stream)
print ("No Marker")
#----------------------------------------------------------------------------------------------
if __name__ == '__main__':
#PiStream = PiVideoStream().start()
CamStream = CamVideoStream().start()
MarkerTracking = ArUcoMarker()
time.sleep(2.0)
while True:
try:
#CamStream.show_frame()
MarkerTracking.show_vid(CamStream.frame)
#MarkerTracking.tracking(vid)
except AttributeError:
pass
cv2.destroyAllWindows()
CamStream.stop()
I'm not entirely sure if my way of using the method from the CamVideoStream class is correct.
I have the following error message:
Exception in thread Thread-2:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 810, in __bootstrap_inner
self.run()
File "C:\Python27\lib\threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
TypeError: tracking() takes exactly 2 arguments (1 given)
I tried to do the same thing as in this post but without success.. I'm lost with all this, if someone could explain me how to use properly the methods from other class with example, it would be really nice !

Related

Can't access parent's attributes using super initialisation in Python

I have parent class Gauge, which records video from web camera(OpenCV) in separate thread in while-loop . All the frames are saved as class attribute and I can easily see them being in the Gauge. Whenever I try to access Gauge's frames from child class using inheritance I become the error, saying AttributeError: 'Video' object has no attribute 'frame' . Here is the snippets:
class Gauge(object):
def __init__(self):
self.capture = cv2.VideoCapture(2)
if self.capture.isOpened():
print("opened camera")
self.video_thread = Thread(target=self.update, args=())
self.video_thread.name='video thread'
self.video_thread.daemon = True
self.video_thread.start()
def update(self):
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
class Video(Gauge):
def __init__(self, master):
super(Video, self).__init__()
#skipping unimportant lines...
while True:
image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB) #AttributeError!!
image = cv2.resize(image,(round(self.master.winfo_width()/2-20),round(self.master.winfo_height()-10)),interpolation=cv2.INTER_AREA)
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
self.labelVideo.configure(image=image)
self.labelVideo.image=image
The problem is most likely due to Video.__init__ trying to access self.frame before the thread running Gauge.update can create it. You also don't want to be running an infinite loop inside Video.__init__. It's also not clear that Video should be a subclass of Gauge at all, but I would try something like
from queue import Queue
class Gauge(object):
def __init__(self, q: Queue):
self.capture = cv2.VideoCapture(2)
if self.capture.isOpened():
print("opened camera")
self.video_thread = Thread(target=self.update, args=(q,))
self.video_thread.name='video thread'
self.video_thread.daemon = True
self.video_thread.start()
# Stores captures in a queue for someone to consume
def update(self, q):
while True:
if self.capture.isOpened():
q.put(self.capture.read())
class Video(Gauge):
def __init__(self, master):
self.q = Queue()
super(Video, self).__init__(self.q)
def capture_images(self):
while True:
# Wait until a capture is available
status, frame = self.q.get()
# Then use the capture
image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
image = cv2.resize(image,(round(self.master.winfo_width()/2-20),round(self.master.winfo_height()-10)),interpolation=cv2.INTER_AREA)
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
self.labelVideo.configure(image=image)
self.labelVideo.image=image
v = Video()
v.capture_images()

How to read multi-camera streams with OpenCV seamlessly?

I went through this beautifully explained Q/A and I want something similar into a much stripped down version of the code I found there which includes PyQt4 and qdarkstyle.
My code is as follows:
import pafy
import base64
import zmq
from threading import Thread
import cv2
import time
class IPCamera(object):
def __init__(self, src=0):
self.frame = None
self.status = None
self.capture = cv2.VideoCapture(src)
self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 2)
self.FPS = 1/25
self.FPS_MS = int(self.FPS * 1000)
# Start frame retrieval thread
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
# self.frame = cv2.resize(self.frame, (640, 480)) # resize the frame
time.sleep(self.FPS)
def show_frame(self):
cv2.imshow('frame', self.frame)
cv2.waitKey(self.FPS_MS)
if __name__ == '__main__':
# Sample youtube video starts
youtube_link = 'https://www.youtube.com/watch?v=QgaUKlAuqn8'
vPafy = pafy.new(youtube_link)
play = vPafy.getbest(preftype="mp4")
src = play.url
# Sample youtube video ends
# Creating ZMQ context starts
context = zmq.Context()
footage_socket = context.socket(zmq.PUB)
footage_socket.connect('tcp://localhost:5555')
# cv2.namedWindow("Client Started!")
# Creating ZMQ context ends
threaded_camera = IPCamera(src)
while threaded_camera.capture.isOpened():
try:
if threaded_camera.status is True:
encoded, buffer = cv2.imencode('.jpg', threaded_camera.frame)
jpg_as_text = base64.b64encode(buffer)
footage_socket.send(jpg_as_text)
# key = cv2.waitKey(1)
# threaded_camera.show_frame()
# if key == 27: # exit on ESC
# break
# else:
# break
except AttributeError:
pass
The above code is running fine, I want to implement the code from the Q/A on the aforementioned link with those libraries removed. Can you help me in that?

Picamera multiprocess

I'm trying to use a separate process to take pictures. This code was modified from being a Thread to being a multiprocess (by me, this is why it doesn't work). When i create an instance of this class and then run it with obj.start() a popup appears the program is already running, do you want to stop it? I don't understand what am I doing wrong?
P.S ("GO" output is never shown on the screen)
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import multiprocessing
class MultiProcess(multiprocessing.Process):
def __init__(self):
print("INIT")
multiprocessing.Process.__init__(self)
# initialize the camera and stream
self.camera = PiCamera()
self.camera.resolution = (640, 480)
self.camera.framerate = 32
self.rawCapture = PiRGBArray(self.camera, size=(320, 240))
self.stream = self.camera.capture_continuous(self.rawCapture, format="bgr", use_video_port=True)
# initialize the frame and the variable used to indicate
# if the thread should be stopped
self.frame = None
self.stopped = False
def start(self):
# start the thread to read frames from the video stream
p = multiprocessing.Process(target=self.update, args=())
print("1")
p.daemon = True
print("2")
p.start()
print("3")
p.join()
print("GO")
return self
def update(self):
# keep looping infinitely until the thread is stopped
for f in self.stream:
print("NEVER REACH HERE")
# grab the frame from the stream and clear the stream in
# preparation for the next frame
self.frame = f.array
self.rawCapture.truncate(0)
# if the thread indicator variable is set, stop the thread
# and resource camera resources
if self.stopped:
self.stream.close()
self.rawCapture.close()
self.camera.close()
return
def read(self):
# return the frame most recently read
return self.frame
def stop(self):
# indicate that the thread should be stopped
self.stopped = True

How can i fetch live stream from url?

I am using RPi-cam-web-interface and from pi camera, rasperry pi continuously throws image to a link, I want to process that image using opencv on my computer.
Here is the link software I'm using suggested by sentdex.
Here's a link to sentdex's video.
Streaming URL to extract image from
is what it looks like, the url from which image is to be extracted.
Have you tried passing your url in VideoCapture like below:
cap = cv2.VideoCapture()
cap.opne("Your_URL")
If you can put your RPI link into VLC player, it should work for this widget. You can stream from a url using cv2.videoCapture(). Change rtsp_stream_link to your RPI url.
from threading import Thread
import cv2
class RTSPVideoWriterObject(object):
def __init__(self, src=0):
# Create a VideoCapture object
self.capture = cv2.VideoCapture(src)
# Default resolutions of the frame are obtained (system dependent)
self.frame_width = int(self.capture.get(3))
self.frame_height = int(self.capture.get(4))
# Set up codec and output video settings
self.codec = cv2.VideoWriter_fourcc('M','J','P','G')
self.output_video = cv2.VideoWriter('output.avi', self.codec, 30, (self.frame_width, self.frame_height))
# Start the thread to read frames from the video stream
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
def show_frame(self):
# Display frames in main program
if self.status:
cv2.imshow('frame', self.frame)
# Press Q on keyboard to stop recording
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
self.output_video.release()
cv2.destroyAllWindows()
exit(1)
def save_frame(self):
# Save obtained frame into video output file
self.output_video.write(self.frame)
if __name__ == '__main__':
rtsp_stream_link = 'your stream link!'
video_stream_widget = RTSPVideoWriterObject(rtsp_stream_link)
while True:
try:
video_stream_widget.show_frame()
#video_stream_widget.save_frame()
except AttributeError:
pass

Recording video with Opencv Python Multithreading

I am trying to record a video using opencv in python when doing multithreading within the thread that displays the stream on the window. I m fairly new to multithreading and I am not sure what is the reason I am unable to get a video recorded. I save a file but it does not have the stream in it. Pointers greatly appreciated.This is my code:
import cv2
import os
import threading
import shutil
import json
import re
import datetime
import time
now=datetime.datetime.now()
class camThread(threading.Thread):
def __init__(self, previewName, camID):
threading.Thread.__init__(self)
self.previewName = previewName
self.camID = camID
def run(self):
print("Starting " + self.previewName)
camPreview(self.previewName, self.camID)
def camPreview(previewName, camID):
cv2.namedWindow(previewName)
cam = cv2.VideoCapture(camID)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 480)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
if cam.isOpened():
rval, frame = cam.read()
frame_width = int(cam.get(3))
frame_height = int(cam.get(4))
else:
rval = False
while rval:
cv2.namedWindow(previewName, cv2.WINDOW_NORMAL)
if (camID == 2):
frame= cv2.flip(frame,-1)
# cv2.setWindowProperty(previewName, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
cv2.imshow(previewName, frame)
# cam.set(CV_CAP_PROP_SETTINGS, 0)
rval, frame = cam.read()
key = cv2.waitKey(20)
if key == 115 :
Cam1="Cam"+str(camID)+"_"+timestr
ts=datetime.datetime.now()
filename="{}.avi".format(Cam1+ts.strftime("%Y%m%d_%H-%M-%S"))
out=cv2.VideoWriter(filename,cv2.VideoWriter_fourcc('M','J', 'P','G'),10,(480,720))
out.write(frame)
if key == 27:
print("Stopping recording")
break
if key == 27: # exit on ESC
break
cv2.destroyWindow(previewName)
# Create threads as follows
thread1 = camThread("Camera 1", 0)
thread2 = camThread("Camera 2", 2)
thread3 = camThread("Camera 3", 3)
timestr=str(now.strftime("%Y%m%d_%H-%M-%S"))
print("Working Directory:")
print(timestr)
#thread1.start()
thread2.start()
thread3.start()
print()
print("Active threads", threading.activeCount())
from threading import Thread
import cv2
import time
class VideoWriterWidget(object):
def __init__(self, video_file_name, src=0):
# Create a VideoCapture object
self.frame_name = str(src) # if using webcams, else just use src as it is.
self.video_file = video_file_name
self.video_file_name = video_file_name + '.avi'
self.capture = cv2.VideoCapture(src)
# Default resolutions of the frame are obtained (system dependent)
self.frame_width = int(self.capture.get(3))
self.frame_height = int(self.capture.get(4))
# Set up codec and output video settings
self.codec = cv2.VideoWriter_fourcc('M','J','P','G')
self.output_video = cv2.VideoWriter(self.video_file_name, self.codec, 30, (self.frame_width, self.frame_height))
# Start the thread to read frames from the video stream
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
# Start another thread to show/save frames
self.start_recording()
print('initialized {}'.format(self.video_file))
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
def show_frame(self):
# Display frames in main program
if self.status:
cv2.imshow(self.frame_name, self.frame)
# Press Q on keyboard to stop recording
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
self.output_video.release()
cv2.destroyAllWindows()
exit(1)
def save_frame(self):
# Save obtained frame into video output file
self.output_video.write(self.frame)
def start_recording(self):
# Create another thread to show/save frames
def start_recording_thread():
while True:
try:
self.show_frame()
self.save_frame()
except AttributeError:
pass
self.recording_thread = Thread(target=start_recording_thread, args=())
self.recording_thread.daemon = True
self.recording_thread.start()
if __name__ == '__main__':
src1 = 'Your link1'
video_writer_widget1 = VideoWriterWidget('Camera 1', src1)
src2 = 'Your link2'
video_writer_widget2 = VideoWriterWidget('Camera 2', src2)
src3 = 'Your link3'
video_writer_widget3 = VideoWriterWidget('Camera 3', src3)
# Since each video player is in its own thread, we need to keep the main thread alive.
# Keep spinning using time.sleep() so the background threads keep running
# Threads are set to daemon=True so they will automatically die
# when the main thread dies
while True:
time.sleep(5)
I think you're on the right track but I was unable to save a file with your code. Here's a video-stream-to-video widget using multithreading to obtain the frames. There are two threads for each camera stream:
Thread #1 - Dedicated to only reading frames from the camera stream.
Thread #2 - Dedicated for processing frames (showing and writing).
We separate reading frames from showing/writing because cv2.VideoCapture.read() is a blocking operation. Thus we read frames in its own independent thread to 'improve' FPS by reducing latency due to I/O operations. In addition, by isolating frame capture to its own thread, there will always be a frame ready to be processed instead of having to wait for the I/O operation to complete and return a new frame. In our second thread dedicated to processing, we are now freely able to show and save each frame to our output file.
Also by encapsulating all this into a single object, we can create a set of threads for each camera which scales easily no matter how many cameras are being used. Since each camera stream is spawned in a background thread, we must keep the main thread alive. Be sure to change the src string to your own camera. Here's an example of recording three video streams simultaneously.
from threading import Thread
import cv2
import time
class VideoWriterWidget(object):
def __init__(self, video_file_name, src=0):
# Create a VideoCapture object
self.frame_name = str(src)
self.video_file = video_file_name
self.video_file_name = video_file_name + '.avi'
self.capture = cv2.VideoCapture(src)
# Default resolutions of the frame are obtained (system dependent)
self.frame_width = int(self.capture.get(3))
self.frame_height = int(self.capture.get(4))
# Set up codec and output video settings
self.codec = cv2.VideoWriter_fourcc('M','J','P','G')
self.output_video = cv2.VideoWriter(self.video_file_name, self.codec, 30, (self.frame_width, self.frame_height))
# Start the thread to read frames from the video stream
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
# Start another thread to show/save frames
self.start_recording()
print('initialized {}'.format(self.video_file))
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
def show_frame(self):
# Display frames in main program
if self.status:
cv2.imshow(self.frame_name, self.frame)
# Press Q on keyboard to stop recording
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
self.output_video.release()
cv2.destroyAllWindows()
exit(1)
def save_frame(self):
# Save obtained frame into video output file
self.output_video.write(self.frame)
def start_recording(self):
# Create another thread to show/save frames
def start_recording_thread():
while True:
try:
self.show_frame()
self.save_frame()
except AttributeError:
pass
self.recording_thread = Thread(target=start_recording_thread, args=())
self.recording_thread.daemon = True
self.recording_thread.start()
if __name__ == '__main__':
src1 = 'Your link1'
video_writer_widget1 = VideoWriterWidget('Camera 1', src1)
src2 = 'Your link2'
video_writer_widget2 = VideoWriterWidget('Camera 2', src2)
src3 = 'Your link3'
video_writer_widget3 = VideoWriterWidget('Camera 3', src3)
# Since each video player is in its own thread, we need to keep the main thread alive.
# Keep spinning using time.sleep() so the background threads keep running
# Threads are set to daemon=True so they will automatically die
# when the main thread dies
while True:
time.sleep(5)

Categories