Python OpenCV: Mutithreading with opecv video streaming - python

I wanted to run one multithread along with opencv video stream. I want to activate GPIO if the object gets detected for 3 seconds while the video is streaming constantly. I have tried with multithreading (join method) but the video gets paused during the thread call, because it is having time.sleep(). Is there any way I can stream the video constantly and parallelly run the thread? Below is the code behaving the same way. If I remove the join than time.sleep is not at all have any effect.
import threading
import time
import numpy as np
import cv2
def print_hello():
print("Hello")
time.sleep(3)
print ("World")
t1 = threading.Thread(target=print_hello)
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
t1.start()
t1.join()
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

.join() waits for end of thread and it blocks code - so it makes no sends to run it inside loop but you should run it after loop or at the end of program
Other problem is .start() in loop because .start() can runs thread only once so using it many times in loop will generate error.
You can start thread before loop and run some loop inside thread to run it all time.
import threading
import time
import numpy as np
import cv2
# --- functions ---
running = True
def print_hello():
while running:
print("Hello World")
time.sleep(3)
# --- main ---
t1 = threading.Thread(target=print_hello)
t1.start()
# --- loop ---
cap = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# --- after loop ---
running = False # to stop loop in thread
t1.join()
cap.release()
cv2.destroyAllWindows()
If you have to start thread in loop then you would have to also create new thread inside loop.
In this example I use key t to start new thread - without this it would create new thread in every loop so it would create hundreds of threads in short time so it makes no sense.
import threading
import time
import numpy as np
import cv2
# --- functions ---
def print_hello():
print("Hello")
time.sleep(3)
print("World")
# --- main ---
all_threads = []
# --- loop ---
cap = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
if key == ord('t'):
t = threading.Thread(target=print_hello)
t.start()
all_threads.append(t)
# --- after loop ---
for t in all_threads:
t.join()
cap.release()
cv2.destroyAllWindows()
But even pressing t many times you can create many threads at the same time and they will work together. If you don't need it then you would have to control if threat is still working and create new one only when it doesn't work any more - use is_alive() - so it can make it more complex.
import threading
import time
import numpy as np
import cv2
# --- functions ---
def print_hello():
print("Hello")
time.sleep(3)
print("World")
# --- main ---
t = None
# --- loop ---
cap = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
if key == ord('t'):
if t is None or not t.is_alive():
t = threading.Thread(target=print_hello)
t.start()
else:
print('previous thread is still running')
# --- after loop ---
if t is not None:
t.join()
cap.release()
cv2.destroyAllWindows()

This is almost never a good idea:
t1.start()
t1.join()
The problem is, it defeats the only purpose of threads, which is, to be able to two two different things at the same time.
This makes more sense because "...some_other_thing...()" can be happening while t1 is doing whatever t1 does.
t1.start()
do_some_other_thing_concurrently_with_t1()
t1.join()

Related

Record the video, save it automatically, and record it again

