Stop video by its play time - python

I created a program to extract the video into frames.I need suggestion to stop the cv2.imshow() after when there is no more frames to show.
video frames count = 88
fps = 10.0
duration= int(8)
def reading_video():
read_input = cv2.VideoCapture(r"D:\data\input.mp4")
frame_rate = int(read_input.get(cv2.CAP_PROP_FRAME_COUNT)) # 88
print("total number of frames is ", frame_rate)
fps = read_input.get(cv2.CAP_PROP_FPS) #10.0
duration = int((frame_rate/fps) %60)# 8
print(duration) # 8.0
initial_frame = 0
while read_input.isOpened():
ret, frame = read_input.read()
if ret == True:
cv2.imshow('video_frame', frame)
write_path = r"D:\data\frame_output"
write_name = 'frame0' + str(initial_frame) + '.jpg'
cv2.imwrite(os.path.join(write_path, write_name), frame)
initial_frame += 1
if cv2.waitKey(0) & 0xFF == ord('c'):
break
else:
break
instance_variable = reading_video()
instance_variable.release()
cv2.destroyAllWindows()
If waitkey(int(duration)) then it played and after no frame i do getting cv2 Assertion error.
If waitkey(0) then i do getting AttributeError: 'NoneType' object has no attribute 'release'

reading_video() doesn't uses return so it returns None and you have
instance_variable = None
and later
None.release()
Inside reading_video() you should use
return read_input
or maybe even directly
read_input.release()
without instance_variable.release()

Related

Save a video with different file name each time we give a Trigger in opencv

This is the process I am trying to achieve :
Live Stream is captured from webcam and the Image frames are stored in a particular folder.
Now, If I give a trigger the frames in that folder at that moment should be converted into a video and get saved with name eg. video1.mp4.
Now again if I press a trigger another video should be saved as video2.mp4.
I have attached the code here . If I press R , it is saving one video as a0.mp4 . But If I press again, nothing seems to happen.
def frametovideo(img_array):
for i in range(len(img_array)):
out.write(img_array[i])
if name == "main":
img_array = []
videono = 0
cap = cv2.VideoCapture(0)
for filename in glob.glob('./output/*.jpg'):
img = cv2.imread(filename)
height, width, layers = img.shape
size = (width,height)
img_array.append(img)
path = 'a' + str(videono) + '.mp4'
out = cv2.VideoWriter(path,cv2.VideoWriter_fourcc(*'mp4v'), 15, size)
while True:
ret, frame = cap.read()
if ret == True:
cv2.imshow("frame",frame)
k = cv2.waitKey(5) & 0xff
if k == ord('r'):
frametovideo(img_array)
videono += 1
You do not understanding how to save filenames Do not used operator. Used string format python 3.8 or later. Try this in below. Actually, you can modified key press.
import cv2
import os
i = 1
wait = 0
video = cv2.VideoCapture(0)
while video.isOpened():
ret, img = video.read()
cv2.imshow('live video', img)
# wait for user to press any key
key = cv2.waitKey(100)
# wait variable is to calculate waiting time
wait = wait+100
if key == ord('q'):
break
# when it reaches to 5000 milliseconds
# we will save that frame in given folder
if wait == 5000:
filename = f'Frame_{str(i)}.jpg'
# Save the images in given path
cv2.imwrite(filename, img)
i += 1
wait = 0
# close the camera
video.release()
# close open windows
cv2.destroyAllWindows()
Btw,look in line #27-34. Correct way to do this if __name__ == "__main__":

Detecting water in a plant stem in real time using computer vision (OpenCV and Python)

