Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileVideoStream puts an NoneType into the queue #251

Open
KanTakahiro opened this issue Jun 13, 2021 · 2 comments
Open

FileVideoStream puts an NoneType into the queue #251

KanTakahiro opened this issue Jun 13, 2021 · 2 comments

Comments

@KanTakahiro
Copy link

I read this article and write a code like this (almost the same code as the article showed):

# import the necessary packages
from imutils.video import FileVideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", required=True, help="path to input video file")
args = vars(ap.parse_args())
# start the file video stream thread and allow the buffer to
# start to fill
print("[INFO] starting video file thread...")
fvs = FileVideoStream(args["video"]).start()
time.sleep(1.0)
# start the FPS timer
fps = FPS().start()

# loop over frames from the video file stream
while fvs.more():
    # grab the frame from the threaded video file stream, resize
    # it, and convert it to grayscale (while still retaining 3
    # channels)
    frame = fvs.read()
    frame = imutils.resize(frame, width=640)
    '''
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    frame = np.dstack([frame, frame, frame])
    '''
    # display the size of the queue on the frame
    cv2.putText(frame, "Queue Size: {}".format(fvs.Q.qsize()), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
    # show the frame and update the FPS counter
    cv2.imshow("Frame", frame)
    cv2.waitKey(1)
    fps.update()

# stop the timer and display FPS information
fps.stop()
print("[INFO] elasped time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
# do a bit of cleanup
cv2.destroyAllWindows()
fvs.stop()

I run this code with python3 test.py -v video.mp4 and the script does playback the all video but finally an error was thrown out:

[INFO] starting video file thread...
Traceback (most recent call last):
  File "neo.py", line 27, in <module>
    frame = imutils.resize(frame, width=640)
  File "/home/takahiro/.local/lib/python3.8/site-packages/imutils/convenience.py", line 69, in resize
    (h, w) = image.shape[:2]
AttributeError: 'NoneType' object has no attribute 'shape'

It seems that a NoneType was fed to the function imutils.resize() instead of a available frame. Since all the frames are fetched from the queue in FileVideoStream, I found the reason that causes this error in the implementation of FileVideoStream.
In function update() of imutils/video/filevideostream.py, if cv2.VideoCapture().read() faild(that basically means it reached the end of video file), although self.stopped is set to be True, self.Q.put(frame) in the below is still executed and put a NoneType into the queue. The process won't stop until the next loop start, but in this case it should be stopped immediately, at least before the self.Q.put(frame).
The original filevideostream.py, with all comments and empty lines deleted:

def update(self):
	while True:
		if self.stopped:
			break
		if not self.Q.full():
			(grabbed, frame) = self.stream.read()
			if not grabbed:
				self.stopped = True
			if self.transform:
				frame = self.transform(frame)
			self.Q.put(frame)
		else:
			time.sleep(0.1)  # Rest for 10ms, we have a full queue
	self.stream.release()

I added a continue under self.stopped = True to avoid self.Q.put(frame) from executing and the error didn't appear any more.
I don't know whether it is a bug of FileVideoStream. Maybe this solution will cause another issue. But if someone using FileVideoStream meets the same error then you can try this solution.

tapani-hopkins added a commit to tapani-hopkins/imutils that referenced this issue Nov 11, 2021
When FileVideoStream reaches the end of the file, it takes one more frame (which is NoneType) and tries to transform and add it to the queue. This has also been noted in issue PyImageSearch#251 . This causes an error if the transform expects a valid frame, or if the main script does not expect the last frame in the Queue to be NoneType.
@hsekki
Copy link

hsekki commented Jan 29, 2022

yeah it works, though I add a return instead of continue. Helpful. Thanks

@frank-engel
Copy link

This fix worked for me as well. Another approach, if someone doesn't want to modify imutils as installed is to introduce an if statement in your while loop which skips if the current frame is None. Using the tutorial as an example, you could modify like so:

# loop over frames from the video file stream
while fvs.more():
    # grab the frame from the threaded video file stream, resize
    # it, and convert it to grayscale (while still retaining 3
    # channels)
    frame = fvs.read()
    if frame is not None:
        frame = imutils.resize(frame, width=450)
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        frame = np.dstack([frame, frame, frame])
        # display the size of the queue on the frame
        cv2.putText(frame, "Queue Size: {}".format(fvs.Q.qsize()),
            (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)	
        # show the frame and update the FPS counter
        cv2.imshow("Frame", frame)
    cv2.waitKey(1)
    fps.update()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants