Use VideoCapture() in two different function within same class OpenCV Python - python

I'm making a GUI in which one button will display the video and another button will start capturing frames from that video at certain intervals.
Here, are the functions that are called by the buttons:-
def capture(self):
global img_location
global camera
camera = cv2.VideoCapture(1)
return_value, image = camera.read()
time.sleep(2) #set the delay you want in frame
now_time = strftime("%Y-%m-%d %H:%M:%S", gmtime())
img_location = './timelapse_focus/'+FolderName+'/'+ now_time +'.jpg'
cv2.imwrite(img_location, image)
del(camera)
def display(self):
# Create a VideoCapture object and read from input file
# If the input is the camera, pass 0 instead of the video file name
# Check if camera opened successfully
camera = cv2.VideoCapture(1)
if (camera.isOpened()== False):
print("Error opening video stream or file")
# Read until video is completed
while(camera.isOpened()):
# Capture frame-by-frame
ret, frame = camera.read()
if ret == True:
# Display the resulting frame
cv2.imshow('Frame',frame)
# Press <q> on keyboard to exit
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# Break the loop
else:
break
# When everything done, release the video capture object
camera.release()
# Closes all the frames
cv2.destroyAllWindows()
for i in range (1,5):
cv2.waitKey(1)
It's showing the following error:-
HIGHGUI ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV
VIDIOC_STREAMON: Bad file descriptor
Unable to stop the stream.: Bad file descriptor
To do the same I tried to declare the camera variable globally.
But it's not working. Even I used self. camera, it is also not working.
Please suggest something.

The problem here is that you try to open cv2.VideoCapture(1) both in the display(self) and in the capture(self). Set frame as self.frame in display(self) and use it in capture(self). Like this:
def capture(self):
time.sleep(2) #set the delay you want in frame
now_time = strftime("%Y-%m-%d %H:%M:%S", gmtime())
img_location = './timelapse_focus/'+FolderName+'/'+ now_time +'.jpg'
cv2.imwrite(img_location, self.frame)
def display(self):
# Create a VideoCapture object and read from input file
# If the input is the camera, pass 0 instead of the video file name
# Check if camera opened successfully
camera = cv2.VideoCapture(1)
if (camera.isOpened()== False):
print("Error opening video stream or file")
# Read until video is completed
while(camera.isOpened()):
# Capture frame-by-frame
ret, self.frame = self.camera.read()
if ret == True:
# Display the resulting frame
cv2.imshow('Frame',self.frame)
# Press <q> on keyboard to exit
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# Break the loop
else:
break
# When everything done, release the video capture object
camera.release()
# Closes all the frames
cv2.destroyAllWindows()
for i in range (1,5):
cv2.waitKey(1)
This is only for capturing one frame each time you call capture(self). Otherwise you need to add a while loop and the method in a Thread in order not to crash your GUI.

Related

Video playback using Tkinter and OpenCV too slow

If I use OpenCV to play video into its own window using this sort of logic:
cap = cv2.VideoCapture('video.mp4',cv2.CAP_FFMPEG)
while True:
ret, frame = cap.read()
if(ret):
cv2.imshow('', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
then it works well and smoothly. But if I use what appears to be the recommended way of playing into my own tkinter window, using the window.after() technique like this snippet:
def update(self):
# Get a frame from the video source
ret, frame = cap.read()
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tk.NW)
self.update_id = self.window.after(self.VIDEO_READ_DELAY, self.update)
it is slow and stutters badly. I've played with the update delay without any real success, so I'm guessing that the processing overhead of the image conversion is what's causing the problem.
Can imshow() be made to play into my tkinter canvas directly?

How to start and stop saving video frames according to a trigger with OpenCV VideoWriter

I am building an app that records frames from IP camera through RTSP.
My engine is in charge to save a video in mp4 with Opencv VideoWriter working well.
What I am looking for is to create a startRecord and a stopRecord class method that will respectively start and stop recording according to a trigger (it could be an argument that I pass to the thread).
Is anyone know what the best way to do that kind of stuff?
Here is my class:
from threading import Thread
import cv2
import time
import multiprocessing
import threading
class RTSPVideoWriterObject(object):
def __init__(self, src=0):
# Create a VideoCapture object
self.capture = cv2.VideoCapture(src)
# 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 endRecord(self):
self.capture.release()
self.output_video.release()
exit(1)
def startRecord(self,endRec):
self.frame_width = int(self.capture.get(3))
self.frame_height = int(self.capture.get(4))
self.codec = cv2.VideoWriter_fourcc(*'mp4v')
self.output_video = cv2.VideoWriter('fileOutput.mp4', self.codec, 30, (self.frame_width, self.frame_height))
while True:
try:
self.output_video.write(self.frame)
if endRec:
self.endRecord()
except AttributeError:
pass
if __name__ == '__main__':
rtsp_stream_link = 'rtsp://foo:192.5545....'
video_stream_widget = RTSPVideoWriterObject(rtsp_stream_link)
stop_threads = False
t1 = threading.Thread(target = video_stream_widget.startRecord, args =[stop_threads])
t1.start()
time.sleep(15)
stop_threads = True
As you can see in the main I reading frames and store them in a separate thread. Then I am starting to record (record method is with an infinite loop so blocking) and then after 15 sec, I am trying to pass a 'stop_record' argument to stop recording properly.
A part of the code comes from Storing RTSP stream as video file with OpenCV VideoWriter
Is someone have an idea?
I read a lot that OpenCV can be very tricky for multithreading
N.
Instead of passing arguments to the thread, use a internal flag in the class to determine when to start/stop recording. The trigger could be as simple as pressing the spacebar to start/stop recording. When the spacebar is pressed it will switch an internal variable, say self.record to True to start recording and False to stop recording. Specifically, to check when the spacebar is pressed, you can check if the returned key value from cv2.waitKey() is 32. If you want the trigger based on any other key, take a look at this post to determine the key code. Here's a quick example to start/stop recording a video using the spacebar:
from threading import Thread
import cv2
class RTSPVideoWriterObject(object):
def __init__(self, src=0):
# Create a VideoCapture object
self.capture = cv2.VideoCapture(src)
self.record = True
# 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(*'mp4v')
self.output_video = cv2.VideoWriter('output.mp4', 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)
if self.record:
self.save_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)
# Press spacebar to start/stop recording
elif key == 32:
if self.record:
self.record = False
print('Stop recording')
else:
self.record = True
print('Start recording')
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()
except AttributeError:
pass
I solved the problem by creating a global variable inside the class, for your case endRec.

Is there a way to check if camera is connected without cap = cv2.videocapture

