MPEG4 영화에서 모든 I-프레임의 Y-채널을 최대한 무손실로 추출합니다.

MPEG4 영화에서 모든 I-프레임의 Y-채널을 최대한 무손실로 추출합니다.

저는 비디오 추적 실험을 진행 중인데 MPEG4 DivX 5x/6x 코덱으로 압축된 비디오가 상당히 잘못되어 문제가 발생했습니다. 저는 이미지 형식, 코덱 및 압축을 처음 접했지만 열역학 제2법칙을 위반하지 않는 한 이 품질을 유지해야 한다는 것을 알게 된 것 같습니다.

이제 곤충을 추적하기 위해(예, 그게 제가 하는 일입니다) I 프레임(프레임 속도가 충분히 높음)에만 관심이 있고 색상 채널 U와 V에는 관심이 없습니다. 모든 블록에 대해 하나의 값을 가지므로 내가 원하는 해상도를 제공하지 못합니다. 제가 관심 있는 정보가 모두 들어있는 Y채널입니다. 트래커를 직접 작성했는데 동영상을 구문 분석할 수 없어서 스틸이 포함된 폴더가 필요합니다.

이제 내 질문은: 추가 품질 손실 없이 어떻게 모든 I-프레임을 그레이 스케일(Y 채널만) 이미지로 추출할 수 있습니까? 저는 우분투 14.04에서 작업하고 있으며 ffmpeg나 imageJ를 우선적으로 사용하겠습니다. 왜냐하면 ffmpeg나 imageJ가 이미 내 파이프라인에 있기 때문입니다. 내가 지금 있는 곳은 다음과 같습니다.

매 두 번째 프레임이 I 프레임이라는 것을 알아낸 것 같지만 확실하지 않습니다. 나는 다음을 사용했다:

ffprobe -show_frames movie.avi | grep -A2 "video" | grep "key_frame"

output: 
key_frame=1
key_frame=0
key_frame=1
key_frame=0
key_frame=1
key_frame=0
key_frame=1
key_frame=0
key_frame=1
key_frame=0

--
this goes on for exactly the number of frames, as this bit of code tells me: 
ffprobe -show_frames movie.avi | grep -A2 "video" | grep -c "key")
13369

이제 모든 I 프레임을 추출하는 방법을 알아낸 것 같습니다.

ffmpeg -i movie.avi -vf '[in]select=eq(pict_type\,I)[out]' /picture%d.jpg         

하지만 그것은 나에게 모든 프레임을 돌려주는 것 같습니다.

ls *jpg | wc -l
133370

내가 도대체 ​​뭘 잘못하고있는 겁니까? 이것은 ffmpeg가 제공하는 출력입니다.

ffmpeg version N-77455-g4707497 Copyright (c) 2000-2015 the FFmpeg developers
built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04)
configuration: --extra-libs=-ldl --prefix=/opt/ffmpeg --mandir=/usr/share/man --enable-avresample --disable-debug --enable-nonfree --enable-gpl --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --disable-decoder=amrnb --disable-decoder=amrwb --enable-libpulse --enable-libdcadec --enable-libfreetype --enable-libx264 --enable-libx265 --enable-libfdk-aac --enable-libvorbis --enable-libmp3lame --enable-libopus --enable-libvpx --enable-libspeex --enable-libass --enable-avisynth --enable-libsoxr --enable-libxvid --enable-libvo-aacenc --enable-libvidstab
libavutil      55. 11.100 / 55. 11.100
libavcodec     57. 20.100 / 57. 20.100
libavformat    57. 20.100 / 57. 20.100
libavdevice    57.  0.100 / 57.  0.100
libavfilter     6. 21.101 /  6. 21.101
libavresample   3.  0.  0 /  3.  0.  0
libswscale      4.  0.100 /  4.  0.100
libswresample   2.  0.101 /  2.  0.101
libpostproc    54.  0.100 / 54.  0.100 
Guessed Channel Layout for  Input Stream #0.1 : stereo
Input #0, avi, from 'movie.avi':
Duration: 00:08:54.76, start: 0.000000, bitrate: 3006 kb/s
Stream #0:0: Video: mpeg4 (Simple Profile) (DX50 / 0x30355844), yuv420p, 720x576 [SAR 16:15 DAR 4:3], 1462 kb/s, 25 fps, 25 tbr, 25 tbn, 25 tbc
Stream #0:1: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, 2 channels, s16, 1536 kb/s
[swscaler @ 0x3c2e920] deprecated pixel format used, make sure you did set range correctly
Output #0, image2, to './picture%d.jpg':
Metadata:
encoder         : Lavf57.20.100
Stream #0:0: Video: mjpeg, yuvj420p(pc), 720x576 [SAR 16:15 DAR 4:3], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
Metadata:
  encoder         : Lavc57.20.100 mjpeg
