kli_nlpr
kli_nlpr

Reputation: 914

python opencv cv2.cv.CV_CAP_PROP_FRAME_COUNT get wrong numbers

import os
import cv2
path='/home/nlpr4/video-data/UCF-101/GolfSwing/v_GolfSwing_g24_c06.avi'
cap=cv2.VideoCapture(path)
video_length=int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))

success=True
count=0
while success:
    success,image=cap.read()
    if success==False:
        break
    count=count+1

print video_length,count

output:

149 
146

why the two numbers different? what's wrong?

Upvotes: 23

Views: 28037

Answers (3)

Wang
Wang

Reputation: 8173

The get() for CAP_PROP_FRAME_COUNT is never supposed to be accurate! If you check the opencv source code. You can find this:

int64_t CvCapture_FFMPEG::get_total_frames() const
{
    int64_t nbf = ic->streams[video_stream]->nb_frames;

    if (nbf == 0)
    {
        nbf = (int64_t)floor(get_duration_sec() * get_fps() + 0.5);
    }
    return nbf;
}

This means it will first look into the stream header for nb_frames, which you can check with ffprobe. If there is no such field, then there is no better way to get frame number than directly decoding the video. The opencv did a rough estimation by get_duration_sec() * get_fps() + 0.5 which surely not mean for accuracy.

Thus, to obtain the correct frame number you have to decode and read through the entire stream, or you have to ask the video generator to generate correct stream header with nb_frames field.

It is unfortunately to see after almost 10 years opencv still does not correct the implementation: we should use av_read_frame(fmt_ctx, &pkt) to read and parse all packet without actual decode them.

I personally stopped relies on opencv for video decoding more than 10 years ago, but recently I have to collaborate with some project using opencv to do so. I have to call ffprobe in a subprocess to get the correct frame counts:

ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4

Upvotes: 21

ilke444
ilke444

Reputation: 2741

CV_CAP_PROP_FRAME_COUNT gives the property of 'number of frames', that comes from the video header. The other number is basically "How many frames can I read from this video file?".

If the video contains frames that cannot be read/decoded (e.g., due to being corrupted), OpenCV skips those frames (after trying to read them) and gives you the next valid frame. So the difference between your two numbers is the number of frames that couldn't be read.

Also, if your video header is corrupted and/or cannot be parsed by the underlying codecs that OpenCV uses, then those numbers can be different too.

Upvotes: 9

boardrider
boardrider

Reputation: 6185

Try this code:

#!/usr/bin/env python

import numpy as np
import cv2

video = "../videos/sample.avi"

video_capture = cv2.VideoCapture(video)
video_length = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))

count = 0
while(True):
        # Capture frame-by-frame
        ret, frame = video_capture.read()
        if not ret:
            break

        count += 1

print video_length, count
# When everything done, release the capture
video_capture.release()
cv2.destroyAllWindows()

On my machine it gives me:

$ ./openstack_video_frames.py 
1232 1232

Upvotes: 0

Related Questions