【问题标题】:How can I get a frame sample (jpeg) from a video (mov)如何从视频(mov)中获取帧样本(jpeg)
【发布时间】:2013-03-22 01:42:39
【问题描述】:

我想使用 java 从视频文件 (mov) 中获取帧样本 (jpeg)。是否有捷径可寻。当我在谷歌搜索时,我只能找到从多个 jpg 制作 mov 。我不知道也许我找不到正确的关键字。

【问题讨论】:

  • 可能我以错误的方式提出问题。我不播放视频文件(在屏幕上)。我只想将其作为文件读取和处理并从中获取示例帧并将此示例帧保存为 jpeg
  • 这是一个similar question,它看起来没有完整的答案,但可能会让您入门。
  • 我是用 Xoggler 做的。我在答案部分给出了代码的链接

标签: java jpeg extract mov


【解决方案1】:

BoofCV 的方法如下:

String fileName = UtilIO.pathExample("tracking/chipmunk.mjpeg");

MediaManager media = DefaultMediaManager.INSTANCE;

ConfigBackgroundBasic configBasic = new ConfigBackgroundBasic(30, 0.005f);
ImageType imageType = ImageType.single(GrayF32.class);
BackgroundModelMoving background = FactoryBackgroundModel.movingBasic(configBasic, new PointTransformHomography_F32(), imageType);

SimpleImageSequence video = media.openVideo(fileName, background.getImageType());

ImageBase nextFrame;
while(video.hasNext()) {
    nextFrame = video.next();

    // Now do something with it...
}