Side data:
  unknown side data type 10 (24 bytes) 
Stream mapping:
Stream #0:0 -> #0:0 (mpeg4 (native) -> mjpeg (native))
Press [q] to stop, [?] for help

frame=13370 fps=506 q=24.8 Lsize=N/A time=00:08:54.80 bitrate=N/A dup=6685 drop=0 speed=20.2x    
video:157591kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

따라서 몇 가지 질문이 있습니다.

  • 내가 도대체 ​​뭘 잘못하고있는 겁니까? 왜 모든 프레임을 돌려받나요?
  • JPEG로 인해 추가 손실이 발생합니까? 아니면 mpeg4에서 인트라 프레임에 사용되는 것과 동일한 압축인가요? 대신 tiff를 사용해야 할까요?
  • y채널만 추출하려면 어떻게 해야 하나요?
  • 매 두 번째 프레임마다 I-프레임을 얻는 것이 정상인가요? MPEG4 인코딩을 조금 읽어봤는데 전체 프레임이 아니라 블록이 참조로 사용되는 것 같나요? 그런 다음 해당 블록이 포함된 모든 프레임을 추출합니까? "실제" 전체 참조 프레임에 더 높은 수준이 있습니까?
  • 품질을 더 회복할 수 있는 방법은 없을까요?

많은 도움을 주셔서 감사합니다!

최고의 소원,

릭 베르동크

답변1

ffmpeg는 달리 명시적으로 지정하지 않는 한 암시적으로 소스의 프레임 속도를 사용합니다. 디코더/필터에서 제공하는 프레임 수가 해당 속도와 다른 경우 이를 달성하기 위해 프레임이 복제되거나 삭제됩니다. 선택한 각 프레임에 대해 새 타임스탬프를 생성하거나 비디오 1초당 I-프레임 빈도와 일치하는 프레임 속도를 지정하여 이 문제를 해결할 수 있습니다. 먼저하는 것이 더 안전합니다.

추가 압축을 피하기 위해 JPEG 대신 TIFF, PNG 또는 BMP를 사용할 수 있습니다. JPEG 및 MPEG 코덱의 예측 방식이 동일한지 확실하지 않습니다.

MPEG-4 코덱에서는 매 프레임마다 I-프레임이 발생하는 것이 일반적이지 않지만 인코딩이 잘못되었다고 말씀하셨습니다. 누군가 GOP, 즉 키프레임 간격을 2로 설정했거나 전자일 가능성이 높은 장면 변경 임계값을 매우 낮게 설정했습니다.

요약하면 다음을 사용하십시오.

ffmpeg -i movie.avi -vf "select=eq(pict_type\,I),setpts=N/25/TB" -pix_fmt gray /picture%d.png 

편집됨

직접 Y 성분 추출의 경우 다음을 사용하십시오.

ffmpeg -i movie.avi -vf "select=eq(pict_type\,I),setpts=N/25/TB,extractplanes=y" -pix_fmt gray /picture%d.png   

관련 정보