PyImageSearch / imutils

A series of convenience functions to make basic image processing operations such as translation, rotation, resizing, skeletonization, and displaying Matplotlib images easier with OpenCV and Python.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FileVideoStream puts an NoneType into the queue

KanTakahiro opened this issue · comments

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.

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

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()