I am working on an experiment with plants in a pressure chamber. I need to be able to identify with a computer vision algorithm the exact moment when water starts to appear at the cut end of the stem. In the case of this video - taken from a USB microscope, this is the interval between 0:30 and 0:34 seconds, approximately.
I tried to use MOG, MOG2 and GMG as a background subtractor, and compare the histograms of each frame (using chi-squared, bhattacharyya, correlation), looking for changes that could be significant, however still without success. Is there a better alternative for this type of work?
Below, some code (made with the help of a friend)
import numpy as np
import sys
import time
import cv2
from matplotlib import pyplot as plt
video_filename = 'M20201022_004.mov'
capture = cv2.VideoCapture(video_filename)
#fgbg = cv2.bgsegm.createBackgroundSubtractorMOG()
fgbg = cv2.createBackgroundSubtractorMOG2()
#kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
#fgbg = cv2.bgsegm.createBackgroundSubtractorGMG()
width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
frames_per_second = capture.get(cv2.CAP_PROP_FPS)
num_frames = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
print(' height: {}\n width: {}\n fps: {}\n num_frames: {}\n'.format(height, width,frames_per_second, num_frames))
frameCounter = 0
t = time.process_time()
dist_hist = 0 # distance between histograms
frame_hist = 0
time_hist = 0
#write file
file1 = open("resultado.txt","w")
if not capture.isOpened():
print("Could not open video")
print('frameCounter: {}'.format(frameCounter))
sys.exit(1)
while capture.isOpened():
success, frame = capture.read()
frameCounter += 1
# Test for read error
if not success:
print('Failed to read video - Video Capture EOF or Error')
print('frameCounter:{}'.format(frameCounter))
if frameCounter == num_frames + 1:
print('EOF found')
else:
print('error')
break
#sys.exit(1)
else:
if frameCounter % 1000 == 0:
print('type:{} size:{} dtype:{} len(shape):{} contador:{}'.format(type(frame),frame.size,frame.dtype,len(frame.shape),frameCounter))
if len(frame.shape) < 3: # grayscale
h, w = frame.shape
print('h:{} w:{}'.format(h, w))
else: # color image
h, w, ch = frame.shape
print('h:{} w:{} ch:{}'.format(h, w, ch))
fgmask = fgbg.apply(frame)
#fgmask = fgbg.apply(frame)
#fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
# Initial histogram Test
if frameCounter == 1:
hist_initial = cv2.calcHist([fgmask], [0],None,[16],[0, 256])
# print('hist_initial:{}'.format(hist_initial))
#elapsed_time = time.process_time() - t
elapsed_time = frameCounter / frames_per_second
# Process Histogram
hist_process = cv2.calcHist([fgmask], [0],None,[16],[0, 256])
dist = cv2.compareHist(hist_initial, hist_process,cv2.HISTCMP_CHISQR)
str1 = str(frameCounter) + "," + str(dist) + "," + str(dist_hist) + "," + str(elapsed_time)
file1.write(str1)
file1.write("\n")
if dist > dist_hist: # Depending on compareHist method
dist_hist = dist
time_hist = elapsed_time
frame_hist = frameCounter
# Print line at image
strfmt = 'frame: {} elapsed_time: {:7.2f}'.format(frameCounter, elapsed_time)
cv2.putText(frame, strfmt, (0, 50),cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0,0,255), 1, cv2.LINE_AA)
cv2.imshow('frame', frame)
cv2.imshow('fgmask', fgmask)
if cv2.waitKey(1) & 0xff == 27: # ESC pressed
break
print('---> frame:{} dist:{:10.6f} time:{:7.2f}'.format(frame_hist, dist_hist,time_hist))
capture.release()
cv2.destroyAllWindows()
file1.close()
Any help appreciated!

How do you perform Multithreaded Frame Extraction in Python with OpenCV?

Hi Stackoverflow Users,
I'm currently trying to perform a multithreaded frame extraction using OpenCV. I've made such multithreaded operations before on other tasks, but for some reason it doesnt seem to work on the frame extraction. This is my Code:
import cv2
import os
import face_recognition
from PIL import Image
import multiprocessing
try:
if not os.path.exists('frames'):
os.makedirs('frames')
except OSError:
print('Error: Creating directory of frames')
try:
if not os.path.exists('faces'):
os.makedirs('faces')
except OSError:
print('Error: Creating directory of faces')
def frame_extract_1():
currentFrame_extract = 1
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret1, frame = video_capture.read()
if ret1 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 1 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
def frame_extract_2():
currentFrame_extract = 2
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret2, frame = video_capture.read()
if ret2 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 2 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
def frame_extract_3():
currentFrame_extract = 3
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret3, frame = video_capture.read()
if ret3 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 3 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
def frame_extract_4():
currentFrame_extract = 4
video_capture = cv2.VideoCapture("DOLFACE_1.mp4")
while(True):
ret4, frame = video_capture.read()
if ret4 == False:
break
name = 'frames/frame_' + str(currentFrame_extract) + '.jpg'
print(f"Processor 4 extracted Frame {currentFrame_extract}, saving it as Frame_{currentFrame_extract}.jpg")
cv2.imwrite(name, frame)
currentFrame_extract += 4
video_capture.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
video_file_path = "DOLFACE_1.mp4"
frame_extractor_1 = multiprocessing.Process(target=frame_extract_1)
frame_extractor_2 = multiprocessing.Process(target=frame_extract_2)
frame_extractor_3 = multiprocessing.Process(target=frame_extract_3)
frame_extractor_4 = multiprocessing.Process(target=frame_extract_4)
frame_extractor_1.start()
frame_extractor_2.start()
frame_extractor_3.start()
frame_extractor_4.start()
frame_extractor_1.join()
frame_extractor_2.join()
frame_extractor_3.join()
frame_extractor_4.join()
Do you know what I am doing wrong? Every "Processor" creates the full Video, without skipping 4 Frames and letting the other Processors do the remaining 3.

Recording video in specified time intervals and then saving them into file OpenCv Python

Here are my goals.
Capture video continuously until 'q; is pressed
Every ten seconds save the video in created directory file
Continue step two until 'q' is pressed
I am executing the following code. But when creating files it's creating 6kb files and saying cannot play. I am fairly new to opencv and python. Not sure what I am missing. Running this code on pycharm with Python 3.6. Also the
cv2.imshow('frame',frame)
stops after ten seconds but recording is happening in background and files are created.
import numpy as np
import cv2
import time
import os
import random
import sys
fps=24
width=864
height=640
video_codec=cv2.VideoWriter_fourcc('D','I','V','X')
name = random.randint(0,1000)
print (name)
if (os.path.isdir(str(name)) is False):
name = random.randint(0,1000)
name=str(name)
name = os.path.join(os.getcwd(), str(name))
print('ALl logs saved in dir:', name)
os.mkdir(name)
cap = cv2.VideoCapture(0)
ret=cap.set(3, 864)
ret=cap.set(4, 480)
cur_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
start=time.time()
video_file_count = 1
video_file = os.path.join(name, str(video_file_count) + ".avi")
print('Capture video saved location : {}'.format(video_file))
while(cap.isOpened()):
start_time = time.time()
ret, frame = cap.read()
if ret==True:
cv2.imshow('frame',frame)
if (time.time() - start > 10):
start = time.time()
video_file_count += 1
video_file = os.path.join(name, str(video_file_count) + ".avi")
video_writer = cv2.VideoWriter(video_file,video_codec, fps,(int(cap.get(3)),int(cap.get(4))))
time.sleep(10)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
I want files with the recorded videos. Files are generated but size 6kb and nothing is being recorded.
You're almost there! Given that I understood what your goal is, and with minimal change to your code, here is what worked for me.
This writes a new video file every ten seconds while recording each frame into the current video.
import numpy as np
import cv2
import time
import os
import random
import sys
fps = 24
width = 864
height = 640
video_codec = cv2.VideoWriter_fourcc("D", "I", "V", "X")
name = random.randint(0, 1000)
print(name)
if os.path.isdir(str(name)) is False:
name = random.randint(0, 1000)
name = str(name)
name = os.path.join(os.getcwd(), str(name))
print("ALl logs saved in dir:", name)
os.mkdir(name)
cap = cv2.VideoCapture(0)
ret = cap.set(3, 864)
ret = cap.set(4, 480)
cur_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
start = time.time()
video_file_count = 1
video_file = os.path.join(name, str(video_file_count) + ".avi")
print("Capture video saved location : {}".format(video_file))
# Create a video write before entering the loop
video_writer = cv2.VideoWriter(
video_file, video_codec, fps, (int(cap.get(3)), int(cap.get(4)))
)
while cap.isOpened():
start_time = time.time()
ret, frame = cap.read()
if ret == True:
cv2.imshow("frame", frame)
if time.time() - start > 10:
start = time.time()
video_file_count += 1
video_file = os.path.join(name, str(video_file_count) + ".avi")
video_writer = cv2.VideoWriter(
video_file, video_codec, fps, (int(cap.get(3)), int(cap.get(4)))
)
# No sleeping! We don't want to sleep, we want to write
# time.sleep(10)
# Write the frame to the current video writer
video_writer.write(frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
else:
break
cap.release()
cv2.destroyAllWindows()
A sign that the videos are being received at 6 kb, an error with the codec. You need to download opencv_ffmpeg.dll and place it in the Python3.2.1 folder and renamed to opencv_ffmpeg321.dll
This solved the problem for me, and before that, 5.6 kb videos were created, regardless of what I do. But the problem is deeper than it seems, it can still be connected with a mismatch in the resolution of the stream and the recording.
For OpenCV version X.Y.Z
opencv_ffmpeg.dll ==> opencv_ffmpegXYZ.dll
For 64-bit version of OpenCV X.Y.Z
opencv_ffmpeg.dll ==> opencv_ffmpegXYZ_64.dll

cv2.VideoCapture.read() gets old frame after time.sleep()

I tried to capture (stereo) images with Python's opencv and two cameras so therefore every 5 seconds an image should be saved. But the problem here is that an old frame is saved.
The minified code is as follows:
cap = cv2.VideoCapture(0)
for i in range(20):
time.sleep(5)
print "Taking image %d:" % i
ret, frame = cap.read()
cv2.imwrite("image %d" % i, frame)
print " image done." if ret else " Error while taking image..."
cap.release()
cv2.destroyAllWindows()
To check this, I changed the position of the camera after each taken image. But nevertheless an image from an old position is saved (actually not the same, but I assume some frames after the last saved image). After 5 (or more) images finally the captured location in the image does also change.
So, is there any problem with time.sleep? I guess that I'm not getting the actual frame, but a buffered one. If this is the case, how could I fix it and capture the actual frame?
VideoCapture is buffering.
If you always want the actual frame, do this:
while True:
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
cap.release()
cv2.imshow(" ", frame)
if cv2.waitKey(2000) != -1:
break
you need to count the elapsed time, but not stop read frames. like this:
import cv2
import time
cap = cv2.VideoCapture(0)
preframe_tm = time.time()
i = 0
while True:
ret, frame = cap.read()
elapsed_time = time.time() - preframe_tm
if elapsed_time < 5:
continue
preframe_tm = time.time()
i += 1
print("Taking image %d:" % i)
cv2.imwrite("image_%d.jpg" % i, frame)
if i >= 20:
break
cap.release()
cv2.destroyAllWindows()

Categories