0

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.

5
  • The error is thrown in VideoReading(args.video)? If so, can you try to adapt it to return VideoReading(int(args.video))? Commented Jul 28, 2017 at 12:00
  • @Uvar: I already tried that. But still getting the same issue. Commented Jul 28, 2017 at 12:09
  • model_list = dict(zip(VideoFilesIndicator, VideoFiles)); note your dictionary is currently backwards; you want to map a number to a file name, not vice versa. Commented Jul 28, 2017 at 12:14
  • Forcing the user of the program to know the internal numbering of the files is bad interface design, though. Commented Jul 28, 2017 at 12:17
  • @chepner: Thanks for your suggestions. I know, but my manager suggested me to do so!! Commented Jul 28, 2017 at 12:20

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer. I tried it, but now getting the following error: 'cv2.error: D:\Build\OpenCV\opencv-3.2.0\modules\highgui\src\window.cpp:312: error: (-215) size.width>0 && size.height>0 in function cv::imshow'. One gets this error when "cv2" (image reading package) don't get the frame to process. So basically it's not getting the video file name. I need to pass the video file name, rather than the value of the dictionary.
@jdhesa: I tried your answer, but I'm getting VideoFiles error. But thanks for your answer.
1

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)

4 Comments

Thanks for your answer. But now I'm getting Typeerror for this code: TypeError: unhashable type: 'dict'.
Not sure how argparse actually comes up with that error, but I've made a few fixes that (incidentally?) removes it.
THanks for your answer. But I tried flevinkelming options and it solved my problem. But I your suggestion to create dictionary using enumerate is pretty useful to me.
I like flevinkelming's approach of converting the number to a file name after, instead of during, argument parsing.
1

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

2 Comments

Thanks for your answer. It's not only solved my problem, but you have beautifully explained it. Thanks again!
Glad I could help!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.