I am making a program that checks if the camera is connected, and if so, Show the webcam footage, The problem is: The way i structured my program i cannot have cap = cv2.videocapture() for the time it takes the command to execute. This makes sabotages for the showframe function and makes it only show a frame every ~1 second. Is there a different way to check if the camera is connected rather than cap = cv2.videocapture() and cap.isOpened()?
I also cannot have a while loop in my program because of the root.mainloop command for tkinter, However, if there is no way to check my camera status rather than cap.isOpened(), can i move the root.mainloop command somewhere where i can have a while True loop in my program?
I've tried both Multiprocessesing and Threading with no further success.
Heres some code:
from tkinter import * # Import the tkinter module (For the Graphical User Interface)
import cv2 # Import the cv2 module for web camera footage
import PIL # Import the pillow library for image configuration.
from PIL import Image, ImageTk # Import the specifics for Image configuration.
print("[INFO] Imports done")
width, height = 800, 600 # Define The width and height widget for cap adjustment
RootGeometry = str(width) + "x" + str(height) # Make a variable to adjust tkinter frame
print("[INFO] Geometries made")
ImageSource = 0
cap = cv2.VideoCapture(ImageSource) # First VideoCapture
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
print("[INFO] Cap set")
root = Tk()
print("[INFO] Window made")
root.title("Main Window")
root.configure(background="white")
root.geometry(RootGeometry)
root.bind('<Escape>', lambda e: root.quit())
lmain = Label(root)
lmain.pack()
print("[INFO] Configuration of cap done.")
def ShowFrame():
ok, frame = cap.read()
if ok:
print("[INFO] Show frame Initialized.")
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = PIL.Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
print("[INFO] After 10 initializing")
lmain.after(10, ShowFrame)
print("[INFO] Showed image")
else:
lmain.after(10, CheckSource)
def CheckSource():
print("[INFO] CheckSource Triggered.")
cap = cv2.VideoCapture(ImageSource)
if cap.isOpened():
print("[INFO] [DEBUG] if Ok initialized")
if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.destroyAllWindows()
cv2.waitKey(0)
print("[WARNING] Exiting app after command")
ShowFrame()
else:
print("[WARNING] No source found. Looking for source.")
lmain.after(10, CheckSource)
CheckSource()
root.mainloop()
print("[INFO] [DEBUG] Root.Mainoop triggered")
Any and all help would be very appreciated!
When there is no webcam/image source, cap.read() will be (False, none). Therefore you can check if a webcam is connected if you do something like:
import cv2
cap=cv2.VideoCapture(ImageSource)
while True:
if cap.read()[0]==False:
print("Not connected")
cap=cv2.VideoCapture(imageSource)
else:
ret, frame=cap.read()
cv2.imshow("webcam footage",frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Hope this helps :)
You should not do a VideoCapture each frame, you only need to check if it exists. isOpened() is the proper function for that. If it does not yet exist, then retry the cam.
I modified your code:
def CheckSource():
print("[INFO] CheckSource Triggered.")
# check if cam is open, if so, do showFrame
if cap.isOpened():
print("[INFO] [DEBUG] if Ok initialized")
if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.destroyAllWindows()
cv2.waitKey(0)
print("[WARNING] Exiting app after command")
ShowFrame()
else:
# cam is not open, try VideoCapture
print("[WARNING] No source found. Looking for source.")
cap = cv2.VideoCapture(ImageSource)
lmain.after(10, CheckSource)

Video Streaming from IP Camera in Python Using OpenCV cv2.VideoCapture

I am trying to get video stream in python from IP camera but i am getting an error. I am Using Pycharm IDE.
import cv2
scheme = '192.168.100.23'
host = scheme
cap = cv2.VideoCapture('http://admin:Ebmacs8485867#'+host+':81/web/admin.html')
while True:
ret, frame = cap.read()
# Place options to overlay on the video here.
# I'll go over that later.
cv2.imshow('Camera', frame)
k = cv2.waitKey(0) & 0xFF
if k == 27: # esc key ends process
cap.release()
break
cv2.destroyAllWindows()
Error:
"E:\Digital Image Processing\python\ReadingAndDisplayingImages\venv\Scripts\python.exe" "E:/Digital Image Processing/python/ReadingAndDisplayingImages/ReadandDisplay.py"
Traceback (most recent call last):
File "E:/Digital Image Processing/python/ReadingAndDisplayingImages/ReadandDisplay.py", line 14, in <module>
cv2.imshow('Camera', frame)
cv2.error: OpenCV(4.0.1) C:\projects\opencv-python\opencv\modules\highgui\src\window.cpp:352: error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'cv::imshow'
warning: Error opening file (/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:901)
warning: http://admin:Ebmacs8485867#192.168.100.23:81/web/admin.html (/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:902)
You're most likely getting that error due to an invalid stream link. Insert your stream link into VLC player to confirm it is working. Here's a IP camera video streaming widget using OpenCV and cv2.VideoCapture.read(). This implementation uses threading for obtaining frames in a different thread since read() is a blocking operation. By putting this operation into a separate that that just focuses on obtaining frames, it improves performance by I/O latency reduction. I used my own IP camera RTSP stream link. Change stream_link to your own IP camera link.
Depending on your IP camera, your RTSP stream link will vary, here's an example of mine:
rtsp://username:password#192.168.1.49:554/cam/realmonitor?channel=1&subtype=0
rtsp://username:password#192.168.1.45/axis-media/media.amp
Code
from threading import Thread
import cv2
class VideoStreamWidget(object):
def __init__(self, src=0):
# Create a VideoCapture object
self.capture = cv2.VideoCapture(src)
# 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:
self.frame = self.maintain_aspect_ratio_resize(self.frame, width=600)
cv2.imshow('IP Camera Video Streaming', self.frame)
# Press Q on keyboard to stop recording
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
cv2.destroyAllWindows()
exit(1)
# Resizes a image and maintains aspect ratio
def maintain_aspect_ratio_resize(self, image, width=None, height=None, inter=cv2.INTER_AREA):
# Grab the image size and initialize dimensions
dim = None
(h, w) = image.shape[:2]
# Return original image if no need to resize
if width is None and height is None:
return image
# We are resizing height if width is none
if width is None:
# Calculate the ratio of the height and construct the dimensions
r = height / float(h)
dim = (int(w * r), height)
# We are resizing width if height is none
else:
# Calculate the ratio of the 0idth and construct the dimensions
r = width / float(w)
dim = (width, int(h * r))
# Return the resized image
return cv2.resize(image, dim, interpolation=inter)
if __name__ == '__main__':
stream_link = 'your stream link!'
video_stream_widget = VideoStreamWidget(stream_link)
while True:
try:
video_stream_widget.show_frame()
except AttributeError:
pass
Related camera/IP/RTSP, FPS, video, threading, and multiprocessing posts
Python OpenCV streaming from camera - multithreading, timestamps
Video Streaming from IP Camera in Python Using OpenCV cv2.VideoCapture
How to capture multiple camera streams with OpenCV?
OpenCV real time streaming video capture is slow. How to drop frames or get synced with real time?
Storing RTSP stream as video file with OpenCV VideoWriter
OpenCV video saving
Python OpenCV multiprocessing cv2.VideoCapture mp4