I'm looking for ways to save the video every minute and record it again.
When I run my code, I capture it until I press 'q'.
Is there a way to automatically save it and record it again?
I use imutils, cv2
import imutils
import cv2 # opencv 모듈
video = ""
result_path = "result_video.avi"
if video == "":
print("[webcam start]")
vs = cv2.VideoCapture(0)
else:
print("[video start]")
vs = cv2.VideoCapture(video)
writer = None
while True:
ret, frame = vs.read()
if frame is None:
break
frame = imutils.resize(frame, width=320, height=240)
cv2.imshow("frame", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
if writer is None:
fourcc = cv2.VideoWriter_fourcc(*"MJPG")
writer = cv2.VideoWriter(result_path, fourcc, 25, (frame.shape[1], frame.shape[0]), True)
if writer is not None:
writer.write(frame)
vs.release()
cv2.destroyAllWindows()
You have not posted your code and its not obvious, how you are recording but following code can add a timer for you that offers a lot of customization e.g. recording once in specified seconds, minutes or even hours.
from time import sleep
from apscheduler.schedulers.blocking import BlockingScheduler
def RecordVideo():
print("Starting the recording")
#record your content
#close camera/desktop or other resource
print('Recording Completed!')
scheduler = BlockingScheduler()
scheduler.add_job(RecordVideo, 'interval', minutes=1) #once per minute
#scheduler.add_job(RecordVideo, 'interval', seconds=60) for timer in seconds
#scheduler.add_job(RecordVideo, 'interval', seconds=60) for timer in hours
scheduler.start()
while True: #keeps the program running
sleep(0.1)
Simply add your recording function as a job

How to play it on fullscreen python cv2

How do I play the video.mp4 in fullscreen instead of playing it in a window
and is there any way to play video with audio without playing the audio separately?
import cv2
from playsound import playsound
from threading import Thread
def func1():
cap = cv2.VideoCapture("video.mp4")
ret, frame = cap.read()
while(1):
ret, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(33) & 0xFF == ord('q') or ret==False :
cap.release()
cv2.destroyAllWindows()
break
cv2.imshow('frame',frame)
def func2():
playsound('6989946141014084358.mp3')
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
You should be able to setup the window ahead of time (e.g. before your blocking while loop):
cv2.namedWindow('frame',cv2.WINDOW_NORMAL)
cv2.setWindowProperty('frame',cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)

uninterrupted while loop with python cv2.VideoCapture() and string input

I use this code to capture and display the input from my webcam.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
check, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
I have a barcode scanner and want to check inside the while loop if a specific string gets scanned in.
input() interupts the stream from the webcam. I need something like cv2.waitKey() but for strings
while(True):
check, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitString(barcode) == '123456':
# do something
if cv2.waitString(barcode) == '098765':
# do something else
I tried msvcrt, but to no avail. The stream continues but nothing gets printed.
if msvcrt.kbhit():
if msvcrt.getwche() == '280602017300':
print("Barcode scanned!")
Or is there a way to skip input() until something was entered?
UPDATE
Making some progress with the help of this post.
How to read keyboard-input?
I was able to update my code.
import threading
import queue
import time
import numpy as np
import cv2
def read_kbd_input(inputQueue):
print('Ready for keyboard input:')
while (True):
input_str = input()
inputQueue.put(input_str)
def main():
inputQueue = queue.Queue()
inputThread = threading.Thread(target=read_kbd_input, args=(inputQueue,), daemon=True)
inputThread.start()
cap = cv2.VideoCapture(0)
font = cv2.FONT_HERSHEY_DUPLEX
fontScale = 1
fontColor = (255,255,255)
lineType = 2
input_str = "test"
while (True):
check, frame = cap.read()
if (inputQueue.qsize() > 0):
input_str = inputQueue.get()
if (input_str == '280602017300'):
print("do something")
cv2.putText(frame, input_str, (10,30), font, fontScale, fontColor, lineType)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
time.sleep(0.01)
print("End.")
if (__name__ == '__main__'):
main()
Now the only problem left is that my webcam stream is supposed to run in fullscreen. So the console will allways be in the background and therefore wont get the inputs form the keyboard or my barcode scanner.
need it the other way around

create new window video stream in tkinter

In my program, i want to show the camera stream and gui in apart. I think i have to use thread for this in python but i dont know how to do that?
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Display the resulting frame
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
How can i change above code to open a new window and display the video stream with thread.
I hope I understand you correctly, that you want to run:
the capturing of the images from the camera in one thread,
while in parallel show the captured images (when available) in another thread.
A classic "producer-consumer problem"!
Consider then the following code:
import cv2
import threading
from threading import Event
class multi_thread_stream:
def __init__(self, ready=None):
self.ready = ready
self.cap = cv2.VideoCapture(0)
self.frame = {}
#Create the Threads
self.t1 = threading.Thread(target=self.capture_stream)
self.t2 = threading.Thread(target=self.display_image)
self.t1.name = 'capture_thread'
self.t2.name = 'display_thread'
self.t1.start()
self.t2.start()
def capture_stream(self):
while True:
# Capture frame-by-frame
self.ret, self.frame = self.cap.read()
self.ready.set()
if cv2.waitKey(1) & 0xFF == ord('q'):
break
def display_image(self):
while True:
# Display the resulting frame
self.ready.wait()
cv2.imshow('frame_2nd_trhead', self.frame)
self.ready.clear()
if cv2.waitKey(1) & 0xFF == ord('q'):
break;
def __del__(self):
# When everything done, release the capture
self.cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
ready = Event()
mts = multi_thread_stream(ready)
mts.t1.join()
mts.t2.join()
There are two functions, that run in two threads. The display-thread waits for a trigger and until the capture-thread has already read a frame and sent a trigger to the display-thread, the display-thread cannot continue further and hence cannot show an image (or throw an error of invalid variable size).
Hope it helps. (or at least it can be a basis for your further solution).

python opencv: ingnoring delay in webcam recording

I am using opencv python for video recording. I am getting problem with continuous operation. I have given delay for some events not for the recording. When I run the program, the program is only taking frames after the amount of delay I have gave. Can any one help me to record contentiously even if delay is given in the loop. I am sending you example code.
Thanks.
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
fouecc = cv2.VideoWrite_fourcc(*'XVID')
out = cv2.VideoWrite('output.avi', fourcc, 20.0,(640,480))
while(True):
ret, frame = cap.read()
out.write(frame)
cv2.imshow('frame', frame)
pump_5.dispense(1,1)
time.sleep(2)
pump_4.dispense(1,1)
time.sleep(2)
if cv2.waitkey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()

Categories