I’m totally stuck on this, I just can’t find what’s wrong. Not sure if this is OpenCV specific or just my limited python skills. But I’m hoping someone can help me out.
What I would like to do is:
scan a directory for (mp4) video files
make a list of the found files
process each file with cv2.VideoCapture()
This is my code:
# file operations
import os
# Motion detection
import cv2
# Scan target directory
# os.scandir returns an iterator, make it a list to be re-usable
# Target directory is in the same directory as the script
targetDirectory = "videofiles"
dircontent = list(os.scandir(targetDirectory))
# Search for mp4 files and make a list [ [filename, path], [filename, path], ... ]
mp4Files = [[f.name[:-4], os.path.abspath(f.name)] for f in dircontent if f.name.lower().endswith('.mp4')]
for videofile in mp4Files:
print(videofile[1], " -- ", type(videofile[1]))
# This prints: E:\Projects\Programming\Python\OpenCV\_CaptureSaveROI\Motiondetection_Batch_Heatmap\Burglary.mp4 -- <class 'str'>
# Open file to process
# Replace backslahes with forward slashes
videofilepath = videofile[1].replace("\\","/")
print(videofilepath)
# This prints: E:/Projects/Programming/Python/OpenCV/_CaptureSaveROI/Motiondetection_Batch_Heatmap/Burglary.mp4
cap = cv2.VideoCapture(videofilepath)
# the following doesn't give an error:
# cap = cv2.VideoCapture("E:/Projects/Programming/Python/OpenCV/_CaptureSaveROI/Motiondetection_Batch_Heatmap/videofiles/Burglary.mp4")
print(cap)
# This prints: <VideoCapture 018CB4C0>
if (cap.isOpened() == False):
print("Error opening the video file")
else:
ret, frame1 = cap.read()
heatmap = frame1.copy() # <<<<<<< ERROR
In the last if/else:
the error I get when not using the if/else :
heatmap = frame1.copy()
AttributeError: 'NoneType' object has no attribute 'copy'
When using the if/else, cap.isOpened() returns false and I get the “Error opening the video file” message
there may be non - video files in your folder
(hidden thumbnails, dot files, DS_Store, etc).
use python’s glob to filter filetypes,
and check cap.isOpened() before proceeding
Ok, I did a test using glob and guess what, it works:
# file operations
import glob
# Motion detection
import cv2
# Scan target directory
# os.scandir returns an iterator, make it a list to be re-usable
# Target directory is in the same directory as the script
targetDirectory = "videofiles"
mp4files = glob.glob(targetDirectory + '/*.mp4')
for element in mp4files:
print(element)
# The above prints all found paths as videofiles\filename.mp4
for videofile in mp4files:
print(videofile, " -- ", type(videofile))
# This prints: videofiles\Burglary.mp4 -- <class 'str'>
cap = cv2.VideoCapture(videofile)
print(cap)
# This prints: <VideoCapture 018CB4C0>
ret, frame1 = cap.read()
if(ret):
heatmap = frame1.copy() # no error
cv2.imshow('heatmap', heatmap)
else:
print('error')
targetDirectory = "videofiles"
dircontent = list(os.scandir(targetDirectory))
# Search for mp4 files and make a list [ [filename, path], [filename, path], ... ]
mp4Files = [[f.name[:-4], os.path.abspath(f.name)] for f in dircontent if f.name.lower().endswith('.mp4')]
for videofile in mp4Files:
print(videofile[1], " -- ", type(videofile[1]))
# This prints: E:\Projects\Programming\Python\OpenCV\_CaptureSaveROI\Motiondetection_Batch_Heatmap\Burglary.mp4 -- <class 'str'>
pathAsString = 'E:/Projects/Programming/Python/OpenCV/_CaptureSaveROI/Motiondetection_Batch_Heatmap/videofiles/Burglary.mp4'
print(pathAsString)
# This prints: E:/Projects/Programming/Python/OpenCV/_CaptureSaveROI/Motiondetection_Batch_Heatmap/videofiles/Burglary.mp4
print(videofile[1] == pathAsString)
# This prints: False
print('types:')
print(type(videofile[1])) # This prints: <class 'str'>
print(type(pathAsString)) # This prints: <class 'str'>
cap = cv2.VideoCapture(videofile[1])
# the following lines don't give an error:
# cap = cv2.VideoCapture('E:/Projects/Programming/Python/OpenCV/_CaptureSaveROI/Motiondetection_Batch_Heatmap/videofiles/Burglary.mp4')
# cap = cv2.VideoCapture(pathAsString)
print(cap)
# This prints: <VideoCapture 018CB4C0>
ret, frame1 = cap.read()
print(ret) # This prints: False
heatmap = frame1.copy() # <<<<<<< ERROR: 'NoneType' object has no attribute 'copy'
videofile[1] == pathAsString returns false because they are two different objects right? What I don’t understand is that they are both strings with the same content but when fed into cv2.VideoCapture() one works and the other doesn’t.
I don’t know if it’s relevant but I’m using pycharm on windows:
Man… I’ve been staring at this too long, I missed the actual difference in the paths (Motiondetection_Batch_Heatmap\Burglary.mp4 != Motiondetection_Batch_Heatmap/videofiles/Burglary.mp4)
Just changed:
mp4Files = [[f.name[:-4], os.path.abspath(f.name)] for f in dircontent if f.name.lower().endswith('.mp4')]
To:
mp4Files = [[f.name[:-4], os.path.abspath(f)] for f in dircontent if f.name.lower().endswith('.mp4')]
So to conclude, this works as expected:
# file operations
import os
# Motion detection
import cv2
# Scan target directory
# os.scandir returns an iterator, make it a list to be re-usable
# Target directory is in the same directory as the script
targetDirectory = "videofiles"
dircontent = list(os.scandir(targetDirectory))
# Search for mp4 files and make a list [ [filename, path], [filename, path], ... ]
mp4Files = [[f.name[:-4], os.path.abspath(f)] for f in dircontent if f.name.lower().endswith('.mp4')]
for videofile in mp4Files:
cap = cv2.VideoCapture(videofile[1])
ret, frame1 = cap.read()
heatmap = frame1.copy()