Auto-capture an image from a video in OpenCV using python

I am trying developing a code which functions as the self-timer camera. The video would be seen in the window and the person's face and eyes would be continuously detected and once the user selects a specific time, the frame at that point of time is captured. I am able to capture the frame after a certain time using sleep function in time module but the video frame seems to freeze. Is there any solution such that I can continue to see the video and the video capture takes place after some delay automatically.
I am using the code-
import numpy as np
import cv2
import time
import cv2.cv as cv
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',frame)
#time.sleep(01)
Capture = cv.CaptureFromCAM(0)
time.sleep(5)
ret, frame = cap.read()
image = cv.QueryFrame(Capture) #here you have an IplImage
imgarray = np.asarray(image[:,:]) #this is the way I use to convert it to numpy array
cv2.imshow('capImage', imgarray)
cv2.waitKey(0)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
Can someone suggest me? Any kind of help would be appreciated.
In order to continuously view the video, you need to repeat the same part of the code which displays the video first and put it in a while loop. Make sure that the handle to the window is not lost.You can make the capture as a mouse click event and use a tickcount, one before the start of the while loop and one inside the loop. Once the difference between the two tick counts is equal to some pre-defined seconds,capture that frame, use break and come out of the while loop.
You need to add another 'cap.read()' line when the delay ends, as this is the code that actually captures the image.
use threading and define the cv.imshow() separately from your function
import threading
import cv2
def getFrame():
global frame
while True:
frame = video_capture.read()[1]
def face_analyse():
while True:
#do some of the opeartion you want
def realtime():
while True:
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
video_capture.release()
cv2.destroyAllWindows()
break
if __name__ == "__main__":
video_capture = cv2.VideoCapture(cam)
frame = video_capture.read()[1]
gfthread = threading.Thread(target=getFrame, args='')
gfthread.daemon = True
gfthread.start()
rtthread = threading.Thread(target=realtime, args='')
rtthread.daemon = True
rtthread.start()
fathread = threading.Thread(target=face_analyse, args='')
fathread.daemon = True
fathread.start()
while True: #keep main thread running while the other two threads are non-daemon
pass

Categories

Resources