【问题标题】:How to read a video frame by frame?如何逐帧读取视频?
【发布时间】:2014-08-24 12:08:06
【问题描述】:

我想逐帧读取 java8-64bit 格式的 Mp4 文件,并将每一帧作为 jpg 格式写入我的硬盘。我的第一次尝试是使用 JavaFX 2.2 媒体播放器播放文件 在视图组件上。我想也许每次加载新框架并准备好在组件表面上绘制时,可以选择注册观察者以获取事件,但似乎没有这种方法。 只抓取那些在组件上绘制的帧/像素就足够了。

这可以通过使用媒体播放器来完成吗?我使用媒体播放器的原因是 bcs,这是我得到的最简单的解决方案。我尝试了 vlcj,只有 32 位和 gstreamer,但没有运气:(

到目前为止我得到了什么:

public class VideoGrabber extends extends JFrame { 

// code for scene setup omitted

final MediaView view = createMediaView(...)

// some other stuff happens here

// now start the video
view.getMediaPlayer().seek(Duration.ZERO);
view.getMediaPlayer().play();
view.getMediaPlayer().setOnEndOfMedia(new Runnable()
{ // save image when done
  BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_BGR 
  view.paint(img.getGraphics());
  ImageIO.write(img, "JPEG", new File("pic-"+System.currentTimeMillis()+".jpg"));
});

// somewhere else to create 
private MediaView createMediaView(String url)
{
  final Media clip = new Media(url);
  final MediaPlayer player = new MediaPlayer(clip);
  final MediaView view = new MediaView(player);
  view.setFitWidth(VID_WIDTH);
  view.setFitHeight(VID_HEIGHT);
  return view;
}

有没有办法做到以下几点:

player.setOnNextFrameReady(final Event evt) { writeImage(evt.getFrame()) };

谢谢!

【问题讨论】:

    标签: java video image-processing


    【解决方案1】:

    您可以使用 MediaView 的 snapshot()。 首先将 mediaPlayer 连接到 MediaView 组件,然后使用 mediaPlayer.seek() 来寻找视频位置。然后你可以使用下面的代码来提取图像帧:

        int width = mediaPlayer.getMedia().getWidth();
        int height = mediaPlayer.getMedia().getHeight();
        WritableImage wim = new WritableImage(width, height);
        MediaView mv = new MediaView();
        mv.setFitWidth(width);
        mv.setFitHeight(height);
        mv.setMediaPlayer(mediaPlayer);
        mv.snapshot(null, wim);
        try {
            ImageIO.write(SwingFXUtils.fromFXImage(wim, null), "png", new File("/test.png"));
        } catch (Exception s) {
            System.out.println(s);
        }
    

    【讨论】:

    • 非常被低估的答案。谢谢。
    【解决方案2】:

    Marvin Framework 提供逐帧处理媒体文件的方法。下面显示了一个简单的视频处理示例,突出显示了斯诺克球的路径。

    在左侧,视频以 30 毫秒的间隔逐帧播放。右侧视频逐帧播放,但通过简单的图像处理方法保留了白球的所有位置。

    源码可以查看here和视频here

    下面是使用 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();
        }
    }
    

    【讨论】:

    • 很不错,我试试看。
    • 链接坏了,是项目死了还是只是网站宕机了?
    • 从 sourceforge 的搜索来看,该项目已死。 sourceforge.net/directory/os:mac/?q=marvin最后一次更新是2016年
    • 项目没有死。由于 Sourceforge 维护,该站点已关闭。存储库已移至 Github。您可以在网站上找到所有这些信息。
    • 我认为它现在已经死了或太旧了,我无法使用它。
    【解决方案3】:

    ffmpeg 这样的框架带有命令行工具,可以将视频分割成单独的帧(即文件夹中的图像)。

    看到这个问题:ffmpeg split avi into frames with known frame rate

    答案包含指向包装 ffmpeg 的 Java 框架的链接。

    【讨论】:

    • 感谢您的回复。在我从 Java 中的视频中获取帧后,我想按需进行进一步处理,然后最终保存它。 ffmpeg 可以创建一个图像流,我可以以某种方式在 jave 中打开它来处理它,而无需将所有数据写入磁盘?
    • 你可以试试https://code.google.com/p/jjmpeg/。我不建议使用命令行逐帧提取到管道中,因为在视频流中查找会太昂贵。
    • 再次感谢。不幸的是,使用 jjmpeg 意味着我必须花更多时间进行逆向工程以了解如何使用它(根本没有可用的文档),而不是花时间在我必须执行的实际任务上。也许其他一些答案会弹出有趣的解决方案。但是谢谢!
    • 项目源码中有一个例子。查看我的编辑。
    • jjmpeg 的链接已失效:/
    猜你喜欢
    • 1970-01-01
    • 2013-11-08
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多