使用OpenCV和Java从gif中的帧中获取Mats

时间:2015-05-25 00:29:12

标签: java opencv image-processing

我正在尝试使用OpenCV从gif获取帧。我找到Convert each animated GIF frame to a separate BufferedImage并使用了第二个建议。我稍微修改了它以返回一个Mats数组而不是BufferedImages。

我尝试了两种从gif获取bufferedImages的方法。每个人都提出了不同的问题。

  1. 使用上一个帖子的建议

    BufferedImage fImage=ir.read(i);
    

    程序调用" ArrayIndexOutOfBoundsException:4096"

  2. 使用上一个帖子的原始代码。

    BufferedImage fImage=ir.getRawImageType(i).createBufferedImage(ir.getWidth(i),ir.getHeight(i));
    

    每一帧都是单调的颜色(虽然不是全黑),而且从BufferedImage派生的垫子是空的。

    System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
    ArrayList<Mat> frames = new ArrayList<Mat>();
    ImageReader ir = new GIFImageReader(new GIFImageReaderSpi());
    ir.setInput(ImageIO.createImageInputStream(new File("ronPaulTestImage.gif")));
    
    for(int i = 0; i < ir.getNumImages(true); i++){
        BufferedImage fImage=ir.read(i);
        //BufferedImage fImage=ir.getRawImageType(i).createBufferedImage(ir.getWidth(i), ir.getHeight(i));
    
        fImage = toBufferedImageOfType(fImage, BufferedImage.TYPE_3BYTE_BGR);
        //byte[] pixels = ((DataBufferByte) r.getRaster().getDataBuffer()).getData();
        Mat m=new Mat();
        //m.put(0,0,pixels);
        m.put(0, 0,((DataBufferByte) fImage.getRaster().getDataBuffer()).getData());
    
        if(i==40){
        //a test, writes the mat and the image at the specified frame to files, exits
            ImageIO.write(fImage,"jpg",new File("TestError.jpg"));
            Imgcodecs.imwrite("TestErrorMat.jpg",m);
            System.exit(0);
    }
    
  3. 以下是gif I used

    • test gif

2 个答案:

答案 0 :(得分:2)

按照Spektre的建议,我找到了一个更好的gif,修复了单色缓冲图像。缺少可见的Mats是由我在声明Mat时使用默认构造函数引起的。

工作代码

    public static ArrayList<Mat> getFrames(File gif) throws IOException{
    ArrayList<Mat> frames = new ArrayList<Mat>();
    ImageReader ir = new GIFImageReader(new GIFImageReaderSpi());
    ir.setInput(ImageIO.createImageInputStream(gif));
    for(int i = 0; i < ir.getNumImages(true); i++){
        BufferedImage fImage=ir.read(i);
        fImage = toBufferedImageOfType(fImage, BufferedImage.TYPE_3BYTE_BGR);
        byte[] pixels = ((DataBufferByte) fImage.getRaster().getDataBuffer()).getData();
        Mat m=new Mat(fImage.getHeight(), fImage.getWidth(), CvType.CV_8UC3);
        m.put(0,0,pixels);
        if(i==15){//a test, writes the mat and the image at the specified frame to files, exits
            ImageIO.write(fImage,"jpg",new File("TestError.jpg"));
            Imgcodecs.imwrite("TestErrorMat.jpg",m);
            System.exit(0);
        }
        frames.add(m);
        }
    return frames;
}

答案 1 :(得分:1)

我没有使用libs用于gif,Java和OpenCV,但是ArrayIndexOutOfBoundsException: 4096

表示未正确清除字典。你的gif是有缺陷的我测试它并且它包含错误,没有足够的清晰代码存在于某些帧。如果您的GIF解码器没有检查/处理这种情况,那么它就会崩溃,因为它的字典增长超过了GIF限制4096/12bit

尝试其他GIF,而不是一些有缺陷的GIF ......

测试了你的gif,每帧大约有7个清晰代码,共包含941个错误(没有明确的代码导致字典超限)

如果您有GIF解码器的源代码

然后找到解码器的一部分,其中新项目被添加到字典并添加

if (dictionary_items<4096)
之前的

...如果忽略了错误的条目,图像看起来仍然正常,很可能是创建它的编码器没有正确编码。