【讨论】:

    【解决方案2】:

    我知道最初的问题已经解决,但是,我发布这个答案以防其他人像我一样被卡住。

    从昨天开始,我已经尝试了一切,我的意思是要做到这一点。所有可用的 Java 库要么已过时,不再维护,要么缺少任何可用的文档(严重吗??!?!)

    我尝试了 JFM(旧且无用)、JCodec(没有任何文档)、JJMpeg(看起来很有希望,但由于缺乏 Java 类文档而使用起来非常困难和麻烦)、OpenCV 自动 Java 构建和一些我不记得的其他图书馆。

    最后,我决定看看JavaCV (Github link) 的课程,瞧!它包含带有详细文档的 FFMPEG 绑定。

    <dependency>
        <groupId>org.bytedeco</groupId>
        <artifactId>javacv</artifactId>
        <version>1.0</version>
    </dependency>
    

    事实证明,有一种非常简单的方法可以将视频文件中的视频帧提取到 BufferedImage 并扩展为 JPEG 文件。 FFmpegFrameGrabber 类可以很容易地用于抓取单个帧并将它们转换为BufferedImage。代码示例如下:

    FFmpegFrameGrabber g = new FFmpegFrameGrabber("textures/video/anim.mp4");
    g.start();
    
    for (int i = 0 ; i < 50 ; i++) {
        ImageIO.write(g.grab().getBufferedImage(), "png", new File("frame-dump/video-frame-" + System.currentTimeMillis() + ".png"));
    }
    
    g.stop();
    

    基本上,此代码会转储视频的前 50 帧并将它们保存为 PNG 文件。好消息是内部搜索功能适用于实际帧而不是关键帧(我在使用 JCodec 时遇到的问题)

    您可以参考 JavaCV 的主页以了解有关可用于从网络摄像头等捕获帧的其他类的更多信息。希望这个答案对您有所帮助:-)

    【讨论】:

    • 只是几个问题.. 1) 为什么要为图像抓取这么多帧?有没有办法检查这个数字,这样我们就不会得到 arrayoutofboundsexception?
    • @oberger 我相信库中有一种方法可以获取文件中的总帧数。现在想不起来了
    • 从 0.11 版开始(截至 2015 年 6 月的稳定版),grab() 现在返回一个 Frame,它没有方法 getBufferedImage()。它也是bugged。如果需要FFmpegFrameGrabber,暂时使用release 0.10
    • @retiremonk 创建new org.bytedeco.javacv.Java2DFrameConverter 并在其上调用getBufferedImage
    • @0__ 在当前版本下:Java2DFrameConverter c = new Java2DFrameConverter; c.convert(g.grab()); 我还发现两件事特别有用: 1. 如果您希望获得几个代表,可以使用 g.grab(); 代替 g.grabKeyFrame();框架,而不是每一个。 2. @oberger grab();grabKeyFrame(); 将返回 null 如果您已到达视频结尾。如果返回null,只需使用if 语句和break 循环。 (确保将grab() 的结果保存在变量中,否则会跳过一帧。)
    【解决方案3】:
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    import org.bytedeco.javacpp.opencv_core.IplImage;
    import org.bytedeco.javacv.FFmpegFrameGrabber;
    import org.bytedeco.javacv.FrameGrabber.Exception;
    
    public class Read{
        public static void main(String []args) throws IOException, Exception
        {
            FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber("C:/Users/Digilog/Downloads/Test.mp4");
            frameGrabber.start();
            IplImage i;
            try {
    
                i = frameGrabber.grab();
                BufferedImage  bi = i.getBufferedImage();
                ImageIO.write(bi,"png", new File("D:/Img.png"));
                frameGrabber.stop();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
    
        }
    }
    

    【讨论】:

    • 此程序将生成视频的第一帧。例如,我使用了 mp4 格式。
    • 谢谢,但最好包括为此所需的 3rd 方库。
    【解决方案4】:

    下面显示了从媒体文件请求帧的基本代码。

    完整的源代码和视频演示:
    "Media File Processing" 使用 Marvin 框架的示例..

    public class MediaFileExample implements Runnable{
    
        private MarvinVideoInterface    videoAdapter;
        private MarvinImage             videoFrame;
    
        public MediaFileExample(){
            try{
                // Create the VideoAdapter used to load the video file
                videoAdapter = new MarvinJavaCVAdapter();
                videoAdapter.loadResource("./res/snooker.wmv");
    
                // Start the thread for requesting the video frames 
                new Thread(this).start();
            }
            catch(MarvinVideoInterfaceException e){e.printStackTrace();}
        }
    
        @Override
        public void run() {
            try{
                while(true){
                    // Request a video frame
                    videoFrame = videoAdapter.getFrame();
                }
            }catch(MarvinVideoInterfaceException e){e.printStackTrace();}
        }
    
        public static void main(String[] args) {
            MediaFileExample m = new MediaFileExample();
        }
    }
    

    【讨论】:

      【解决方案5】:

      Xuggler 完成了这项工作。他们甚至提供了一个完全符合我需要的示例代码。链接在下面

      http://xuggle.googlecode.com/svn/trunk/java/xuggle-xuggler/src/com/xuggle/mediatool/demos/DecodeAndCaptureFrames.java

      我已经修改了这个链接中的代码,使它只保存视频的第一帧。

      import javax.imageio.ImageIO;
      
      import java.io.File;
      
      import java.awt.image.BufferedImage;
      
      import com.xuggle.mediatool.IMediaReader;
      import com.xuggle.mediatool.MediaListenerAdapter;
      import com.xuggle.mediatool.ToolFactory;
      import com.xuggle.mediatool.event.IVideoPictureEvent;
      import com.xuggle.xuggler.Global;
      
      /**
       *  * @author aclarke
       *    @author trebor
       */
      
      public class DecodeAndCaptureFrames extends MediaListenerAdapter
      {
        private int mVideoStreamIndex = -1;
        private boolean gotFirst = false;
        private String saveFile;
        private Exception e;
        /** Construct a DecodeAndCaptureFrames which reads and captures
         * frames from a video file.
         * 
         * @param filename the name of the media file to read
         */
      
        public DecodeAndCaptureFrames(String videoFile, String saveFile)throws Exception
        {
          // create a media reader for processing video
          this.saveFile = saveFile;
          this.e = null;
           IMediaReader reader = ToolFactory.makeReader(videoFile);
      
          // stipulate that we want BufferedImages created in BGR 24bit color space
          reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
      
      
          // note that DecodeAndCaptureFrames is derived from
          // MediaReader.ListenerAdapter and thus may be added as a listener
          // to the MediaReader. DecodeAndCaptureFrames implements
          // onVideoPicture().
      
          reader.addListener(this);
      
          // read out the contents of the media file, note that nothing else
          // happens here.  action happens in the onVideoPicture() method
          // which is called when complete video pictures are extracted from
          // the media source
      
            while (reader.readPacket() == null && !gotFirst);
      
            if (e != null)
                throw e;
        }
      
      
      
        /** 
         * Called after a video frame has been decoded from a media stream.
         * Optionally a BufferedImage version of the frame may be passed
         * if the calling {@link IMediaReader} instance was configured to
         * create BufferedImages.
         * 
         * This method blocks, so return quickly.
         */
      
        public void onVideoPicture(IVideoPictureEvent event)
        {
          try
          {
            // if the stream index does not match the selected stream index,
            // then have a closer look
      
            if (event.getStreamIndex() != mVideoStreamIndex)
            {
              // if the selected video stream id is not yet set, go ahead an
              // select this lucky video stream
      
              if (-1 == mVideoStreamIndex)
                mVideoStreamIndex = event.getStreamIndex();
      
              // otherwise return, no need to show frames from this video stream
      
              else
                return;
            }
      
            ImageIO.write(event.getImage(), "jpg", new File(saveFile));
            gotFirst = true;
      
          }
          catch (Exception e)
          {
            this.e = e;
          }
        }
      }
      

      【讨论】:

      • 我们只使用了 mov 文件(用 iPhone 录制)。我没有尝试使用 avi 的代码。不幸的是,我没有一个简单的方法可以尝试。
      • 如果我需要从 avi 视频(总是在 java 中)获取单帧(为了创建该视频的缩略图),你有什么建议?
      • 这件事我帮不了你。现在我正在做一些完全不同的事情。我的建议是针对特定问题检查 SO,如果没有这样的问题,则将其作为新问题提出。
      • 这不再是正确的解决方案。该库不再受支持。
      【解决方案6】:

      也许这会对你有所帮助:

      Buffer buf = frameGrabber.grabFrame();
      // Convert frame to an buffered image so it can be processed and saved
      Image img = (new BufferToImage((VideoFormat) buf.getFormat()).createImage(buf));
      buffImg = new BufferedImage(img.getWidth(this), img.getHeight(this), BufferedImage.TYPE_INT_RGB);
      //TODO saving the buffImg
      

      更多信息:

      How to take single snapshots from a webcam?

      【讨论】:

      • 我要试试这个。我会发布结果。感谢任何方式
      • 不幸的是“如何从网络摄像头拍摄单个快照?”中给出的链接。死了。另一方面,我发现这个链接有一个答案osdir.com/ml/java.imagej/2005-01/msg00242.html 但是它需要 Quicktime for Java,Apple 不再提供:(
      猜你喜欢
      • 2012-04-28
      • 1970-01-01
      • 2017-09-03
      • 2011-08-26
      • 1970-01-01
      • 1970-01-01
      • 2013-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多