Reputation: 1746
I want to read any one of the items from a list of videos. The video reading and display code is the following. This code is working perfectly fine.
import cv2
def VideoReading(vid):
cap = cv2.VideoCapture(vid)
while True:
ret, frame = cap.read()
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Since I've large number of videos and I'm calling the code through command line, writing the entire video name is cumbersome. So I created a dictionary. Here given the example of 2:
{"Video1.mp4": 1, 'Video2.mp4': 2}
Now I'm using the following code to call the video using value 1 or 2, rather than Video name. The code is the following:
def Main():
VideoFiles= ["Video1.mp4", "Video2.mp4"]
VideoFilesIndicator = [1, 2]
model_list = {}
for i in range(len(VideoFiles)):
model_list[VideoFiles[i]] = VideoFilesIndicator[i]
print(model_list)
def convertvalues(value):
return model_list.get(value, value)
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--video", help = "add video file name of any format", type = convertvalues,\
choices = [1,2], default = 1)
args =parser.parse_args()
return VideoReading(args.video)
if __name__ == "__main__":
Main()
Now when I'm running the code in cmd "python VideoReading.py -v 2"
, it's throwing me the following error.
error: argument -v/--video: invalid choice: '2' (choose from 1, 2)
I'm not understanding why I'm getting this error. I'm following this post to build my program.
Upvotes: 0
Views: 886
Reputation: 531125
Your dictionary is backwards; you want to map a number to a file name, so that when you enter a number, a file name can be returned. There's no need to provide a default value from convertvalues
, because you are using choices
to limit the allowable inputs to the valid keys of the dict.
def main():
video_files = ["Video1.mp4", "Video2.mp4"]
model_list = dict(enumerate(video_files, start=1))
print(model_list)
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--video",
help="add video file name of any format",
type=lambda str: model_list[int(str)],
choices=model_list.values())
args = parser.parse_args()
return VideoReading(args.video)
Upvotes: 1
Reputation: 690
An alternative solution, with minimal code, and dynamic help
output for users:
import argparse
def main():
model = {
1: "Video1.mp4",
2: "Video2.mp4",
3: "Video3.mp4"
} # Add more if needed
videos = ['{}({})'.format(v, str(k)) for k, v in model.items()]
help_ = "Videos to choose from: {}".format(', '.join(videos))
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--video', help=help_, type=int, default=1)
args = parser.parse_args()
return VideoReading(model[args.video])
if __name__ == '__main__':
main()
python VideoReading.py -h
:
usage: VideoReading.py [-h] [-v VIDEO]
optional arguments:
-h, --help show this help message and exit
-v VIDEO, --v VIDEO
Videos to choose from: Video1.mp4(1), Video2.mp4(2),
Video3.mp4(3)
python VideoReading.py
:
If you were printing the selection - Video1.mp4
python VideoReading.py -v 3
:
If you were printing the selection - Video3.mp4
Upvotes: 1
Reputation: 59701
The problem is that convertvalues
is returning '2'
as a string, because convertvalues
returns value
as it is (i.e. a string) when it is not found in model_list
. Try with:
def convertvalues(value):
return model_list.get(value, int(value))
Also, as it is, your argument parser will always receive an integer in video
in the end (either you passed an integer or convertvalues
transformed a video file name into an integer). To get the actual file name again you can do something like
args = parser.parse_args()
video_file = VideoFiles[VideoFilesIndicator.index(args.video)]
return VideoReading(video_file)
My suggestion is based on trying to make the minimal amount of changes to the code. However, you may also consider more changes in the program, like flevinkelming suggests, if you don't feel comfortable with the final shape of the code.
Upvotes: 2