extract frame

extract frames every two seconds:(fps:29.97)

  1. ffmpeg[fps:30]: #30,#90,#150,#210 [ffmpeg: select one frame at the center] [ffmpeg start from 1 ]

  2. ext.c [fps:29]: #1, #59, #117, #175 (since the c code starts from 0, so in fact, it should be #2, #60,#118,#176)

code

#/bin/bash
inputvideo=6040577337
inputvideo=HVC929804
outpath="out_ffm_all"
outdir="out_ffm"
ffmpeg -i $inputvideo $outpath/out-%d.jpg
#ffmpeg -i $inputvideo -vf fps=0.5 $outdir/out-%d.jpg                                                   
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <cv.h>
#include <highgui.h>

#define PNG_COMPRESSION 3

CvSize FixedSize(CvSize size);

int main (int argc, char **argv)
{
  if(argc < 3){
    fprintf(stderr,"usage:eframe VIDEO_FILE frame_interval(sec) OutputDir\n");
    return -1;
  }

  CvCapture* capture;
  IplImage *frame = NULL;
  char *filename = argv[1];
  float sec_interval_frame = atof(argv[2]);
  char *dir = argv[3];
  int fps = 0, width = 0, height = 0, nframe = 0;
  int n = 0;
  int param[2];
  char video[100],s1[100],s2[100];
  char *ptr; 

  param[0] = CV_IMWRITE_PNG_COMPRESSION;
  param[1] = PNG_COMPRESSION;

  if((capture = cvCaptureFromFile(filename)) == NULL){
    fprintf(stderr,"Can't open file %s\n.",filename);
    return -1;
  }

  fps = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
  width = cvGetCaptureProperty (capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty (capture, CV_CAP_PROP_FRAME_HEIGHT);
  nframe = cvGetCaptureProperty (capture, CV_CAP_PROP_FRAME_COUNT);

  if (fps == 0) {
    fprintf(stderr,"Cannot get frame rate of the video file: %s.\n",filename);
    return -1;
  }

  strcpy(video,dir);
  strcat(video,"/");
  if ((ptr = strrchr(filename,'/')) != NULL){
    ptr++;
  }else{
    ptr = filename;
  }
  ptr = strtok(ptr,".");
  strcat(video,ptr);
  strcat(video,"_");
  fprintf(stdout,"# %s,%d,%d\n",filename,fps,nframe);

  while(1) {
    frame = cvQueryFrame(capture);
    if(frame == NULL) break;
    if (n % (int)(fps*sec_interval_frame) == 1){
      strcpy(s1,video);
      sprintf(s2, "%08d", n);
      strcat(s1, s2);
      strcat(s1,".png");
      cvSaveImage(s1, frame, param);
      fprintf(stdout,"%d\n",n);
    }
    n++;
  }
  cvReleaseCapture(&capture);
  if (n != nframe){
    fprintf(stderr,"# Error: %d != %d\n",n,nframe);
  }

  return 0;
}

compression

两种方法最后得到的图像的大小也不一样,因为都进行了压缩.
http://www.howtogeek.com/203979/is-the-png-format-lossless-since-it-has-a-compression-parameter/
PNG is Compressed, but Lossless
The compression level is a trade-off between file size and encoding/decoding speed. To overly generalize, even non-image formats such as FLAC have similar concepts.
Different Compression Levels, Same Decoded Output
Although the file sizes are different due the the different compression levels, the actual decoded output will be identical. You can compare the MD5 hashes of the decoded outputs with ffmpeg using the MD5 muxer. This is best shown with some examples.

Create PNG Files

ffmpeg -i input -vframes 1 -compression_level 0 0.png
ffmpeg -i input -vframes 1 -compression_level 100 100.png

By default, ffmpeg will use -compression_level 100 for PNG output.
A quick, sloppy test showed that 100 (the highest compression level) took roughly three times longer to encode and five times longer to decode than 0 (the lowest compression level) in this example.

compare

instaill imagemagick

for ((j=1;j<29;j++));do
        i=$[30+60*(j-1)]
        echo "-----------------$j---------------"
        echo $i
        compare out_ffm/out-${j}.png out_ffm_all/out-${i}.png -metric RMSE 3.png
        echo $[i-1]
        compare out_ffm/out-${j}.png out_ffm_all/out-$[i-1].png -metric RMSE 3.png
        echo $[i+1]
        compare out_ffm/out-${j}.png out_ffm_all/out-$[i+1].png -metric RMSE 3.png
        echo ""
done

result

extracted frame indexframe numberframe numberframe number
c code written by dangffmpeg(frame rate = 29.97)ffmpeg(frame rate=29.917)
123030
2609090
3118150150
4176210210
5234270270
6292330330
7350390389
8408450449
9466510509
10524570569
11582630629
12640690689
13698750748
14756810808
15814870868
16872930928
17930990988
1898810491048
19104611091107
20110411691167

conclusion

We extract frame every two seconds.
I test two videos, the frame rate of which are 29.97 and 29.917.
[fn is the frame number in the original video( frame number starts from 1) for the n th extracted frame]
When using the code written by dang,

fn=2+int(frame_rate*2)*n=2+58n

When using the ffmpeg, I thought it should be,

fn=math.ceil(frame_rate)+math.ceil(frame_rate)*2=30+60n

However, for the video whose frame rate equals to 29.97,
when n is larger than 17, …
for the video whose frame rate equals to 29.917,
when n is larger than 6, …

fn=math.ceil((frame_rateframe_rate)*2)=30+60n

use ffmpeg to reproduce the frames extracted by the C code

${ffdir}/ffmpeg -i $video -vf trim=start_frame=1,framestep=$((`${ffdir}/ffprobe $video 2>&1 | grep -o '[0-9.]\+ fps' | sed -e 's/[\. ].*$//g'` * 2)) -loglevel error -nostdin $outdir/${videoname%.*}/${videoname%.*}_%08d.png 2>&1 > /dev/null | sed -e 's/^/    ['${videoname%.*}'] /g' >&2
ffmpeg -i $video -vf trim=start_frame=1,framestep=$((`ffprobe $video 2>&1 | grep -o '[0-9.]\+ fps' | sed -e 's/[\. ].*$//g'` * 2)) $out
#when the option of "trim=start_frame", the video starts from 0. so when set it to 1, the video starts from 2.
fps_int=`ffprobe $video 2>&1 | grep -o '[0-9.]\+ fps' | sed -e 's/[\. ].*$//g'`
framestep=$(($fps_int * 2))
ffmpeg -i $video -vf trim=start_frame=1,framestep=$framestep $out

compare

for ((i=1;i<29;i++));do
        j=$[1+(i-1)*58]
        printf -v m "%08d" $j
        compare ffmpeg_c/${i}.png c/6040577337_${m}.png -metric RMSE 3.png
done
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值